19 declare(strict_types=1);
   157     public function __construct(
int $id = 0, 
bool $a_call_by_reference = 
true)
   163         $this->
ctrl = $DIC[
'ilCtrl'];
   165         $this->
settings = $DIC[
'ilSetting'];
   166         $this->bench = $DIC[
'ilBench'];
   167         $this->component_repository = $DIC[
'component.repository'];
   168         $this->component_factory = $DIC[
'component.factory'];
   169         $this->filesystem_web = $DIC->filesystem()->web();
   170         $this->lo_metadata = $DIC->learningObjectMetadata();
   173         $this->participant_access_filter = $local_dic[
'participant.access_filter.factory'];
   174         $this->test_man_scoring_done_helper = $local_dic[
'scoring.manual.done_helper'];
   175         $this->
logger = $local_dic[
'logging.logger'];
   176         $this->log_viewer = $local_dic[
'logging.viewer'];
   177         $this->global_settings_repo = $local_dic[
'settings.global.repository'];
   178         $this->marks_repository = $local_dic[
'marks.repository'];
   179         $this->questionrepository = $local_dic[
'question.general_properties.repository'];
   180         $this->testrequest = $local_dic[
'request_data_collector'];
   181         $this->participant_repository = $local_dic[
'participant.repository'];
   182         $this->export_factory = $local_dic[
'exportimport.factory'];
   186         $this->
lng->loadLanguageModule(
"assessment");
   187         $this->score_settings = null;
   194             $this->component_repository,
   196             $this->questionrepository
   202         return TestDIC::dic();
   217         return $this->question_set_config_factory->getQuestionSetConfig();
   240         $id = parent::create();
   247         if (!parent::update()) {
   259         $this->main_settings = null;
   260         $this->score_settings = null;
   261         $this->mark_schema = null;
   265     public function delete(): 
bool   268         if (!parent::delete()) {
   279         $qsaImportFails->deleteRegisteredImportFails();
   281         $sltImportFails->deleteRegisteredImportFails();
   283         if ($this->
logger->isLoggingEnabled()) {
   284             $this->
logger->logTestAdministrationInteraction(
   285                 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
   287                     $this->
user->getId(),
   290                         AdditionalInformationGenerator::KEY_TEST_TITLE => $test_title = 
$this->title   302         $participantData->load($this->
getTestId());
   305         $this->db->manipulateF(
   306             "DELETE FROM tst_mark WHERE test_fi = %s",
   311         $this->db->manipulateF(
   312             "DELETE FROM tst_tests WHERE test_id = %s",
   318         $directory = $tst_data_dir . 
"/tst_" . $this->
getId();
   319         if (is_dir($directory)) {
   327         foreach ($mobs as $mob) {
   345         if (!is_writable($tst_data_dir)) {
   346             $this->
ilias->raiseError(
"Test Data Directory (" . $tst_data_dir
   347                 . 
") not writeable.", $this->
ilias->error_obj->MESSAGE);
   351         $tst_dir = $tst_data_dir . 
"/tst_" . $this->
getId();
   353         if (!@is_dir($tst_dir)) {
   354             $this->
ilias->raiseError(
"Creation of Test Directory failed.", $this->
ilias->error_obj->MESSAGE);
   357         $export_dir = $tst_dir . 
"/export";
   359         if (!@is_dir($export_dir)) {
   360             $this->
ilias->raiseError(
"Creation of Export Directory failed.", $this->
ilias->error_obj->MESSAGE);
   370     public function getExportFiles(
string $dir = 
''): array
   373         if (!@is_dir($dir) || !is_writable($dir)) {
   382             if ($file->isDir()) {
   386             $files[] = $file->getBasename();
   406         if (!is_writable($tst_data_dir)) {
   408                 . 
") not writeable.", 
$ilias->error_obj->FATAL);
   412         $tst_dir = $tst_data_dir . 
"/tst_import";
   414         if (!@is_dir($tst_dir)) {
   441         if ($this->
isComplete($test_question_set_config)) {
   445             $this->db->manipulateF(
   446                 'UPDATE tst_tests SET complete = %s WHERE test_id = %s',
   448                 [$complete, $this->test_id]
   453     public function saveToDb(
bool $properties_only = 
false): void
   455         if ($this->test_id === -1) {
   457             $next_id = $this->db->nextId(
'tst_tests');
   462                     'test_id' => [
'integer', $next_id],
   463                     'obj_fi' => [
'integer', $this->
getId()],
   464                     'created' => [
'integer', time()],
   465                     'tstamp' => [
'integer', time()],
   470             $this->test_id = $next_id;
   476                     $aresult = $this->db->queryF(
   477                         "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
   478                         [
'integer', 
'integer', 
'integer'],
   481                     while ($row = $this->db->fetchAssoc($aresult)) {
   482                         $this->db->manipulateF(
   483                             "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
   484                             [
'integer', 
'timestamp', 
'integer'],
   485                             [1, date(
'Y-m-d H:i:s'), $row[
"active_id"]]
   490                     $aresult = $this->db->queryF(
   491                         "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
   492                         [
'integer', 
'integer', 
'integer'],
   495                     while ($row = $this->db->fetchAssoc($aresult)) {
   496                         $this->db->manipulateF(
   497                             "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
   498                             [
'integer', 
'timestamp', 
'integer'],
   499                             [0, null, $row[
"active_id"]]
   504                     $aresult = $this->db->queryF(
   505                         "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
   506                         [
'integer', 
'integer'],
   509                     while ($row = $this->db->fetchAssoc($aresult)) {
   510                         $this->db->manipulateF(
   511                             "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
   512                             [
'integer', 
'timestamp', 
'integer'],
   513                             [0, null, $row[
"active_id"]]
   527         if ($properties_only) {
   535         $this->marks_repository->storeMarkSchema($this->
getMarkSchema());
   540         $this->db->manipulateF(
   541             'DELETE FROM tst_test_question WHERE test_fi = %s',
   545         foreach ($this->questions as $key => $value) {
   546             $next_id = $this->db->nextId(
'tst_test_question');
   547             $this->db->insert(
'tst_test_question', [
   548                 'test_question_id' => [
'integer', $next_id],
   549                 'test_fi' => [
'integer', $this->
getTestId()],
   550                 'question_fi' => [
'integer', $value],
   551                 'sequence' => [
'integer', $key],
   552                 'tstamp' => [
'integer', time()]
   565         foreach ($question_ids as 
$id) {
   566             $question = assQuestion::instantiateQuestionGUI($id);
   568                 $title = $question->getObject()->getTitle();
   570                 while (in_array(
$title . 
' (' . $i . 
')', $question_titles)) {
   574                 $title .= 
' (' . $i . 
')';
   576                 $question_titles[] = 
$title;
   578                 $new_id = $question->getObject()->duplicate(
false, 
$title);
   580                 $clone = assQuestion::instantiateQuestionGUI($new_id);
   581                 $question = $clone->getObject();
   582                 $question->setObjId($this->
getId());
   583                 $clone->setObject($question);
   584                 $clone->getObject()->saveToDb();
   598         $result = $this->db->queryF(
   599             "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
   600             [
'integer',
'integer'],
   603         return $result->numRows();
   608         $result = $this->db->queryF(
   609             "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
   613         if ($result->numRows() === 1) {
   614             $data = $this->db->fetchObject($result);
   620         if (isset($this->ref_id)) {
   622             switch ($activation[
"timing_type"]) {
   643         $this->questions = [];
   645             if ($active_id === 0) {
   648             if (is_null($pass)) {
   649                 $pass = self::_getPass($active_id);
   651             $result = $this->db->queryF(
   652                 'SELECT tst_test_rnd_qst.* '   653                 . 
'FROM tst_test_rnd_qst, qpl_questions '   654                 . 
'WHERE tst_test_rnd_qst.active_fi = %s '   655                 . 
'AND qpl_questions.question_id = tst_test_rnd_qst.question_fi '   656                 . 
'AND tst_test_rnd_qst.pass = %s '   657                 . 
'ORDER BY sequence',
   658                 [
'integer', 
'integer'],
   662             $result = $this->db->queryF(
   663                 'SELECT tst_test_question.* '   664                 . 
'FROM tst_test_question, qpl_questions '   665                 . 
'WHERE tst_test_question.test_fi = %s '   666                 . 
'AND qpl_questions.question_id = tst_test_question.question_fi '   667                 . 
'ORDER BY sequence',
   673         if ($this->test_id !== -1) {
   675             while (
$data = $this->db->fetchAssoc($result)) {
   676                 $this->questions[$index++] = 
$data[
"question_fi"];
   683         $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
   684         if ($page_id !== null) {
   688         return $this->
getMainSettings()->getIntroductionSettings()->getIntroductionText();
   693         $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
   694         if ($page_id === null) {
   702         $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
   703         if ($page_id !== null) {
   706         return $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksText();
   711         $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
   712         if ($page_id === null) {
   721         $page_object->setParentId($this->
getId());
   722         $new_page_id = $page_object->createPageWithNextId();
   723         (
new ilTestPage($source_page_id))->copy($new_page_id);
   737         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getPostponedQuestionsMoveToEnd();
   742         return $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->isReportingEnabled();
   747         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled();
   752         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled();
   757         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled();
   768         $ilDB = $DIC[
'ilDB'];
   769         $result = 
$ilDB->queryF(
   770             "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",
   774         if ($result->numRows()) {
   775             $row = 
$ilDB->fetchAssoc($result);
   776             return $row[
"count_system"];
   803         $ilDB = $DIC[
'ilDB'];
   804         $result = 
$ilDB->queryF(
   805             "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",
   809         if ($result->numRows()) {
   810             $row = 
$ilDB->fetchAssoc($result);
   811             return (
int) $row[
"pass_scoring"];
   822         $ilDB = $DIC[
'ilDB'];
   823         $result = 
$ilDB->queryF(
   824             "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",
   828         if ($result->numRows()) {
   829             $row = 
$ilDB->fetchAssoc($result);
   830             return (
bool) $row[
"score_cutting"];
   837         if ($this->mark_schema === null) {
   838             $this->mark_schema = $this->marks_repository->getMarkSchemaFor($this->
getTestId());
   846         $this->marks_repository->storeMarkSchema($mark_schema);
   847         $this->mark_schema = null;
   852         return $this->
getMainSettings()->getTestBehaviourSettings()->getNumberOfTries();
   857         return $this->
getMainSettings()->getTestBehaviourSettings()->getBlockAfterPassedEnabled();
   862         return $this->
getMainSettings()->getTestBehaviourSettings()->getKioskModeEnabled();
   867         return $this->
getMainSettings()->getTestBehaviourSettings()->getShowTitleInKioskMode();
   871         return $this->
getMainSettings()->getTestBehaviourSettings()->getShowParticipantNameInKioskMode();
   876         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed();
   881         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionTitleOutputMode();
   886         $result = $this->db->queryF(
   887             "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",
   891         if ($result->numRows()) {
   892             $row = $this->db->fetchAssoc($result);
   893             $test_allows_reuse = $row[
"use_previous_answers"];
   896         if ($test_allows_reuse === 
'1') {
   897             $res = $this->
user->getPref(
"tst_use_previous_answers");
   907         return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
   912         $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
   913         if ($processing_time === null
   914             || $processing_time === 
''   915             || !preg_match(
'/(\d{2}):(\d{2}):(\d{2})/is', $processing_time, $matches)
   930         $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime() ?? 
'';
   931         if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/", (
string) $processing_time, $matches)) {
   933             return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
   941         return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTimeEnabled();
   946         return $this->
getMainSettings()->getTestBehaviourSettings()->getResetProcessingTime();
   951         return $this->
getMainSettings()->getAccessSettings()->getStartTimeEnabled();
   956         $start_time = $this->
getMainSettings()->getAccessSettings()->getStartTime();
   957         return $start_time !== null ? $start_time->getTimestamp() : 0;
   962         return $this->
getMainSettings()->getAccessSettings()->getEndTimeEnabled();
   967         $end_time = $this->
getMainSettings()->getAccessSettings()->getEndTime();
   968         return $end_time !== null ? $end_time->getTimestamp() : 0;
   973         return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode();
   978         return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_KIOSK;
   983         return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_NONE;
   988         return $this->
getMainSettings()->getFinishingSettings()->getRedirectionUrl() ?? 
'';
   993         return $this->
getMainSettings()->getAccessSettings()->getPasswordEnabled();
  1021         $participant_data->load($this->test_id);
  1023         $question->removeAllExistingSolutions();
  1030                 $participant_data->getActiveIds(),
  1037         $question->delete($question_id);
  1046         if ($this->
logger->isLoggingEnabled()) {
  1047             $this->
logger->logTestAdministrationInteraction(
  1048                 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
  1050                     $this->
user->getId(),
  1051                     TestAdministrationInteractionTypes::QUESTION_REMOVED_IN_CORRECTIONS,
  1053                         AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question->getTitleForHTMLOutput(),
  1054                         AdditionalInformationGenerator::KEY_QUESTION_TEXT => $question->getQuestion(),
  1055                         AdditionalInformationGenerator::KEY_QUESTION_ID => $question->getId(),
  1056                         AdditionalInformationGenerator::KEY_QUESTION_TYPE => $question->getQuestionType()
  1074             $this->questionrepository
  1077         foreach ($active_ids as $active_id) {
  1079             $passSelector->setActiveId($active_id);
  1081             foreach ($passSelector->getExistingPasses() as $pass) {
  1082                 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
  1085                 $test_sequence->removeQuestion($question_id, $reindexed_sequence_position_map);
  1096         foreach ($question_ids as $question_id) {
  1106             $question = self::_instanciateQuestion($question_id);
  1107             $question_title = $question->getTitleForHTMLOutput();
  1108             $question->delete($question_id);
  1109             if ($this->
logger->isLoggingEnabled()) {
  1110                 $this->
logger->logTestAdministrationInteraction(
  1111                     $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
  1113                         $this->
user->getId(),
  1114                         TestAdministrationInteractionTypes::QUESTION_REMOVED,
  1116                             AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question_title
  1122             $this->
logger->error($e->getMessage());
  1123             $this->
logger->error($e->getTraceAsString());
  1140         $participantData->setUserIdsFilter($user_ids);
  1141         $participantData->load($this->
getTestId());
  1146         if ($this->
logger->isLoggingEnabled()) {
  1147             $this->
logger->logTestAdministrationInteraction(
  1148                 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
  1150                     $this->
user->getId(),
  1151                     TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
  1153                         AdditionalInformationGenerator::KEY_USERS => $participantData->getUserIds()
  1169             $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $user_ids);
  1172         if ($participant_data->
getUserIds() !== []) {
  1175             if ($test_lp instanceof 
ilTestLP) {
  1176                 $test_lp->setTestObject($this);
  1177                 $test_lp->resetLPDataForUserIds($participant_data->
getUserIds(), 
false);
  1180             $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $participant_data->
getUserIds());
  1190             $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $user_ids);
  1193         if ($this->
logger->isLoggingEnabled()) {
  1194             $this->
logger->logTestAdministrationInteraction(
  1195                 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
  1197                     $this->
user->getId(),
  1198                     TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
  1200                         AdditionalInformationGenerator::KEY_USERS => $participant_data->
getUserIds(),
  1211         $participantData->setUserIdsFilter($user_ids);
  1212         $participantData->load($this->
getTestId());
  1214         $in_user_ids = $this->db->in(
'usr_id', $participantData->getUserIds(), 
false, 
'integer');
  1215         $this->db->manipulateF(
  1216             "DELETE FROM usr_pref WHERE {$in_user_ids} AND keyword = %s",
  1221         if ($participantData->getActiveIds() !== []) {
  1228         $in_active_ids = $this->db->in(
'active_fi', $active_ids, 
false, 
'integer');
  1230         $this->db->manipulate(
"DELETE FROM tst_solutions WHERE {$in_active_ids}");
  1231         $this->db->manipulate(
"DELETE FROM tst_qst_solved WHERE {$in_active_ids}");
  1232         $this->db->manipulate(
"DELETE FROM tst_test_result WHERE {$in_active_ids}");
  1233         $this->db->manipulate(
"DELETE FROM tst_pass_result WHERE {$in_active_ids}");
  1234         $this->db->manipulate(
"DELETE FROM tst_result_cache WHERE {$in_active_ids}");
  1235         $this->db->manipulate(
"DELETE FROM tst_sequence WHERE {$in_active_ids}");
  1236         $this->db->manipulate(
"DELETE FROM tst_times WHERE {$in_active_ids}");
  1237         $this->db->manipulate(
  1239             . 
' WHERE ' . $this->db->in(
'active_id', $active_ids, 
false, 
'integer')
  1243             $this->db->manipulate(
"DELETE FROM tst_test_rnd_qst WHERE {$in_active_ids}");
  1246         foreach ($active_ids as $active_id) {
  1261         $IN_activeIds = $this->db->in(
'active_id', $active_ids, 
false, 
'integer');
  1262         $this->db->manipulate(
"DELETE FROM tst_active WHERE $IN_activeIds");
  1275         $result = $this->db->queryF(
  1276             "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
  1277             [
'integer', 
'integer'],
  1280         $data = $this->db->fetchObject($result);
  1281         if (
$data->sequence > 1) {
  1283             $result = $this->db->queryF(
  1284                 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
  1285                 [
'integer',
'integer'],
  1288             $data_previous = $this->db->fetchObject($result);
  1290             $this->db->manipulateF(
  1291                 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
  1292                 [
'integer',
'integer'],
  1293                 [
$data->sequence, $data_previous->test_question_id]
  1296             $this->db->manipulateF(
  1297                 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
  1298                 [
'integer',
'integer'],
  1299                 [
$data->sequence - 1, 
$data->test_question_id]
  1314         $current_question_result = $this->db->queryF(
  1315             "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
  1316             [
'integer',
'integer'],
  1319         $current_question_data = $this->db->fetchObject($current_question_result);
  1320         $next_question_result = $this->db->queryF(
  1321             "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
  1322             [
'integer',
'integer'],
  1323             [$this->
getTestId(), $current_question_data->sequence + 1]
  1325         if ($this->db->numRows($next_question_result) === 1) {
  1327             $next_question_data = $this->db->fetchObject($next_question_result);
  1329             $this->db->manipulateF(
  1330                 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
  1331                 [
'integer',
'integer'],
  1332                 [$current_question_data->sequence, $next_question_data->test_question_id]
  1335             $this->db->manipulateF(
  1336                 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
  1337                 [
'integer',
'integer'],
  1338                 [$current_question_data->sequence + 1, $current_question_data->test_question_id]
  1353         $duplicate_id = $question->duplicate(
true, 
'', 
'', -1, $this->
getId());
  1354         return $duplicate_id;
  1360             $duplicate_id = $question_id;
  1366         $result = $this->db->queryF(
  1367             "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
  1373         if ($result->numRows() == 1) {
  1374             $data = $this->db->fetchObject($result);
  1375             $sequence = 
$data->seq + 1;
  1378         $next_id = $this->db->nextId(
'tst_test_question');
  1379         $this->db->manipulateF(
  1380             "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
  1381             [
'integer', 
'integer',
'integer',
'integer',
'integer'],
  1382             [$next_id, $this->
getTestId(), $duplicate_id, $sequence, time()]
  1385         $this->db->manipulateF(
  1386             "DELETE FROM tst_active WHERE test_fi = %s",
  1391         $this->
saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
  1393         if ($this->
logger->isLoggingEnabled()) {
  1394             $this->
logger->logTestAdministrationInteraction(
  1395                 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
  1397                     $this->
user->getId(),
  1398                     TestAdministrationInteractionTypes::QUESTION_ADDED,
  1400                         AdditionalInformationGenerator::KEY_QUESTION_ID => $question_id
  1402                             ->toLog($this->
logger->getAdditionalInformationGenerator())
  1407         return $duplicate_id;
  1414             $result = $this->db->queryF(
  1415                 'SELECT qpl_questions.title FROM tst_test_question, qpl_questions '  1416                 . 
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id '  1417                 . 
'ORDER BY tst_test_question.sequence',
  1421             while ($row = $this->db->fetchAssoc($result)) {
  1422                 array_push($titles, $row[
'title']);
  1439             $result = $this->db->queryF(
  1440                 'SELECT qpl_questions.title, qpl_questions.question_id '  1441                 . 
'FROM tst_test_question, qpl_questions '  1442                 . 
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id '  1443                 . 
'ORDER BY tst_test_question.sequence',
  1447             while ($row = $this->db->fetchAssoc($result)) {
  1448                 $titles[$row[
'question_id']] = $row[
"title"];
  1473                     return $this->
lng->txt(
"ass_question") . 
' ' . $nr;
  1475                 return $this->
lng->txt(
"ass_question");
  1479                     $txt = $this->
lng->txt(
"ass_question") . 
' ' . $nr;
  1481                     $txt = $this->
lng->txt(
"ass_question");
  1483                 if ($points != 
'') {
  1484                     $lngv = $this->
lng->txt(
'points');
  1486                         $lngv = $this->
lng->txt(
'point');
  1488                     $txt .= 
' - ' . $points . 
' ' . $lngv;
  1494         return $this->
lng->txt(
"ass_question");
  1508         $result = $this->db->queryF(
  1509             "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",
  1513         $row = $this->db->fetchObject($result);
  1525         $existing_questions = [];
  1528             if (is_null($pass)) {
  1531             $result = $this->db->queryF(
  1532                 "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",
  1533                 [
'integer',
'integer'],
  1537             $result = $this->db->queryF(
  1538                 "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",
  1543         while (
$data = $this->db->fetchObject($result)) {
  1544             if (
$data->original_id === null) {
  1548             array_push($existing_questions, 
$data->original_id);
  1550         return $existing_questions;
  1562         if ($question_id < 1) {
  1565         $result = $this->db->queryF(
  1566             "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",
  1570         if ($result->numRows() == 1) {
  1571             $data = $this->db->fetchObject($result);
  1572             return $data->type_tag;
  1586         $next_id = $this->db->nextId(
'tst_times');
  1587         $affectedRows = $this->db->manipulateF(
  1588             "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
  1589             [
'integer', 
'integer', 
'timestamp', 
'timestamp', 
'integer', 
'integer'],
  1590             [$next_id, $active_id, date(
"Y-m-d H:i:s"), date(
"Y-m-d H:i:s"), $pass, time()]
  1603         $affectedRows = $this->db->manipulateF(
  1604             "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
  1605             [
'timestamp', 
'integer', 
'integer'],
  1606             [date(
'Y-m-d H:i:s'), time(), $times_id]
  1618         if (is_null($pass)) {
  1619             $result = $this->db->queryF(
  1620                 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
  1621                 [
'integer',
'integer'],
  1625             $result = $this->db->queryF(
  1626                 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
  1627                 [
'integer',
'integer'],
  1632         while ($row = $this->db->fetchAssoc($result)) {
  1633             array_push($result_array, $row[
"question_fi"]);
  1635         return $result_array;
  1649         return ((($currentpass > 0) && ($num == 0)) || $this->
isTestFinished($active_id)) ? true : 
false;
  1662             if ($active_id === null) {
  1666             if (count($this->questions) === 0) {
  1669             if (is_null($pass)) {
  1670                 $pass = self::_getPass($active_id);
  1672             $result = $this->db->queryF(
  1673                 "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'),
  1674                 [
'integer',
'integer'],
  1678             if (count($this->questions) === 0) {
  1681             $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'));
  1684         while ($row = $this->db->fetchAssoc($result)) {
  1685             $result_array[$row[
"question_id"]] = $row;
  1687         return $result_array;
  1705         if (is_array($tst_access_code) &&
  1707             isset($tst_access_code[$this->
getTestId()]) &&
  1708             $tst_access_code[$this->
getTestId()] !== 
'') {
  1709             $result = $this->db->queryF(
  1710                 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
  1711                 [
'integer', 
'integer', 
'text'],
  1714         } elseif ((
string) $anonymous_id !== 
'') {
  1715             $result = $this->db->queryF(
  1716                 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
  1717                 [
'integer', 
'integer', 
'text'],
  1718                 [
$user_id, $this->test_id, $anonymous_id]
  1724             $result = $this->db->queryF(
  1725                 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s',
  1726                 [
'integer', 
'integer'],
  1731         if ($result->numRows()) {
  1732             $row = $this->db->fetchAssoc($result);
  1733             return (
int) $row[
'active_id'];
  1742         $ilDB = $DIC[
'ilDB'];
  1743         $ilUser = $DIC[
'ilUser'];
  1751         $result = 
$ilDB->queryF(
  1752             "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
  1753             [
'integer', 
'integer'],
  1756         if ($result->numRows()) {
  1757             $row = 
$ilDB->fetchAssoc($result);
  1758             return $row[
"active_id"];
  1772         $keys = array_keys($array);
  1775         foreach ($keys as $key) {
  1776             $result[$key] = $array[$key];
  1790         bool $ordered_sequence = 
false,
  1791         bool $consider_hidden_questions = 
true,
  1792         bool $consider_optional_questions = 
true  1796         if ($pass === null) {
  1801         $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
  1803         $test_sequence->setConsiderHiddenQuestionsEnabled($consider_hidden_questions);
  1804         $test_sequence->setConsiderOptionalQuestionsEnabled($consider_optional_questions);
  1809         if ($ordered_sequence) {
  1819                 tst_test_result.question_fi,  1820                 tst_test_result.points reached,  1821                 tst_test_result.hint_count requested_hints,  1822                 tst_test_result.hint_points hint_points,  1823                 tst_test_result.answered answered,  1824                 tst_manual_fb.finalized_evaluation finalized_evaluation  1826             FROM tst_test_result  1828             LEFT JOIN tst_solutions  1829             ON tst_solutions.active_fi = tst_test_result.active_fi  1830             AND tst_solutions.question_fi = tst_test_result.question_fi  1832             LEFT JOIN tst_manual_fb  1833             ON tst_test_result.active_fi = tst_manual_fb.active_fi  1834             AND tst_test_result.question_fi = tst_manual_fb.question_fi  1836             WHERE tst_test_result.active_fi = %s  1837             AND tst_test_result.pass = %s  1840         $solutionresult = $this->db->queryF(
  1842             [
'integer', 
'integer'],
  1846         while ($row = $this->db->fetchAssoc($solutionresult)) {
  1847             $arr_results[ $row[
'question_fi'] ] = $row;
  1850         $num_worked_through = count($arr_results);
  1852         $IN_question_ids = $this->db->in(
'qpl_questions.question_id', $sequence, 
false, 
'integer');
  1855                         SELECT          qpl_questions.*,  1856                                                 qpl_qst_type.type_tag,  1857                                                 qpl_sol_sug.question_fi has_sug_sol  1862                         LEFT JOIN       qpl_sol_sug  1863                         ON                      qpl_sol_sug.question_fi = qpl_questions.question_id  1865                         WHERE           qpl_qst_type.question_type_id = qpl_questions.question_type_fi  1866                         AND                     $IN_question_ids  1869         $result = $this->db->query($query);
  1872         while ($row = $this->db->fetchAssoc($result)) {
  1873             if (!isset($arr_results[ $row[
'question_id'] ])) {
  1874                 $percentvalue = 0.0;
  1877                     $row[
'points'] ? $arr_results[$row[
'question_id']][
'reached'] / $row[
'points'] : 0
  1880             if ($percentvalue < 0) {
  1881                 $percentvalue = 0.0;
  1887                 "max" => round($row[
'points'], 2),
  1888                 "reached" => round($arr_results[$row[
'question_id']][
'reached'] ?? 0, 2),
  1889                 'requested_hints' => $arr_results[$row[
'question_id']][
'requested_hints'] ?? 0,
  1890                 'hint_points' => $arr_results[$row[
'question_id']][
'hint_points'] ?? 0,
  1891                 "percent" => sprintf(
"%2.2f ", ($percentvalue) * 100) . 
"%",
  1893                 "type" => $row[
"type_tag"],
  1894                 "qid" => $row[
'question_id'],
  1895                 "original_id" => $row[
"original_id"],
  1896                 "workedthrough" => isset($arr_results[$row[
'question_id']]) ? 1 : 0,
  1897                 'answered' => $arr_results[$row[
'question_id']][
'answered'] ?? 0,
  1898                 'finalized_evaluation' => $arr_results[$row[
'question_id']][
'finalized_evaluation'] ?? 0,
  1901             $unordered[ $row[
'question_id'] ] = 
$data;
  1905         $numQuestionsTotal = count($unordered);
  1909         $pass_requested_hints = 0;
  1910         $pass_hint_points = 0;
  1914         foreach ($sequence as $qid) {
  1917             $pass_max += round($unordered[$qid][
'max'], 2);
  1918             $pass_reached += round($unordered[$qid][
'reached'], 2);
  1919             $pass_requested_hints += $unordered[$qid][
'requested_hints'];
  1920             $pass_hint_points += $unordered[$qid][
'hint_points'];
  1921             $found[] = $unordered[$qid];
  1927             if (
$results[
'reached_points'] < 0) {
  1931             if ($pass_reached < 0) {
  1936         $found[
'pass'][
'total_max_points'] = $pass_max;
  1937         $found[
'pass'][
'total_reached_points'] = $pass_reached;
  1938         $found[
'pass'][
'total_requested_hints'] = $pass_requested_hints;
  1939         $found[
'pass'][
'total_hint_points'] = $pass_hint_points;
  1940         $found[
'pass'][
'percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
  1941         $found[
'pass'][
'num_workedthrough'] = $num_worked_through;
  1942         $found[
'pass'][
'num_questions_total'] = $numQuestionsTotal;
  1944         $found[
"test"][
"total_max_points"] = 
$results[
'max_points'];
  1945         $found[
"test"][
"total_reached_points"] = 
$results[
'reached_points'];
  1946         $found[
"test"][
"total_requested_hints"] = 
$results[
'hint_count'];
  1947         $found[
"test"][
"total_hint_points"] = 
$results[
'hint_points'];
  1948         $found[
"test"][
"result_pass"] = 
$results[
'pass'];
  1949         $found[
'test'][
'result_tstamp'] = 
$results[
'tstamp'];
  1951         if ((!$found[
'pass'][
'total_reached_points']) or (!$found[
'pass'][
'total_max_points'])) {
  1954             $percentage = ($found[
'pass'][
'total_reached_points'] / $found[
'pass'][
'total_max_points']) * 100.0;
  1956             if ($percentage < 0) {
  1961         $found[
"test"][
"passed"] = 
$results[
'passed'];
  1974         $result = $this->db->queryF(
  1975             'SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s',
  1979         $row = $this->db->fetchAssoc($result);
  1980         return $row[
'total'];
  1991         $result = $this->db->queryF(
  1992             "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",
  1993             [
'integer',
'integer'],
  1997         while ($row = $this->db->fetchAssoc($result)) {
  1998             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
  2007             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
  2016             $time += ($epoch_2 - $epoch_1);
  2041         $result = $this->db->queryF(
  2042             "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",
  2048         while ($row = $this->db->fetchAssoc($result)) {
  2049             if (!array_key_exists($row[
"active_fi"], $times)) {
  2050                 $times[$row[
"active_fi"]] = 0;
  2052             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
  2061             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
  2070             $times[$row[
"active_fi"]] += ($epoch_2 - $epoch_1);
  2083         $result = $this->db->queryF(
  2084             "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",
  2085             [
'integer',
'integer'],
  2089         while ($row = $this->db->fetchAssoc($result)) {
  2090             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
  2099             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
  2108             $time += ($epoch_2 - $epoch_1);
  2115         $result = $this->db->queryF(
  2116             "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
  2117             [
'integer',
'integer'],
  2121         while ($row = $this->db->fetchAssoc($result)) {
  2122             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
  2131             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
  2140             $time += ($epoch_2 - $epoch_1);
  2152         $result = $this->db->queryF(
  2153             "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
  2160         while ($row = $this->db->fetchObject($result)) {
  2161             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
  2170             if (!$first_visit) {
  2171                 $first_visit = $epoch_1;
  2173             if ($epoch_1 < $first_visit) {
  2174                 $first_visit = $epoch_1;
  2176             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
  2186                 $last_visit = $epoch_2;
  2188             if ($epoch_2 > $last_visit) {
  2189                 $last_visit = $epoch_2;
  2191             $times[$row->active_fi] += ($epoch_2 - $epoch_1);
  2194         foreach ($times as $key => $value) {
  2195             $max_time += $value;
  2197         if ((!$test_result[
"test"][
"total_reached_points"]) or (!$test_result[
"test"][
"total_max_points"])) {
  2200             $percentage = ($test_result[
"test"][
"total_reached_points"] / $test_result[
"test"][
"total_max_points"]) * 100.0;
  2201             if ($percentage < 0) {
  2205         $mark_obj = $this->
getMarkSchema()->getMatchingMark($percentage);
  2206         $first_date = getdate($first_visit);
  2207         $last_date = getdate($last_visit);
  2208         $qworkedthrough = 0;
  2209         foreach ($test_result as $key => $value) {
  2210             if (preg_match(
"/\d+/", $key)) {
  2211                 $qworkedthrough += $value[
"workedthrough"];
  2214         if (!$qworkedthrough) {
  2217             $atimeofwork = $max_time / $qworkedthrough;
  2223         if ($mark_obj !== null) {
  2224             $result_mark = $mark_obj->getShortName();
  2226             if ($mark_obj->getPassed()) {
  2232         $percent_worked_through = 0;
  2233         if (count($this->questions)) {
  2234             $percent_worked_through = $qworkedthrough / count($this->questions);
  2237             "qworkedthrough" => $qworkedthrough,
  2238             "qmax" => count($this->questions),
  2239             "pworkedthrough" => $percent_worked_through,
  2240             "timeofwork" => $max_time,
  2241             "atimeofwork" => $atimeofwork,
  2242             "firstvisit" => $first_date,
  2243             "lastvisit" => $last_date,
  2244             "resultspoints" => $test_result[
"test"][
"total_reached_points"],
  2245             "maxpoints" => $test_result[
"test"][
"total_max_points"],
  2246             "resultsmarks" => $result_mark,
  2247             "passed" => $passed,
  2248             "distancemedian" => 
"0"  2250         foreach ($test_result as $key => $value) {
  2251             if (preg_match(
"/\d+/", $key)) {
  2252                 $result_array[$key] = $value;
  2255         return $result_array;
  2267         $totalpoints_array = [];
  2269         foreach ($all_users as $active_id => $user_name) {
  2271             $reached = $test_result[
"test"][
"total_reached_points"];
  2272             $total = $test_result[
"test"][
"total_max_points"];
  2273             $percentage = $total != 0 ? $reached / $total : 0;
  2274             $mark = $this->
getMarkSchema()->getMatchingMark($percentage * 100.0);
  2276             if ($mark !== null && $mark->getPassed()) {
  2277                 array_push($totalpoints_array, $test_result[
"test"][
"total_reached_points"]);
  2280         return $totalpoints_array;
  2290         $result = $this->db->queryF(
  2291             "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",
  2295         $persons_array = [];
  2296         while ($row = $this->db->fetchAssoc($result)) {
  2297             $name = $this->
lng->txt(
"anonymous");
  2298             $fullname = $this->
lng->txt(
"anonymous");
  2301                 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
  2302                     $name = $this->
lng->txt(
"deleted_user");
  2303                     $fullname = $this->
lng->txt(
"deleted_user");
  2304                     $login = $this->
lng->txt(
"unknown");
  2306                     $login = $row[
"login"];
  2308                         $name = $this->
lng->txt(
"anonymous");
  2309                         $fullname = $this->
lng->txt(
"anonymous");
  2311                         $name = trim($row[
"lastname"] . 
", " . $row[
"firstname"] . 
" " . $row[
"title"]);
  2312                         $fullname = trim($row[
"title"] . 
" " . $row[
"firstname"] . 
" " . $row[
"lastname"]);
  2316             $persons_array[$row[
"active_id"]] = [
  2318                 "fullname" => $fullname,
  2322         return $persons_array;
  2327         $result = $this->db->queryF(
  2328             "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),
  2332         $persons_array = [];
  2333         while ($row = $this->db->fetchAssoc($result)) {
  2339                 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"anonymous");
  2341                 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
  2342                     $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"deleted_user");
  2345                         $persons_array[$row[
"active_id"]] = $row[
"lastname"];
  2347                         $persons_array[$row[
"active_id"]] = trim($row[
"lastname"] . 
", " . $row[
"firstname"] . 
" " . $row[
"title"]);
  2352         return $persons_array;
  2357         $result = $this->db->queryF(
  2358             'SELECT tst_active.user_fi, tst_active.active_id, usr_data.login, '  2359             . 
'usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active '  2360             . 
'LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id '  2361             . 
'WHERE tst_active.test_fi = %s '  2362             . 
'ORDER BY usr_data.lastname ' . strtoupper($name_sort_order),
  2366         $persons_array = [];
  2367         while ($row = $this->db->fetchAssoc($result)) {
  2369                 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
"anonymous")];
  2371                 if (strlen($row[
'firstname'] . $row[
'lastname'] . $row[
"title"]) == 0) {
  2372                     $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
'deleted_user')];
  2375                         $persons_array[$row[
'active_id']] = [
'name' => $row[
'lastname']];
  2377                         $persons_array[$row[
'active_id']] = [
  2378                             'name' => trim($row[
'lastname'] . 
', ' . $row[
'firstname']
  2379                                 . 
' ' . $row[
'title']),
  2380                             'login' => $row[
'login']
  2386         return $persons_array;
  2393             $result = $this->db->queryF(
  2394                 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, '  2395                 . 
'tst_test_rnd_qst.pass, qpl_questions.points '  2396                 . 
'FROM tst_test_rnd_qst, qpl_questions '  2397                 . 
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id '  2398                 . 
'AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence',
  2403             $result = $this->db->queryF(
  2404                 'SELECT tst_test_question.sequence, tst_test_question.question_fi, '  2405                 . 
'qpl_questions.points '  2406                 . 
'FROM tst_test_question, tst_active, qpl_questions '  2407                 . 
'WHERE tst_test_question.question_fi = qpl_questions.question_id '  2408                 . 
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
  2414         if ($result->numRows()) {
  2415             while ($row = $this->db->fetchAssoc($result)) {
  2416                 array_push($qtest, $row);
  2426             $result = $this->db->queryF(
  2427                 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, '  2428                 . 
'qpl_questions.points '  2429                 . 
'FROM tst_test_rnd_qst, qpl_questions '  2430                 . 
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id '  2431                 . 
'AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s '  2432                 . 
'ORDER BY tst_test_rnd_qst.sequence',
  2433                 [
'integer', 
'integer'],
  2437             $result = $this->db->queryF(
  2438                 'SELECT tst_test_question.sequence, tst_test_question.question_fi, '  2439                 . 
'qpl_questions.points '  2440                 . 
'FROM tst_test_question, tst_active, qpl_questions '  2441                 . 
'WHERE tst_test_question.question_fi = qpl_questions.question_id '  2442                 . 
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
  2448         if ($result->numRows()) {
  2449             while ($row = $this->db->fetchAssoc($result)) {
  2450                 array_push($qpass, $row);
  2471         return $list->getAccessFilteredList(
  2472             $this->participant_access_filter->getAccessStatisticsUserFilter($this->getRefId())
  2479             ->getEvaluationData();
  2486         switch ($question_set_type) {
  2488                 $res = $this->db->queryF(
  2490                                                 SELECT          tst_test_rnd_qst.pass,  2491                                                                         COUNT(tst_test_rnd_qst.question_fi) qcount,  2492                                                                         SUM(qpl_questions.points) qsum  2494                                                 FROM            tst_test_rnd_qst,  2497                                                 WHERE           tst_test_rnd_qst.question_fi = qpl_questions.question_id  2498                                                 AND                     tst_test_rnd_qst.active_fi = %s  2501                                                 GROUP BY        tst_test_rnd_qst.active_fi,  2502                                                                         tst_test_rnd_qst.pass  2504                     [
'integer', 
'integer'],
  2510                 $res = $this->db->queryF(
  2512                                                 SELECT          COUNT(tst_test_question.question_fi) qcount,  2513                                                                         SUM(qpl_questions.points) qsum  2515                                                 FROM            tst_test_question,  2519                                                 WHERE           tst_test_question.question_fi = qpl_questions.question_id  2520                                                 AND                     tst_test_question.test_fi = tst_active.test_fi  2521                                                 AND                     tst_active.active_id = %s  2523                                                 GROUP BY        tst_test_question.test_fi  2531                 throw new ilTestException(
"not supported question set type: $question_set_type");
  2534         $row = $this->db->fetchAssoc(
$res);
  2536         if (is_array($row)) {
  2537             return [
"count" => $row[
"qcount"], 
"points" => $row[
"qsum"]];
  2540         return [
"count" => 0, 
"points" => 0];
  2546         $data->setFilter($filterby, $filtertext);
  2566         if ($user_id === null
  2567             || $firstname . $lastname === 
'') {
  2568             return $this->
lng->txt(
'deleted_user');
  2572             return $this->
lng->txt(
'anonymous');
  2579         return trim($lastname . 
', ' . $firstname);
  2584         $query = 
"SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
  2586         if ($active_ids_to_filter !== null && $active_ids_to_filter !== []) {
  2587             $query .= 
" AND " . $this->db->in(
'active_id', $active_ids_to_filter, 
false, 
'integer');
  2590         $result = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
  2592         while ($row = $this->db->fetchObject($result)) {
  2593             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
  2602             preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
  2611             if (isset($times[$row->active_fi])) {
  2612                 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
  2614                 $times[$row->active_fi] = ($epoch_2 - $epoch_1);
  2619         foreach ($times as $value) {
  2620             $max_time += $value;
  2623         if ($counter === 0) {
  2626         return (
int) round($max_time / $counter);
  2636         bool $use_object_id = 
false,
  2637         ?
bool $equal_points = 
false,
  2638         bool $could_be_offline = 
false,
  2639         bool $show_path = 
false,
  2640         bool $with_questioncount = 
false,
  2641         string $permission = 
'read'  2645             $equal_points ?? 
false,
  2648             $with_questioncount,
  2690         if ((!$question_type) and ($question_id > 0)) {
  2694         if (!strlen($question_type)) {
  2698         if ($question_id > 0) {
  2699             $question_gui = assQuestion::instantiateQuestionGUI($question_id);
  2701             $question_type_gui = $question_type . 
'GUI';
  2702             $question_gui = 
new $question_type_gui();
  2705         return $question_gui;
  2716         if (strcmp((
string) $question_id, 
"") !== 0) {
  2727     public function moveQuestions(array $move_questions, 
int $target_index, 
int $insert_mode): void
  2729         $this->questions = array_values($this->questions);
  2730         $array_pos = array_search($target_index, $this->questions);
  2731         if ($insert_mode == 0) {
  2732             $part1 = array_slice($this->questions, 0, $array_pos);
  2733             $part2 = array_slice($this->questions, $array_pos);
  2734         } elseif ($insert_mode == 1) {
  2735             $part1 = array_slice($this->questions, 0, $array_pos + 1);
  2736             $part2 = array_slice($this->questions, $array_pos + 1);
  2738         foreach ($move_questions as $question_id) {
  2739             if (!(array_search($question_id, $part1) === 
false)) {
  2740                 unset($part1[array_search($question_id, $part1)]);
  2742             if (!(array_search($question_id, $part2) === 
false)) {
  2743                 unset($part2[array_search($question_id, $part2)]);
  2746         $part1 = array_values($part1);
  2747         $part2 = array_values($part2);
  2748         $new_array = array_values(array_merge($part1, $move_questions, $part2));
  2749         $this->questions = [];
  2751         foreach ($new_array as $question_id) {
  2752             $this->questions[$counter] = $question_id;
  2757         if ($this->
logger->isLoggingEnabled()) {
  2758             $this->
logger->logTestAdministrationInteraction(
  2759                 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
  2761                     $this->
user->getId(),
  2762                     TestAdministrationInteractionTypes::QUESTION_MOVED,
  2817         if (count($available_pools)) {
  2818             $available = 
" AND " . $this->db->in(
'qpl_questions.obj_fi', $available_pools, 
false, 
'integer');
  2822         if ($completeonly) {
  2823             $available .= 
" AND qpl_questions.complete = " . $this->db->quote(
"1", 
'text');
  2827         if (is_array($arr_filter)) {
  2828             if (array_key_exists(
'title', $arr_filter) && strlen($arr_filter[
'title'])) {
  2829                 $where .= 
" AND " . $this->db->like(
'qpl_questions.title', 
'text', 
"%%" . $arr_filter[
'title'] . 
"%%");
  2831             if (array_key_exists(
'description', $arr_filter) && strlen($arr_filter[
'description'])) {
  2832                 $where .= 
" AND " . $this->db->like(
'qpl_questions.description', 
'text', 
"%%" . $arr_filter[
'description'] . 
"%%");
  2834             if (array_key_exists(
'author', $arr_filter) && strlen($arr_filter[
'author'])) {
  2835                 $where .= 
" AND " . $this->db->like(
'qpl_questions.author', 
'text', 
"%%" . $arr_filter[
'author'] . 
"%%");
  2837             if (array_key_exists(
'type', $arr_filter) && strlen($arr_filter[
'type'])) {
  2838                 $where .= 
" AND qpl_qst_type.type_tag = " . $this->db->quote($arr_filter[
'type'], 
'text');
  2840             if (array_key_exists(
'qpl', $arr_filter) && strlen($arr_filter[
'qpl'])) {
  2841                 $where .= 
" AND " . $this->db->like(
'object_data.title', 
'text', 
"%%" . $arr_filter[
'qpl'] . 
"%%");
  2846         $original_clause = 
" qpl_questions.original_id IS NULL";
  2847         if (count($original_ids)) {
  2848             $original_clause = 
" qpl_questions.original_id IS NULL AND " . $this->db->in(
'qpl_questions.question_id', $original_ids, 
true, 
'integer');
  2851         $query_result = $this->db->query(
"  2852                         SELECT          qpl_questions.*, qpl_questions.tstamp,  2853                                                 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,  2854                                                 object_data.title parent_title  2855                         FROM            qpl_questions, qpl_qst_type, object_data  2856                         WHERE $original_clause $available  2857                         AND object_data.obj_id = qpl_questions.obj_fi  2858                         AND qpl_questions.tstamp > 0  2859                         AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id  2864         if ($query_result->numRows()) {
  2865             while ($row = $this->db->fetchAssoc($query_result)) {
  2868                 if (!$row[
'plugin']) {
  2869                     $row[ 
'ttype' ] = $this->
lng->txt($row[ 
"type_tag" ]);
  2875                 $plugin = $this->component_repository->getPluginByName($row[
'plugin_name']);
  2880                 $pl = $this->component_factory->getPlugin(
$plugin->getId());
  2881                 $row[ 
'ttype' ] = $pl->getQuestionTypeTranslation();
  2895         if (($importdir = 
ilSession::get(
'path_to_container_import_file')) === null) {
  2913         $introduction_settings = $introduction_settings->withIntroductionEnabled(
false);
  2914         foreach ($assessment->objectives as 
$objectives) {
  2915             foreach ($objectives->materials as $material) {
  2917                     $introduction_settings,
  2929                 $finishing_settings,
  2945         foreach ($assessment->qtimetadata as 
$metadata) {
  2946             switch ($metadata[
"label"]) {
  2947                 case "solution_details":
  2948                     $result_details_settings = $result_details_settings->withShowPassDetails((
bool) $metadata[
"entry"]);
  2950                 case "show_solution_list_comparison":
  2951                     $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
  2953                 case "print_bs_with_res":
  2954                     $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
  2960                     $test_behaviour_settings = $test_behaviour_settings->withNumberOfTries((
int) $metadata[
"entry"]);
  2962                 case 'block_after_passed':
  2963                     $test_behaviour_settings = $test_behaviour_settings->withBlockAfterPassedEnabled((
bool) $metadata[
'entry']);
  2965                 case "pass_waiting":
  2966                     $test_behaviour_settings = $test_behaviour_settings->withPassWaiting($metadata[
"entry"]);
  2969                     $test_behaviour_settings = $test_behaviour_settings->withKioskMode((
int) $metadata[
"entry"]);
  2971                 case 'show_introduction':
  2972                     $introduction_settings = $introduction_settings->withIntroductionEnabled((
bool) $metadata[
'entry']);
  2974                 case "showfinalstatement":
  2975                 case 'show_concluding_remarks':
  2976                     $finishing_settings = $finishing_settings->withConcludingRemarksEnabled((
bool) $metadata[
"entry"]);
  2978                 case 'exam_conditions':
  2979                     $introduction_settings = $introduction_settings->withExamConditionsCheckboxEnabled($metadata[
'entry'] === 
'1');
  2981                 case "highscore_enabled":
  2982                     $gamification_settings = $gamification_settings->withHighscoreEnabled((
bool) $metadata[
"entry"]);
  2984                 case "highscore_anon":
  2985                     $gamification_settings = $gamification_settings->withHighscoreAnon((
bool) $metadata[
"entry"]);
  2987                 case "highscore_achieved_ts":
  2988                     $gamification_settings = $gamification_settings->withHighscoreAchievedTS((
bool) $metadata[
"entry"]);
  2990                 case "highscore_score":
  2991                     $gamification_settings = $gamification_settings->withHighscoreScore((
bool) $metadata[
"entry"]);
  2993                 case "highscore_percentage":
  2994                     $gamification_settings = $gamification_settings->withHighscorePercentage((
bool) $metadata[
"entry"]);
  2996                 case "highscore_hints":
  2997                     $gamification_settings = $gamification_settings->withHighscoreHints((
bool) $metadata[
"entry"]);
  2999                 case "highscore_wtime":
  3000                     $gamification_settings = $gamification_settings->withHighscoreWTime((
bool) $metadata[
"entry"]);
  3002                 case "highscore_own_table":
  3003                     $gamification_settings = $gamification_settings->withHighscoreOwnTable((
bool) $metadata[
"entry"]);
  3005                 case "highscore_top_table":
  3006                     $gamification_settings = $gamification_settings->withHighscoreTopTable((
bool) $metadata[
"entry"]);
  3008                 case "highscore_top_num":
  3009                     $gamification_settings = $gamification_settings->withHighscoreTopNum((
int) $metadata[
"entry"]);
  3011                 case "use_previous_answers":
  3012                     $participant_functionality_settings = $participant_functionality_settings->withUsePreviousAnswerAllowed((
bool) $metadata[
"entry"]);
  3014                 case 'question_list_enabled':
  3015                     $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
'entry']);
  3017                 case "title_output":
  3018                     $question_behaviour_settings = $question_behaviour_settings->withQuestionTitleOutputMode((
int) $metadata[
"entry"]);
  3020                 case "question_set_type":
  3021                     if ($metadata[
'entry'] === self::QUESTION_SET_TYPE_RANDOM) {
  3022                         $this->questions = [];
  3024                     $general_settings = $general_settings->withQuestionSetType($metadata[
"entry"]);
  3027                     $general_settings = $general_settings->withAnonymity((
bool) $metadata[
"entry"]);
  3029                 case "results_presentation":
  3030                     $result_details_settings = $result_details_settings->withResultsPresentation((
int) $metadata[
"entry"]);
  3032                 case "reset_processing_time":
  3033                     $test_behaviour_settings = $test_behaviour_settings->withResetProcessingTime($metadata[
"entry"] === 
'1');
  3035                 case "answer_feedback_points":
  3036                     $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackPointsEnabled((
bool) $metadata[
"entry"]);
  3038                 case "answer_feedback":
  3039                     $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackGenericEnabled((
bool) $metadata[
"entry"]);
  3041                 case 'instant_feedback_specific':
  3042                     $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSpecificEnabled((
bool) $metadata[
'entry']);
  3044                 case "instant_verification":
  3045                     $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSolutionEnabled((
bool) $metadata[
"entry"]);
  3047                 case "force_instant_feedback":
  3048                     $question_behaviour_settings = $question_behaviour_settings->withForceInstantFeedbackOnNextQuestion((
bool) $metadata[
"entry"]);
  3050                 case "follow_qst_answer_fixation":
  3051                     $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnNextQuestionEnabled((
bool) $metadata[
"entry"]);
  3053                 case "instant_feedback_answer_fixation":
  3054                     $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnInstantFeedbackEnabled((
bool) $metadata[
"entry"]);
  3057                 case "suspend_test_allowed":
  3058                     $participant_functionality_settings = $participant_functionality_settings->withSuspendTestAllowed((
bool) $metadata[
"entry"]);
  3060                 case "sequence_settings":
  3061                     $participant_functionality_settings = $participant_functionality_settings->withPostponedQuestionsMoveToEnd((
bool) $metadata[
"entry"]);
  3064                     $participant_functionality_settings = $participant_functionality_settings->withQuestionMarkingEnabled((
bool) $metadata[
"entry"]);
  3066                 case "fixed_participants":
  3067                     $access_settings = $access_settings->withFixedParticipants((
bool) $metadata[
"entry"]);
  3069                 case "score_reporting":
  3070                     if ($metadata[
'entry'] !== null) {
  3071                         $result_summary_settings = $result_summary_settings->withScoreReporting(
  3072                             ScoreReportingTypes::tryFrom((
int) $metadata[
'entry']) ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED
  3076                 case "shuffle_questions":
  3077                     $question_behaviour_settings = $question_behaviour_settings->withShuffleQuestions((
bool) $metadata[
"entry"]);
  3079                 case "count_system":
  3080                     $scoring_settings = $scoring_settings->withCountSystem((
int) $metadata[
"entry"]);
  3082                 case "mailnotification":
  3083                     $finishing_settings = $finishing_settings->withMailNotificationContentType((
int) $metadata[
"entry"]);
  3086                     $finishing_settings = $finishing_settings->withAlwaysSendMailNotification((
bool) $metadata[
"entry"]);
  3088                 case "exportsettings":
  3089                     $result_details_settings = $result_details_settings->withExportSettings((
int) $metadata[
"entry"]);
  3091                 case "score_cutting":
  3092                     $scoring_settings = $scoring_settings->withScoreCutting((
int) $metadata[
"entry"]);
  3095                     $access_settings = $access_settings->withPasswordEnabled(
  3096                         $metadata[
"entry"] !== null && $metadata[
"entry"] !== 
''  3097                     )->withPassword($metadata[
"entry"]);
  3099                 case 'ip_range_from':
  3100                     if ($metadata[
'entry'] !== 
'') {
  3101                         $access_settings = $access_settings->withIpRangeFrom($metadata[
'entry']);
  3105                     if ($metadata[
'entry'] !== 
'') {
  3106                         $access_settings = $access_settings->withIpRangeTo($metadata[
'entry']);
  3109                 case "pass_scoring":
  3110                     $scoring_settings = $scoring_settings->withPassScoring((
int) $metadata[
"entry"]);
  3112                 case 'pass_deletion_allowed':
  3113                     $result_summary_settings = $result_summary_settings->withPassDeletionAllowed((
bool) $metadata[
"entry"]);
  3115                 case "usr_pass_overview_mode":
  3116                     $participant_functionality_settings = $participant_functionality_settings->withUsrPassOverviewMode((
int) $metadata[
"entry"]);
  3118                 case "question_list":
  3119                     $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
"entry"]);
  3122                 case "reporting_date":
  3124                     if ($reporting_date !== null) {
  3125                         $result_summary_settings = $result_summary_settings->withReportingDate($reporting_date);
  3128                 case 'enable_processing_time':
  3129                     $test_behaviour_settings = $test_behaviour_settings->withProcessingTimeEnabled((
bool) $metadata[
'entry']);
  3131                 case "processing_time":
  3132                     $test_behaviour_settings = $test_behaviour_settings->withProcessingTime($metadata[
'entry']);
  3134                 case "starting_time":
  3136                     if ($starting_time !== null) {
  3137                         $access_settings = $access_settings->withStartTime($starting_time)
  3138                             ->withStartTimeEnabled(
true);
  3143                     if ($ending_time !== null) {
  3144                         $access_settings = $access_settings->withEndTime($ending_time)
  3145                             ->withStartTimeEnabled(
true);
  3148                 case "enable_examview":
  3149                     $finishing_settings = $finishing_settings->withShowAnswerOverview((
bool) $metadata[
"entry"]);
  3151                 case 'redirection_mode':
  3152                     $finishing_settings = $finishing_settings->withRedirectionMode((
int) $metadata[
'entry']);
  3154                 case 'redirection_url':
  3155                     $finishing_settings = $finishing_settings->withRedirectionUrl($metadata[
'entry']);
  3157                 case 'examid_in_test_pass':
  3158                     $test_behaviour_settings = $test_behaviour_settings->withExamIdInTestAttemptEnabled((
bool) $metadata[
'entry']);
  3160                 case 'examid_in_test_res':
  3161                     $result_details_settings = $result_details_settings->withShowExamIdInTestResults((
bool) $metadata[
"entry"]);
  3163                 case 'skill_service':
  3164                     $additional_settings = $additional_settings->withSkillsServiceEnabled((
bool) $metadata[
'entry']);
  3166                 case 'show_grading_status':
  3167                     $result_summary_settings = $result_summary_settings->withShowGradingStatusEnabled((
bool) $metadata[
"entry"]);
  3169                 case 'show_grading_mark':
  3170                     $result_summary_settings = $result_summary_settings->withShowGradingMarkEnabled((
bool) $metadata[
"entry"]);
  3172                 case 'activation_limited':
  3175                 case 'activation_start_time':
  3178                 case 'activation_end_time':
  3181                 case 'activation_visibility':
  3185                     $question_behaviour_settings = $question_behaviour_settings->withAutosaveEnabled((
bool) $metadata[
'entry']);
  3187                 case 'autosave_ival':
  3188                     $question_behaviour_settings = $question_behaviour_settings->withAutosaveInterval((
int) $metadata[
'entry']);
  3190                 case 'offer_question_hints':
  3191                     $question_behaviour_settings = $question_behaviour_settings->withQuestionHintsEnabled((
bool) $metadata[
'entry']);
  3193                 case 'show_summary':
  3194                     $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled(($metadata[
'entry'] & 1) > 0)
  3195                         ->withUsrPassOverviewMode((
int) $metadata[
'entry']);
  3198                 case 'hide_info_tab':
  3199                     $additional_settings = $additional_settings->withHideInfoTab($metadata[
'entry'] === 
'1');
  3201             if (preg_match(
"/mark_step_\d+/", $metadata[
"label"])) {
  3202                 $xmlmark = $metadata[
"entry"];
  3203                 preg_match(
"/<short>(.*?)<\/short>/", $xmlmark, $matches);
  3204                 $mark_short = $matches[1];
  3205                 preg_match(
"/<official>(.*?)<\/official>/", $xmlmark, $matches);
  3206                 $mark_official = $matches[1];
  3207                 preg_match(
"/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
  3208                 $mark_percentage = (float) $matches[1];
  3209                 preg_match(
"/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
  3210                 $mark_passed = (bool) $matches[1];
  3211                 $mark_steps[] = 
new Mark($mark_short, $mark_official, $mark_percentage, $mark_passed);
  3214         $this->mark_schema = $this->
getMarkSchema()->withMarkSteps($mark_steps);
  3222         $main_settings = $main_settings
  3224             ->withIntroductionSettings($introduction_settings)
  3225             ->withAccessSettings($access_settings)
  3226             ->withParticipantFunctionalitySettings($participant_functionality_settings)
  3227             ->withTestBehaviourSettings($test_behaviour_settings)
  3228             ->withQuestionBehaviourSettings($question_behaviour_settings)
  3229             ->withFinishingSettings($finishing_settings)
  3230             ->withAdditionalSettings($additional_settings);
  3234         $score_settings = $score_settings
  3236                 ->withScoringSettings($scoring_settings)
  3237                 ->withResultDetailsSettings($result_details_settings)
  3238                 ->withResultSummarySettings($result_summary_settings);
  3250         $text = $material[
'text'];
  3251         $mobs = $material[
'mobs'];
  3252         if (str_starts_with(
$text, 
'<PageObject>')) {
  3255                 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
  3259                 $mappings[
'components/ILIAS/File'][
'file'] ?? []
  3262             $page_object->setParentId($this->
getId());
  3263             $page_object->setXMLContent(
$text);
  3264             $new_page_id = $page_object->createPageWithNextId();
  3284         $text = $material[
'text'];
  3285         $mobs = $material[
'mobs'];
  3286         if (str_starts_with(
$text, 
'<PageObject>')) {
  3289                 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
  3293                 $mappings[
'components/ILIAS/File'][
'file'] ?? []
  3296             $page_object->setParentId($this->
getId());
  3297             $page_object->setXMLContent(
$text);
  3298             $new_page_id = $page_object->createPageWithNextId();
  3319         preg_match_all(
'/il_(\d+)_mob_(\d+)/', $text, $matches);
  3320         foreach ($matches[0] as $index => $match) {
  3321             if (empty($mappings[$matches[2][$index]])) {
  3324             $text = str_replace($match, 
"il__mob_{$mappings[$matches[2][$index]]}", $text);
  3332         preg_match_all(
'/il_(\d+)_file_(\d+)/', $text, $matches);
  3333         foreach ($matches[0] as $index => $match) {
  3334             if (empty($mappings[$matches[2][$index]])) {
  3337             $text = str_replace($match, 
"il__file_{$mappings[$matches[2][$index]]}", $text);
  3344         foreach ($mobs as $mob) {
  3345             $importfile = $importdir . DIRECTORY_SEPARATOR . $mob[
'uri'];
  3346             if (file_exists($importfile)) {
  3351                         'src="' . $mob[
'mob'] . 
'"',
  3352                         'src="' . 
'il_' . 
IL_INST_ID . 
'_mob_' . $media_object->getId() . 
'"',
  3372         $a_xml_writer->xmlHeader();
  3373         $a_xml_writer->xmlSetDtdDef(
"<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
  3374         $a_xml_writer->xmlStartTag(
"questestinterop");
  3380         $a_xml_writer->xmlStartTag(
"assessment", $attrs);
  3381         $a_xml_writer->xmlElement(
"qticomment", null, $this->
getDescription());
  3384             $a_xml_writer->xmlElement(
  3391         $a_xml_writer->xmlStartTag(
"qtimetadata");
  3392         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3393         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"ILIAS_VERSION");
  3394         $a_xml_writer->xmlElement(
"fieldentry", null, 
ILIAS_VERSION);
  3395         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3397         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3398         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"anonymity");
  3399         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getGeneralSettings()->getAnonymity()));
  3400         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3402         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3403         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"question_set_type");
  3404         $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getGeneralSettings()->getQuestionSetType());
  3405         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3407         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3408         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"sequence_settings");
  3410         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3412         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3413         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"author");
  3414         $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getAuthor());
  3415         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3417         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3418         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"reset_processing_time");
  3419         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getTestBehaviourSettings()->getResetProcessingTime());
  3420         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3422         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3423         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"count_system");
  3424         $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getCountSystem());
  3425         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3427         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3428         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"score_cutting");
  3429         $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getScoreCutting());
  3430         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3432         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3433         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"password");
  3434         $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getAccessSettings()->getPassword() ?? 
'');
  3435         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3437         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3438         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"ip_range_from");
  3439         $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getAccessSettings()->getIpRangeFrom());
  3440         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3442         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3443         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"ip_range_to");
  3444         $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getAccessSettings()->getIpRangeTo());
  3445         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3447         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3448         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"pass_scoring");
  3449         $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getPassScoring());
  3450         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3452         $a_xml_writer->xmlStartTag(
'qtimetadatafield');
  3453         $a_xml_writer->xmlElement(
'fieldlabel', null, 
'pass_deletion_allowed');
  3455         $a_xml_writer->xmlEndTag(
'qtimetadatafield');
  3457         if ($this->
getScoreSettings()->getResultSummarySettings()->getReportingDate() !== null) {
  3458             $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3459             $a_xml_writer->xmlElement(
"fieldlabel", null, 
"reporting_date");
  3460             $a_xml_writer->xmlElement(
  3467             $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3470         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3471         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"nr_of_tries");
  3472         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getNumberOfTries()));
  3473         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3475         $a_xml_writer->xmlStartTag(
'qtimetadatafield');
  3476         $a_xml_writer->xmlElement(
'fieldlabel', null, 
'block_after_passed');
  3477         $a_xml_writer->xmlElement(
'fieldentry', null, (
int) $main_settings->
getTestBehaviourSettings()->getBlockAfterPassedEnabled());
  3478         $a_xml_writer->xmlEndTag(
'qtimetadatafield');
  3480         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3481         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"pass_waiting");
  3483         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3485         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3486         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"kiosk");
  3487         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getKioskMode()));
  3488         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3490         $a_xml_writer->xmlStartTag(
'qtimetadatafield');
  3491         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"redirection_mode");
  3492         $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getFinishingSettings()->getRedirectionMode());
  3493         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3495         $a_xml_writer->xmlStartTag(
'qtimetadatafield');
  3496         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"redirection_url");
  3497         $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getFinishingSettings()->getRedirectionUrl());
  3498         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3500         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3501         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"use_previous_answers");
  3503         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3505         $a_xml_writer->xmlStartTag(
'qtimetadatafield');
  3506         $a_xml_writer->xmlElement(
'fieldlabel', null, 
'question_list_enabled');
  3508         $a_xml_writer->xmlEndTag(
'qtimetadatafield');
  3510         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3511         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"title_output");
  3512         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getQuestionBehaviourSettings()->getQuestionTitleOutputMode()));
  3513         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3515         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3516         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"results_presentation");
  3517         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getResultsPresentation()));
  3518         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3520         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3521         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"examid_in_test_pass");
  3522         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getExamIdInTestAttemptEnabled()));
  3523         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3525         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3526         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"examid_in_test_res");
  3527         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults()));
  3528         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3530         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3531         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"usr_pass_overview_mode");
  3533         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3535         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3536         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"score_reporting");
  3537         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->value));
  3538         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3540         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3541         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"show_solution_list_comparison");
  3542         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $this->score_settings->getResultDetailsSettings()->getShowSolutionListComparison());
  3543         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3545         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3546         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"instant_verification");
  3547         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled()));
  3548         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3550         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3551         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"answer_feedback");
  3552         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled()));
  3553         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3555         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3556         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"instant_feedback_specific");
  3557         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled()));
  3558         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3560         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3561         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"answer_feedback_points");
  3562         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled()));
  3563         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3565         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3566         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"follow_qst_answer_fixation");
  3567         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled());
  3568         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3570         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3571         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"instant_feedback_answer_fixation");
  3572         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled());
  3573         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3575         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3576         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"force_instant_feedback");
  3577         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion());
  3578         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3580         $highscore_metadata = [
  3592         foreach ($highscore_metadata as $label => 
$data) {
  3593             $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3594             $a_xml_writer->xmlElement(
"fieldlabel", null, $label);
  3595             $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", 
$data[
'value']));
  3596             $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3599         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3600         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"suspend_test_allowed");
  3602         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3604         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3605         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"show_marker");
  3607         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3609         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3610         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"fixed_participants");
  3611         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getAccessSettings()->getFixedParticipants()));
  3612         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3614         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3615         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"show_introduction");
  3616         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getIntroductionEnabled()));
  3617         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3619         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3620         $a_xml_writer->xmlElement(
"fieldlabel", null, 
'exam_conditions');
  3621         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getExamConditionsCheckboxEnabled()));
  3622         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3624         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3625         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"show_concluding_remarks");
  3626         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getFinishingSettings()->getConcludingRemarksEnabled()));
  3627         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3629         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3630         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"mailnotification");
  3631         $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getFinishingSettings()->getMailNotificationContentType());
  3632         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3634         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3635         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"mailnottype");
  3636         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getFinishingSettings()->getAlwaysSendMailNotification());
  3637         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3639         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3640         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"exportsettings");
  3642         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3644         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3645         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"shuffle_questions");
  3646         $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getShuffleQuestions()));
  3647         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3649         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3650         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"processing_time");
  3652         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3654         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3655         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"enable_examview");
  3656         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getFinishingSettings()->getShowAnswerOverview());
  3657         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3659         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3660         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"skill_service");
  3661         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getAdditionalSettings()->getSkillsServiceEnabled());
  3662         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3666                 "solutionswitch" => 
"Yes"  3671         $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs, null);
  3673         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3674         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"show_grading_status");
  3676         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3678         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3679         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"show_grading_mark");
  3681         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3683         $a_xml_writer->xmlStartTag(
'qtimetadatafield');
  3684         $a_xml_writer->xmlElement(
'fieldlabel', null, 
'hide_info_tab');
  3685         $a_xml_writer->xmlElement(
'fieldentry', null, (
int) $this->
getMainSettings()->getAdditionalSettings()->getHideInfoTab());
  3686         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3689             $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3690             $a_xml_writer->xmlElement(
"fieldlabel", null, 
"starting_time");
  3691             $a_xml_writer->xmlElement(
  3698             $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3702             $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3703             $a_xml_writer->xmlElement(
"fieldlabel", null, 
"ending_time");
  3704             $a_xml_writer->xmlElement(
  3711             $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3714         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3715         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"activation_limited");
  3717         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3719         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3720         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"activation_start_time");
  3722         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3724         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3725         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"activation_end_time");
  3727         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3729         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3730         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"activation_visibility");
  3732         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3734         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3735         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"autosave");
  3737         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3739         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3740         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"autosave_ival");
  3742         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3744         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3745         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"offer_question_hints");
  3747         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3749         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3750         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"instant_feedback_specific");
  3751         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled());
  3752         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3754         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3755         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"instant_feedback_answer_fixation");
  3756         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled());
  3757         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3759         $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3760         $a_xml_writer->xmlElement(
"fieldlabel", null, 
"enable_processing_time");
  3761         $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getTestBehaviourSettings()->getProcessingTimeEnabled());
  3762         $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3764         foreach ($this->
getMarkSchema()->getMarkSteps() as $index => $mark) {
  3765             $a_xml_writer->xmlStartTag(
"qtimetadatafield");
  3766             $a_xml_writer->xmlElement(
"fieldlabel", null, 
"mark_step_$index");
  3767             $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
  3768                 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
  3769                 $mark->getShortName(),
  3770                 $mark->getOfficialName(),
  3771                 $mark->getMinimumLevel(),
  3774             $a_xml_writer->xmlEndTag(
"qtimetadatafield");
  3776         $a_xml_writer->xmlEndTag(
"qtimetadata");
  3779         $introduction = $page_id !== null
  3780             ? (
new ilTestPage($page_id))->getXMLContent()
  3783         $a_xml_writer->xmlStartTag(
"objectives");
  3785         $a_xml_writer->xmlEndTag(
"objectives");
  3789                 "solutionswitch" => 
"Yes"  3794         $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs, null);
  3798             $concluding_remarks = $page_id !== null
  3799                 ? (
new ilTestPage($page_id))->getXMLContent()
  3802             $a_xml_writer->xmlStartTag(
"presentation_material");
  3803             $a_xml_writer->xmlStartTag(
"flow_mat");
  3804             $this->
addQTIMaterial($a_xml_writer, $page_id, $concluding_remarks);
  3805             $a_xml_writer->xmlEndTag(
"flow_mat");
  3806             $a_xml_writer->xmlEndTag(
"presentation_material");
  3812         $a_xml_writer->xmlElement(
"section", $attrs, null);
  3813         $a_xml_writer->xmlEndTag(
"assessment");
  3814         $a_xml_writer->xmlEndTag(
"questestinterop");
  3816         $xml = $a_xml_writer->xmlDumpMem(
false);
  3822         return $date_time->setTimezone(
new DateTimeZone(
'UTC'))->format(
'\PY\Yn\Mj\D\TG\Hi\Ms\S');
  3827         if ($period === null) {
  3830         if (preg_match(
"/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $period, $matches)) {
  3833                     "%02d-%02d-%02d %02d:%02d:%02d",
  3853     public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog): void
  3855         $this->mob_ids = [];
  3858         $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Start Export Page Objects");
  3859         $this->bench->start(
"ContentObjectExport", 
"exportPageObjects");
  3861         $this->bench->stop(
"ContentObjectExport", 
"exportPageObjects");
  3862         $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Finished Export Page Objects");
  3865         $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Start Export Media Objects");
  3866         $this->bench->start(
"ContentObjectExport", 
"exportMediaObjects");
  3868         $this->bench->stop(
"ContentObjectExport", 
"exportMediaObjects");
  3869         $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Finished Export Media Objects");
  3872         $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Start Export File Items");
  3873         $this->bench->start(
"ContentObjectExport", 
"exportFileItems");
  3875         $this->bench->stop(
"ContentObjectExport", 
"exportFileItems");
  3876         $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Finished Export File Items");
  3886         if ($a_tag == 
"Identifier" && $a_param == 
"Entry") {
  3902         foreach ($this->questions as $question_id) {
  3903             $this->bench->start(
"ContentObjectExport", 
"exportPageObject");
  3904             $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Page Object " . $question_id);
  3907             $a_xml_writer->xmlStartTag(
"PageObject", $attrs);
  3911             $this->bench->start(
"ContentObjectExport", 
"exportPageObject_XML");
  3913             $page_object->buildDom();
  3914             $page_object->insertInstIntoIDs((
string) $inst);
  3915             $mob_ids = $page_object->collectMediaObjects(
false);
  3917             $xml = $page_object->getXMLFromDom(
false, 
false, 
false, 
"", 
true);
  3918             $xml = str_replace(
"&", 
"&", $xml);
  3919             $a_xml_writer->appendXML($xml);
  3920             $page_object->freeDom();
  3921             unset($page_object);
  3923             $this->bench->stop(
"ContentObjectExport", 
"exportPageObject_XML");
  3926             $this->bench->start(
"ContentObjectExport", 
"exportPageObject_CollectMedia");
  3928             foreach ($mob_ids as $mob_id) {
  3929                 $this->mob_ids[$mob_id] = $mob_id;
  3931             $this->bench->stop(
"ContentObjectExport", 
"exportPageObject_CollectMedia");
  3934             $this->bench->start(
"ContentObjectExport", 
"exportPageObject_CollectFileItems");
  3936             foreach ($file_ids as $file_id) {
  3937                 $this->file_ids[$file_id] = $file_id;
  3939             $this->bench->stop(
"ContentObjectExport", 
"exportPageObject_CollectFileItems");
  3941             $a_xml_writer->xmlEndTag(
"PageObject");
  3944             $this->bench->stop(
"ContentObjectExport", 
"exportPageObject");
  3953         foreach ($this->mob_ids as $mob_id) {
  3954             $expLog->write(date(
"[y-m-d H:i:s] ") . 
"Media Object " . $mob_id);
  3956                 $target_dir = $a_target_dir . DIRECTORY_SEPARATOR . 
'objects'  3957                     . DIRECTORY_SEPARATOR . 
'il_' . 
IL_INST_ID . 
'_mob_' . $mob_id;
  3960                 $media_obj->exportXML($a_xml_writer, (
int) $a_inst);
  3961                 foreach ($media_obj->getMediaItems() as $item) {
  3962                     $stream = $item->getLocationStream();
  3963                     file_put_contents($target_dir . DIRECTORY_SEPARATOR . $item->getLocation(), $stream);
  3977         foreach ($this->file_ids as $file_id) {
  3978             $expLog->write(date(
"[y-m-d H:i:s] ") . 
"File Item " . $file_id);
  3979             $file_dir = $target_dir . 
'/objects/il_' . 
IL_INST_ID . 
'_file_' . $file_id;
  3981             $file_obj = 
new ilObjFile((
int) $file_id, 
false);
  3982             $source_file = $file_obj->getFile($file_obj->getVersion());
  3983             if (!is_file($source_file)) {
  3984                 $source_file = $file_obj->getFile();
  3986             if (is_file($source_file)) {
  3987                 copy($source_file, $file_dir . 
'/' . $file_obj->getFileName());
  4006         $this->
saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
  4019         $results_summary_settings = $this->
getScoreSettings()->getResultSummarySettings();
  4021             || $results_summary_settings->getScoreReporting()->isReportingEnabled() === 
false) {
  4025         if ($results_summary_settings->getScoreReporting() === ScoreReportingTypes::SCORE_REPORTING_DATE) {
  4026             return $results_summary_settings->getReportingDate()
  4044         $path_to_lifecycle = $this->lo_metadata->paths()->custom()->withNextStep(
'lifeCycle')->get();
  4045         $path_to_authors = $this->lo_metadata->paths()->authors();
  4047         $reader = $this->lo_metadata->read($this->
getId(), 0, $this->
getType(), $path_to_lifecycle);
  4048         if (!is_null($reader->allData($path_to_lifecycle)->current())) {
  4052         if ($author === 
'') {
  4053             $author = $this->
user->getFullname();
  4055         $this->lo_metadata->manipulate($this->
getId(), 0, $this->
getType())
  4056                           ->prepareCreateOrUpdate($path_to_authors, $author)
  4077         $path_to_authors = $this->lo_metadata->paths()->authors();
  4078         $author_data = $this->lo_metadata->read($this->
getId(), 0, $this->
getType(), $path_to_authors)
  4079                                          ->allData($path_to_authors);
  4081         return $this->lo_metadata->dataHelper()->makePresentableAsList(
', ', ...$author_data);
  4095         $lo_metadata = $DIC->learningObjectMetadata();
  4097         $path_to_authors = $lo_metadata->paths()->authors();
  4098         $author_data = $lo_metadata->read($obj_id, 0, 
"tst", $path_to_authors)
  4099                                     ->allData($path_to_authors);
  4101         return $lo_metadata->dataHelper()->makePresentableAsList(
',', ...$author_data);
  4113         $ilUser = $DIC[
'ilUser'];
  4116         $tests = array_slice(
  4124         if (count($tests)) {
  4127                 if ($use_object_id) {
  4129                     $result_array[$obj_id] = $titles[
$ref_id];
  4135         return $result_array;
  4150         $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
  4151         $new_obj->setTmpCopyWizardCopyId($copy_id);
  4154         $new_obj->saveToDb();
  4155         $new_obj->addToNewsOnOnline(
false, $new_obj->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
  4158                 ->withIntroductionSettings(
  4159                     $this->
getMainSettings()->getIntroductionSettings()->withIntroductionPageId(
  4161                     )->withTestId($new_obj->getTestId())
  4162                 )->withFinishingSettings(
  4163                     $this->
getMainSettings()->getFinishingSettings()->withConcludingRemarksPageId(
  4165                     )->withTestId($new_obj->getTestId())
  4171         $this->marks_repository->storeMarkSchema(
  4184             $templateRepository,
  4188         $cloneAction->cloneCertificate($this, $new_obj);
  4190         $this->question_set_config_factory->getQuestionSetConfig()->cloneQuestionSetRelatedData($new_obj);
  4191         $new_obj->saveQuestionsToDb();
  4194         $skillLevelThresholdList->setTestId($this->
getTestId());
  4195         $skillLevelThresholdList->loadFromDb();
  4196         $skillLevelThresholdList->cloneListForTest($new_obj->getTestId());
  4199         $obj_settings->cloneSettings($new_obj->getId());
  4201         if ($new_obj->getTestLogger()->isLoggingEnabled()) {
  4202             $new_obj->getTestLogger()->logTestAdministrationInteraction(
  4203                 $new_obj->getTestLogger()->getInteractionFactory()->buildTestAdministrationInteraction(
  4204                     $new_obj->getRefId(),
  4205                     $this->
user->getId(),
  4206                     TestAdministrationInteractionTypes::NEW_TEST_CREATED,
  4225                 $this->component_repository,
  4227                 $this->questionrepository
  4230             $questionSetConfig->loadFromDb();
  4232             if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
  4239                 $sourcePoolDefinitionList->loadDefinitions();
  4241                 if (is_int($sourcePoolDefinitionList->getQuestionAmount())) {
  4242                     $num = $sourcePoolDefinitionList->getQuestionAmount();
  4244             } elseif (is_int($questionSetConfig->getQuestionAmountPerTest())) {
  4245                 $num = $questionSetConfig->getQuestionAmountPerTest();
  4249             $num = count($this->questions);
  4260         return count($this->questions);
  4273         $ilDB = $DIC[
'ilDB'];
  4275         $result = 
$ilDB->queryF(
  4276             "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
  4280         if ($result->numRows()) {
  4281             $row = 
$ilDB->fetchAssoc($result);
  4282             $object_id = $row[
"obj_fi"];
  4297         $ilDB = $DIC[
'ilDB'];
  4299         $result = 
$ilDB->queryF(
  4300             "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",
  4304         if ($result->numRows()) {
  4305             $row = 
$ilDB->fetchAssoc($result);
  4306             $object_id = $row[
"obj_fi"];
  4321         $ilDB = $DIC[
'ilDB'];
  4323         $result = 
$ilDB->queryF(
  4324             "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
  4328         if ($result->numRows()) {
  4329             $row = 
$ilDB->fetchAssoc($result);
  4330             $test_id = $row[
"test_id"];
  4345         if (($active_id) && ($question_id)) {
  4346             if ($pass === null) {
  4349             if ($pass === null) {
  4352             $query = $this->db->queryF(
  4353                 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
  4354                 [
'integer', 
'integer', 
'integer'],
  4355                 [$active_id, $question_id, $pass]
  4357             $result = $this->db->fetchAll($query);
  4358             if (count($result) == 1) {
  4359                 return $result[0][
"value1"];
  4376             $result = $this->db->queryF(
  4377                 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
  4381             if ($result->numRows() == 1) {
  4382                 $row = $this->db->fetchAssoc($result);
  4383                 $res = $row[
"question_text"];
  4394         return $participant_list;
  4409                 $result = $this->db->queryF(
  4410                     "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
  4411                     "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 " .
  4412                     "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
  4413                     "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
  4415                     [
'text', 
'text', 
'text', 
'integer', 
'integer'],
  4419                 $result = $this->db->queryF(
  4420                     "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
  4421                     "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 " .
  4422                     "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
  4423                     "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
  4425                     [
'text', 
'text', 
'text', 
'integer'],
  4426                     [
'', $this->
lng->txt(
'anonymous'), 
'', $this->
getTestId()]
  4431                 $result = $this->db->queryF(
  4432                     "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
  4433                     "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 " .
  4434                     "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
  4435                     "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
  4437                     [
'integer', 
'integer'],
  4441                 $result = $this->db->queryF(
  4442                     "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
  4443                     "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 " .
  4444                     "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
  4445                     "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
  4453         while ($row = $this->db->fetchAssoc($result)) {
  4454             $result_array[$row[
'usr_id']] = $row;
  4456         return $result_array;
  4463                                 SELECT  tst_active.active_id,  4465                                                 tst_active.user_fi usr_id,  4469                                                 tst_active.submitted test_finished,  4470                                                 usr_data.matriculation,  4472                                                 tst_active.lastindex,  4473                                                 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes  4476                                 ON tst_active.user_fi = usr_data.usr_id  4477                                 WHERE tst_active.test_fi = %s  4478                                 ORDER BY usr_data.lastname  4480             $result = $this->db->queryF(
  4482                 [
'text', 
'text', 
'text', 
'integer'],
  4483                 [
'', $this->
lng->txt(
"anonymous"), 
"", $this->
getTestId()]
  4487                                 SELECT  tst_active.active_id,  4489                                                 tst_active.user_fi usr_id,  4493                                                 tst_active.submitted test_finished,  4494                                                 usr_data.matriculation,  4496                                                 tst_active.lastindex,  4497                                                 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes  4500                                 ON tst_active.user_fi = usr_data.usr_id  4501                                 WHERE tst_active.test_fi = %s  4502                                 ORDER BY usr_data.lastname  4504             $result = $this->db->queryF(
  4511         while ($row = $this->db->fetchAssoc($result)) {
  4512             $data[$row[
'active_id']] = $row;
  4514         foreach (
$data as $index => $participant) {
  4515             if (strlen(trim($participant[
"firstname"] . $participant[
"lastname"])) == 0) {
  4516                 $data[$index][
"lastname"] = $this->
lng->txt(
"deleted_user");
  4528         $filtered_participants = [];
  4530             if ($participant[
'tries'] > 0) {
  4533                         if ($this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
  4534                             $filtered_participants[$active_id] = $participant;
  4538                         if (!$this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
  4539                             $filtered_participants[$active_id] = $participant;
  4543                         $filtered_participants[$active_id] = $participant;
  4547         return $filtered_participants;
  4558         if (!is_array($ids) || count($ids) == 0) {
  4563             $result = $this->db->queryF(
  4564                 "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",
  4565                 [
'text', 
'text', 
'text'],
  4566                 [
"", $this->
lng->txt(
"anonymous"), 
""]
  4569             $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");
  4573         while ($row = $this->db->fetchAssoc($result)) {
  4574             $result_array[$row[
"usr_id"]] = $row;
  4576         return $result_array;
  4581         if (!is_array($ids) || count($ids) == 0) {
  4594         if (!is_array($ids) || count($ids) == 0) {
  4598         foreach ($ids as $obj_id) {
  4612         $this->db->manipulateF(
  4613             "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
  4614             [
'integer', 
'integer'],
  4617         $this->db->manipulateF(
  4618             "INSERT INTO tst_invited_user (test_fi, user_fi, ip_range_from, ip_range_to, tstamp) VALUES (%s, %s, %s, %s, %s)",
  4619             [
'integer', 
'integer', 
'text', 
'text', 
'integer'],
  4620             [$this->
getTestId(), 
$user_id, (strlen($client_ip)) ? $client_ip : null, (strlen($client_ip)) ? $client_ip : null,time()]
  4632         $ilDB = $DIC[
'ilDB'];
  4633         if (is_numeric($question_fi)) {
  4634             $result = 
$ilDB->queryF(
  4635                 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
  4636                 [
'integer', 
'integer'],
  4637                 [$active_id, $question_fi]
  4640             $result = 
$ilDB->queryF(
  4641                 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
  4647         while ($row = 
$ilDB->fetchAssoc($result)) {
  4648             $result_array[$row[
"question_fi"]] = $row;
  4650         return $result_array;
  4660         $this->db->manipulateF(
  4661             "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
  4662             [
'integer', 
'integer'],
  4663             [$active_id, $question_id]
  4665         $this->db->manipulateF(
  4666             "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
  4667             [
'integer', 
'integer', 
'integer'],
  4668             [$value, $question_id, $active_id]
  4677         $result = $this->db->queryF(
  4678             "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
  4679             [
'integer', 
'integer'],
  4682         return $result->numRows() == 1;
  4694         $result = $this->db->queryF(
  4695             "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
  4696             [
'integer', 
'integer', 
'integer'],
  4699         return $result->numRows() == 1;
  4733             "user_id" => $this->
lng->txt(
"user_id"),
  4734             "matriculation" => $this->
lng->txt(
"matriculation"),
  4735             "lastname" => $this->
lng->txt(
"lastname"),
  4736             "firstname" => $this->
lng->txt(
"firstname"),
  4737             "login" => $this->
lng->txt(
"login"),
  4738             "reached_points" => $this->
lng->txt(
"tst_reached_points"),
  4739             "max_points" => $this->
lng->txt(
"tst_maximum_points"),
  4740             "percent_value" => $this->
lng->txt(
"tst_percent_solved"),
  4741             "mark" => $this->
lng->txt(
"tst_mark"),
  4742             "passed" => $this->
lng->txt(
"tst_mark_passed"),
  4745         if (count($participants)) {
  4746             foreach ($participants as $active_id => $user_rec) {
  4749                 $reached_points = 0;
  4753                 if (!is_int($pass)) {
  4756                 foreach ($this->questions as $value) {
  4758                     if (is_object($question)) {
  4759                         $max_points += $question->getMaximumPoints();
  4760                         $reached_points += $question->getReachedPoints($active_id, $pass);
  4763                 if ($max_points > 0) {
  4764                     $percentvalue = $reached_points / $max_points;
  4765                     if ($percentvalue < 0) {
  4766                         $percentvalue = 0.0;
  4771                 $mark_obj = $this->
getMarkSchema()->getMatchingMark($percentvalue * 100);
  4773                 if ($mark_obj !== null) {
  4774                     $mark = $mark_obj->getOfficialName();
  4777                     $user_rec[
'firstname'] = 
"";
  4778                     $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
  4781                     "user_id" => $user_rec[
'usr_id'],
  4782                     "matriculation" => $user_rec[
'matriculation'],
  4783                     "lastname" => $user_rec[
'lastname'],
  4784                     "firstname" => $user_rec[
'firstname'],
  4785                     "login" => $user_rec[
'login'],
  4786                     "reached_points" => $reached_points,
  4787                     "max_points" => $max_points,
  4788                     "percent_value" => $percentvalue,
  4790                     "passed" => $user_rec[
'passed'] ? 
'1' : 
'0',
  4808         $ilDB = $DIC[
'ilDB'];
  4809         $result = 
$ilDB->queryF(
  4810             "SELECT tries FROM tst_active WHERE active_id = %s",
  4814         if ($result->numRows()) {
  4815             $row = 
$ilDB->fetchAssoc($result);
  4816             return $row[
"tries"];
  4834         $ilDB = $DIC[
'ilDB'];
  4835         $result = 
$ilDB->queryF(
  4836             "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
  4841         if ($result->numRows()) {
  4842             $row = 
$ilDB->fetchAssoc($result);
  4843             return $row[
"maxpass"];
  4857         $ilDB = $DIC[
'ilDB'];
  4859         $result = 
$ilDB->queryF(
  4860             "SELECT * FROM tst_pass_result WHERE active_fi = %s",
  4865         if (!$result->numRows()) {
  4871         while ($row = 
$ilDB->fetchAssoc($result)) {
  4872             if ($row[
"maxpoints"] > 0.0) {
  4873                 $factor = (float) ($row[
"points"] / $row[
"maxpoints"]);
  4877             if ($factor === 0.0 && $bestfactor === 0.0
  4878                 || $factor > $bestfactor) {
  4880                 $bestfactor = $factor;
  4884         if (is_array($bestrow)) {
  4885             return $bestrow[
"pass"];
  4901         $counted_pass = null;
  4907         return $counted_pass;
  4925         foreach ($this->questions as $value) {
  4926             if ($this->questionrepository->lookupResultRecordExist($active_id, $value, $pass)) {
  4927                 $workedthrough += 1;
  4930         return $workedthrough;
  4942         $ilDB = $DIC[
'ilDB'];
  4944         if (is_null($pass)) {
  4949                         SELECT  tst_pass_result.tstamp pass_res_tstamp,  4950                                         tst_test_result.tstamp quest_res_tstamp  4952                         FROM tst_pass_result  4954                         LEFT JOIN tst_test_result  4955                         ON tst_test_result.active_fi = tst_pass_result.active_fi  4956                         AND tst_test_result.pass = tst_pass_result.pass  4958                         WHERE tst_pass_result.active_fi = %s  4959                         AND tst_pass_result.pass = %s  4961                         ORDER BY tst_test_result.tstamp DESC  4964         $result = 
$ilDB->queryF(
  4966             [
'integer', 
'integer'],
  4970         while ($row = 
$ilDB->fetchAssoc($result)) {
  4971             if ($row[
'quest_res_tstamp']) {
  4972                 return $row[
'quest_res_tstamp'];
  4975             return $row[
'pass_res_tstamp'];
  4992             "executable" => 
true,
  4993             "errormessage" => 
""  4997             $result[
"executable"] = 
false;
  4998             $result[
"errormessage"] = $this->
lng->txt(
'autosave_failed') . 
': ' . $this->
lng->txt(
'offline');
  5003             $result[
"executable"] = 
false;
  5008             $result[
"executable"] = 
false;
  5019             $result[
"executable"] = 
false;
  5020             $result[
"errormessage"] = $this->
lng->txt(
"detail_max_processing_time_reached");
  5025         $testPassesSelector->setActiveId($active_id);
  5026         $testPassesSelector->setLastFinishedPass($test_session->getLastFinishedPass());
  5029             $closedPasses = $testPassesSelector->getClosedPasses();
  5032                 $result[
"executable"] = 
false;
  5033                 $result[
"errormessage"] = $this->
lng->txt(
"maximum_nr_of_tries_reached");
  5039                     $result[
'executable'] = 
false;
  5040                     $result[
'errormessage'] = $this->
lng->txt(
"tst_addit_passes_blocked_after_passed_msg");
  5046         $next_pass_allowed_timestamp = 0;
  5047         if (!$this->
isNextPassAllowed($testPassesSelector, $next_pass_allowed_timestamp)) {
  5050             $result[
'executable'] = 
false;
  5051             $result[
'errormessage'] = sprintf($this->
lng->txt(
'wait_for_next_pass_hint_msg'), $date);
  5059         $waiting_between_passes = $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaiting();
  5063             $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaitingEnabled()
  5064             && ($waiting_between_passes !== 
'')
  5066             && ($last_finished_pass_timestamp !== null)
  5068             $time_values = explode(
':', $waiting_between_passes);
  5069             $next_pass_allowed_timestamp = strtotime(
'+ ' . $time_values[0] . 
' Days + ' . $time_values[1] . 
' Hours' . $time_values[2] . 
' Minutes', $last_finished_pass_timestamp);
  5070             return (time() > $next_pass_allowed_timestamp);
  5080         $pass_selector->setActiveId($test_session->
getActiveId());
  5083         return $pass_selector->hasReportablePasses();
  5090         $pass_selector->setActiveId($test_session->
getActiveId());
  5093         return $pass_selector->hasExistingPasses();
  5105         if ($active_id < 1) {
  5108         if ($pass === null) {
  5111         $result = $this->db->queryF(
  5112             "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
  5113             [
'integer', 
'integer'],
  5116         if ($result->numRows()) {
  5117             $row = $this->db->fetchAssoc($result);
  5118             if (preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches)) {
  5149         if ($now > ($starting_time + $processing_time)) {
  5158         $tags_trafo = $this->
refinery->string()->stripTags();
  5162                                                 questtypes.type_tag,  5164                                                 origquest.obj_fi orig_obj_fi  5166                         FROM            qpl_questions questions  5168                         INNER JOIN      qpl_qst_type questtypes  5169                         ON                      questtypes.question_type_id = questions.question_type_fi  5171                         INNER JOIN      tst_test_question tstquest  5172                         ON                      tstquest.question_fi = questions.question_id  5174                         LEFT JOIN       qpl_questions origquest  5175                         ON                      origquest.question_id = questions.original_id  5177                         WHERE           tstquest.test_fi = %s  5179                         ORDER BY        tstquest.sequence  5182         $query_result = $this->db->queryF(
  5190         while ($row = $this->db->fetchAssoc($query_result)) {
  5191             $row[
'title'] = $tags_trafo->transform($row[
'title']);
  5192             $row[
'description'] = $tags_trafo->transform($row[
'description'] !== 
'' && $row[
'description'] !== null ? $row[
'description'] : 
' ');
  5193             $row[
'author'] = $tags_trafo->transform($row[
'author']);
  5195             $questions[] = $row;
  5204             if ($questionData[
'question_id'] != $question_id) {
  5216         $row = $this->db->fetchAssoc($this->db->queryF(
  5217             "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
  5218             [
'integer', 
'integer'],
  5219             [$question_id, $this->getId()]
  5222         return (
bool) $row[
'cnt'];
  5230             $points += $question_data[
'points'];
  5243                                                 questtypes.type_tag,  5244                                                 origquest.obj_fi orig_obj_fi  5246                         FROM            qpl_questions questions  5248                         INNER JOIN      qpl_qst_type questtypes  5249                         ON                      questtypes.question_type_id = questions.question_type_fi  5251                         INNER JOIN      tst_rnd_cpy tstquest  5252                         ON                      tstquest.qst_fi = questions.question_id  5254                         LEFT JOIN       qpl_questions origquest  5255                         ON                      origquest.question_id = questions.original_id  5257                         WHERE           tstquest.tst_fi = %s  5260         $query_result = $this->db->queryF(
  5266         return $this->db->fetchAll($query_result);
  5271         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getShuffleQuestions();
  5287         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewMode();
  5292         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionListEnabled();
  5297         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewEnabled();
  5302         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtBeginning();
  5307         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtEnd();
  5312         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShowDescriptionInQuestionList();
  5320         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowPassDetails();
  5328         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionPrintview();
  5343         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionFeedback();
  5351         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionAnswersOnly();
  5359         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSignature();
  5367         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSuggested();
  5376         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListComparison();
  5381         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListOwnAnswers();
  5390         $ilDB = $DIC[
'ilDB'];
  5391         $result = 
$ilDB->queryF(
  5392             "SELECT user_fi FROM tst_active WHERE active_id = %s",
  5396         if ($result->numRows()) {
  5397             $row = 
$ilDB->fetchAssoc($result);
  5398             return $row[
"user_fi"];
  5406         $result = $this->db->queryF(
  5407             "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
  5411         if ($result->numRows()) {
  5412             $row = $this->db->fetchAssoc($result);
  5413             return $row[
"finished"];
  5418     public static function lookupLastTestPassAccess(
int $active_id, 
int $pass_index): ?
int  5422         $ilDB = $DIC[
'ilDB'];
  5425             SELECT MAX(tst_times.tstamp) as last_pass_access  5427             WHERE active_fi = %s  5433             [
'integer', 
'integer'],
  5434             [$active_id, $pass_index]
  5437         while ($row = 
$ilDB->fetchAssoc(
$res)) {
  5438             return $row[
'last_pass_access'];
  5453         if (preg_match(
"/<[^>]*?>/", $a_text)) {
  5470         for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
  5471             $material = $a_material->getMaterial($i);
  5472             if ($material[
'type'] === 
'mattext') {
  5473                 $result .= $material[
'material']->getContent();
  5475             if ($material[
'type'] === 
'matimage') {
  5476                 $matimage = $material[
'material'];
  5477                 if (preg_match(
'/(il_([0-9]+)_mob_([0-9]+))/', $matimage->getLabel(), $matches)) {
  5479                         'mob' => $matimage->getLabel(),
  5480                         'uri' => $matimage->getUri()
  5486         $decoded_result = base64_decode($result);
  5487         if (str_starts_with($decoded_result, 
'<PageObject>')) {
  5488             $result = $decoded_result;
  5502             'texttype' => 
'text/plain'  5506         if ($page_id !== null) {
  5507             $attrs[
'texttype'] = 
'text/xml';
  5510             $page_object->buildDom();
  5511             $page_object->insertInstIntoIDs((
string) 
IL_INST_ID);
  5512             $material = base64_encode($page_object->getXMLFromDom());
  5514             foreach ($file_ids as $file_id) {
  5515                 $this->file_ids[] = (
int) $file_id;
  5517             $mob_string = 
'il_' . IL_INST_ID . 
'_mob_';
  5518         } elseif ($this->
isHTML($material)) {
  5519             $attrs[
'texttype'] = 
'text/xhtml';
  5521             $mob_string = 
'mm_';
  5524         $xml_writer->
xmlElement(
'mattext', $attrs, $material);
  5525         foreach ($mobs as $mob) {
  5526             $mob_id_string = (string) $mob;
  5527             $moblabel = 
'il_' . 
IL_INST_ID . 
'_mob_' . $mob_id_string;
  5528             if (strpos($material, $mob_string . $mob_id_string) !== 
false) {
  5532                         'label' => $moblabel,
  5533                         'uri' => 
'objects/' . 
'il_' . 
IL_INST_ID . 
'_mob_' . $mob_id_string . 
'/' . $mob_obj->getTitle()
  5536                 $xml_writer->
xmlElement(
'matimage', $imgattrs, null);
  5550         if ($txt_output == null) {
  5555             $prepare_for_latex_output,
  5556             $omitNl2BrWhenTextArea
  5562         return $this->
getMainSettings()->getGeneralSettings()->getAnonymity();
  5569         $ilDB = $DIC[
'ilDB'];
  5571         $result = 
$ilDB->queryF(
  5572             "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
  5576         while ($row = 
$ilDB->fetchAssoc($result)) {
  5577             return (
int) $row[
'anonymity'];
  5584         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getSuspendTestAllowed();
  5589         return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionMarkingEnabled();
  5594         return $this->
getMainSettings()->getAccessSettings()->getFixedParticipants();
  5600                         SELECT          tst_tests.question_set_type  5602                         INNER JOIN      tst_tests  5603                         ON                      tst_active.test_fi = tst_tests.test_id  5604                         WHERE           tst_active.active_id = %s  5607         $res = $this->db->queryF($query, [
'integer'], [$active_id]);
  5609         while ($row = $this->db->fetchAssoc(
$res)) {
  5610             return $row[
'question_set_type'];
  5629             return $this->
lng->txt(
"anonymous") . $suffix;
  5632             if (strlen($uname[
"firstname"] . $uname[
"lastname"]) == 0) {
  5633                 $uname[
"firstname"] = $this->
lng->txt(
"deleted_user");
  5635             if ($sorted_order) {
  5636                 return trim($uname[
"lastname"] . 
", " . $uname[
"firstname"]) . $suffix;
  5638                 return trim($uname[
"firstname"] . 
" " . $uname[
"lastname"]) . $suffix;
  5650         $result = $this->db->queryF(
  5651             "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
  5653             [$this->
user->getId()]
  5656         while ($row = $this->db->fetchAssoc($result)) {
  5657             $defaults[$row[
"test_defaults_id"]] = $row;
  5664         $result = $this->db->queryF(
  5665             "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
  5669         if ($result->numRows() == 1) {
  5670             $row = $this->db->fetchAssoc($result);
  5679         $this->db->manipulateF(
  5680             "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
  5748             'mailnotification' => $main_settings->
getFinishingSettings()->getMailNotificationContentType(),
  5782             fn(
Mark $v): array => [
  5791         $next_id = $this->db->nextId(
'tst_test_defaults');
  5793             'tst_test_defaults',
  5795                 'test_defaults_id' => [
'integer', $next_id],
  5796                 'name' => [
'text', $a_name],
  5797                 'user_fi' => [
'integer', $this->
user->getId()],
  5798                 'defaults' => [
'clob', serialize($testsettings)],
  5799                 'marks' => [
'clob', json_encode($marks)],
  5800                 'tstamp' => [
'integer', time()]
  5807         $testsettings = unserialize($test_defaults[
'defaults'], [
'allowed_classes' => [DateTimeImmutable::class]]);
  5808         $activation_starting_time = is_numeric($testsettings[
'activation_starting_time'] ?? 
false)
  5809             ? (
int) $testsettings[
'activation_starting_time']
  5811         $activation_ending_time = is_numeric($testsettings[
'activation_ending_time'] ?? 
false)
  5812             ? (
int) $testsettings[
'activation_ending_time']
  5814         $unserialized_marks = json_decode($test_defaults[
'marks'], 
true);
  5817         if (is_array($unserialized_marks)
  5818             && is_array($unserialized_marks[0])) {
  5823                         $v[
'official_name'],
  5824                         $v[
'minimum_level'],
  5831             $info = 
'old_mark_default_not_applied';
  5836             (
bool) ($testsettings[
'is_activation_limited'] ?? 
false),
  5837             $activation_starting_time,
  5838             $activation_ending_time,
  5839             (
bool) ($testsettings[
'activation_visibility'] ?? 
false),
  5853         $main_settings = $main_settings
  5856                     ->withQuestionSetType(
  5857                         $testsettings[
'questionSetType'] ?? $general_settings->getQuestionSetType()
  5859                         (
bool) ($testsettings[
'Anonymity'] ?? $general_settings->getAnonymity())
  5861             )->withIntroductionSettings(
  5862                 $introduction_settings
  5863                     ->withIntroductionEnabled(
  5864                         (
bool) $testsettings[
'IntroEnabled'] ?? $introduction_settings->getIntroductionEnabled()
  5865                     )->withExamConditionsCheckboxEnabled(
  5866                         (
bool) ($testsettings[
'ExamConditionsCheckboxEnabled'] ?? $introduction_settings->getExamConditionsCheckboxEnabled())
  5868             )->withAccessSettings(
  5870                     ->withStartTimeEnabled(
  5871                         (
bool) ($testsettings[
'StartingTimeEnabled'] ?? $access_settings->getStartTimeEnabled())
  5874                             $testsettings[
'StartingTime'] ?? $access_settings->getStartTime()
  5876                     )->withEndTimeEnabled(
  5877                         (
bool) $testsettings[
'EndingTimeEnabled'] ?? $access_settings->getEndTimeEnabled()
  5880                             $testsettings[
'EndingTime'] ?? $access_settings->getEndTime()
  5882                     )->withPasswordEnabled(
  5883                         (
bool) ($testsettings[
'password_enabled'] ?? $access_settings->getPasswordEnabled())
  5885                         $testsettings[
'password'] ?? $access_settings->getPassword()
  5886                     )->withFixedParticipants(
  5887                         (
bool) ($testsettings[
'fixed_participants'] ?? $access_settings->getFixedParticipants())
  5889             )->withTestBehaviourSettings(
  5890                 $test_behavior_settings
  5891                     ->withNumberOfTries(
  5892                         (
int) ($testsettings[
'NrOfTries'] ?? $test_behavior_settings->getNumberOfTries())
  5893                     )->withBlockAfterPassedEnabled(
  5894                         (
bool) ($testsettings[
'BlockAfterPassed'] ?? $test_behavior_settings->getBlockAfterPassedEnabled())
  5896                         $testsettings[
'pass_waiting'] ?? $test_behavior_settings->getPassWaiting()
  5898                         $testsettings[
'Kiosk'] ?? $test_behavior_settings->getKioskMode()
  5899                     )->withProcessingTimeEnabled(
  5900                         (
bool) ($testsettings[
'EnableProcessingTime'] ?? $test_behavior_settings->getProcessingTimeEnabled())
  5901                     )->withProcessingTime(
  5902                         $testsettings[
'ProcessingTime'] ?? $test_behavior_settings->getProcessingTime()
  5903                     )->withResetProcessingTime(
  5904                         (
bool) ($testsettings[
'ResetProcessingTime'] ?? $test_behavior_settings->getResetProcessingTime())
  5905                     )->withExamIdInTestAttemptEnabled(
  5906                         (
bool) ($testsettings[
'examid_in_test_pass'] ?? $test_behavior_settings->getExamIdInTestAttemptEnabled())
  5908             )->withQuestionBehaviourSettings(
  5909                 $question_behavior_settings
  5910                     ->withQuestionTitleOutputMode(
  5911                         $testsettings[
'TitleOutput'] ?? $question_behavior_settings->getQuestionTitleOutputMode()
  5912                     )->withAutosaveEnabled(
  5913                         (
bool) ($testsettings[
'autosave'] ?? $question_behavior_settings->getAutosaveEnabled())
  5914                     )->withAutosaveInterval(
  5915                         $testsettings[
'autosave_ival'] ?? $question_behavior_settings->getAutosaveInterval()
  5916                     )->withShuffleQuestions(
  5917                         (
bool) ($testsettings[
'Shuffle'] ?? $question_behavior_settings->getShuffleQuestions())
  5918                     )->withQuestionHintsEnabled(
  5919                         (
bool) ($testsettings[
'offer_question_hints'] ?? $question_behavior_settings->getQuestionHintsEnabled())
  5920                     )->withInstantFeedbackPointsEnabled(
  5921                         (
bool) ($testsettings[
'AnswerFeedbackPoints'] ?? $question_behavior_settings->getInstantFeedbackPointsEnabled())
  5922                     )->withInstantFeedbackGenericEnabled(
  5923                         (
bool) ($testsettings[
'AnswerFeedback'] ?? $question_behavior_settings->getInstantFeedbackGenericEnabled())
  5924                     )->withInstantFeedbackSpecificEnabled(
  5925                         (
bool) ($testsettings[
'SpecificAnswerFeedback'] ?? $question_behavior_settings->getInstantFeedbackSpecificEnabled())
  5926                     )->withInstantFeedbackSolutionEnabled(
  5927                         (
bool) ($testsettings[
'InstantFeedbackSolution'] ?? $question_behavior_settings->getInstantFeedbackSolutionEnabled())
  5928                     )->withForceInstantFeedbackOnNextQuestion(
  5929                         (
bool) ($testsettings[
'force_inst_fb'] ?? $question_behavior_settings->getForceInstantFeedbackOnNextQuestion())
  5930                     )->withLockAnswerOnInstantFeedbackEnabled(
  5931                         (
bool) ($testsettings[
'inst_fb_answer_fixation'] ?? $question_behavior_settings->getLockAnswerOnInstantFeedbackEnabled())
  5932                     )->withLockAnswerOnNextQuestionEnabled(
  5933                         (
bool) ($testsettings[
'follow_qst_answer_fixation'] ?? $question_behavior_settings->getLockAnswerOnNextQuestionEnabled())
  5935             )->withParticipantFunctionalitySettings(
  5936                 $participant_functionality_settings
  5937                     ->withUsePreviousAnswerAllowed(
  5938                         (
bool) ($testsettings[
'use_previous_answers'] ?? $participant_functionality_settings->getUsePreviousAnswerAllowed())
  5939                     )->withSuspendTestAllowed(
  5940                         (
bool) ($testsettings[
'ShowCancel'] ?? $participant_functionality_settings->getSuspendTestAllowed())
  5941                     )->withPostponedQuestionsMoveToEnd(
  5942                         (
bool) ($testsettings[
'SequenceSettings'] ?? $participant_functionality_settings->getPostponedQuestionsMoveToEnd())
  5943                     )->withUsrPassOverviewMode(
  5944                         (
int) ($testsettings[
'ListOfQuestionsSettings'] ?? $participant_functionality_settings->getUsrPassOverviewMode())
  5945                     )->withQuestionMarkingEnabled(
  5946                         (
bool) ($testsettings[
'ShowMarker'] ?? $participant_functionality_settings->getQuestionMarkingEnabled())
  5948             )->withFinishingSettings(
  5950                     ->withShowAnswerOverview(
  5951                         (
bool) ($testsettings[
'enable_examview'] ?? $finishing_settings->getShowAnswerOverview())
  5952                     )->withConcludingRemarksEnabled(
  5953                         (
bool) ($testsettings[
'ShowFinalStatement'] ?? $finishing_settings->getConcludingRemarksEnabled())
  5954                     )->withRedirectionMode(
  5955                         (
int) ($testsettings[
'redirection_mode'] ?? $finishing_settings->getRedirectionMode())
  5956                     )->withRedirectionUrl(
  5957                         $testsettings[
'redirection_url'] ?? $finishing_settings->getRedirectionUrl()
  5958                     )->withMailNotificationContentType(
  5959                         (
int) ($testsettings[
'mailnotification'] ?? $finishing_settings->getMailNotificationContentType())
  5960                     )->withAlwaysSendMailNotification(
  5961                         (
bool) ($testsettings[
'mailnottype'] ?? $finishing_settings->getAlwaysSendMailNotification())
  5963             )->withAdditionalSettings(
  5964                 $additional_settings
  5965                     ->withSkillsServiceEnabled(
  5966                         (
bool) ($testsettings[
'skill_service'] ?? $additional_settings->getSkillsServiceEnabled())
  5968                         (
bool) ($testsettings[
'HideInfoTab'] ?? $additional_settings->getHideInfoTab())
  5974         $score_reporting = ScoreReportingTypes::SCORE_REPORTING_DISABLED;
  5975         if ($testsettings[
'ScoreReporting'] !== null) {
  5976             $score_reporting = ScoreReportingTypes::tryFrom($testsettings[
'ScoreReporting'])
  5977                 ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED;
  5980         $reporting_date = $testsettings[
'ReportingDate'];
  5981         if (is_string($reporting_date)) {
  5992         $score_settings = $score_settings
  5996                         $testsettings[
'PassScoring'] ?? $scoring_settings->getPassScoring()
  5997                     )->withScoreCutting(
  5998                         $testsettings[
'ScoreCutting'] ?? $scoring_settings->getScoreCutting()
  6000                         $testsettings[
'CountSystem'] ?? $scoring_settings->getCountSystem()
  6002             )->withResultSummarySettings(
  6003                 $result_summary_settings
  6004                     ->withPassDeletionAllowed(
  6005                         (
bool) ($testsettings[
'pass_deletion_allowed'] ?? $result_summary_settings->getPassDeletionAllowed())
  6006                     )->withShowGradingStatusEnabled(
  6007                         (
bool) ($testsettings[
'show_grading_status'] ?? $result_summary_settings->getShowGradingStatusEnabled())
  6008                     )->withShowGradingMarkEnabled(
  6009                         (
bool) ($testsettings[
'show_grading_mark'] ?? $result_summary_settings->getShowGradingMarkEnabled())
  6010                     )->withScoreReporting(
  6012                     )->withReportingDate(
  6015             )->withResultDetailsSettings(
  6016                 $result_details_settings
  6017                     ->withResultsPresentation(
  6018                         (
int) ($testsettings[
'ResultsPresentation'] ?? $result_details_settings->getResultsPresentation())
  6019                     )->withShowSolutionListComparison(
  6020                         (
bool) ($testsettings[
'show_solution_list_comparison'] ?? $result_details_settings->getShowSolutionListComparison())
  6021                     )->withShowExamIdInTestResults(
  6022                         (
bool) ($testsettings[
'examid_in_test_res'] ?? $result_details_settings->getShowExamIdInTestResults())
  6024             )->withGamificationSettings(
  6025                 $gamification_settings
  6026                     ->withHighscoreEnabled(
  6027                         (
bool) ($testsettings[
'highscore_enabled'] ?? $gamification_settings->getHighscoreEnabled())
  6028                     )->withHighscoreAnon(
  6029                         (
bool) ($testsettings[
'highscore_anon'] ?? $gamification_settings->getHighscoreAnon())
  6030                     )->withHighscoreAchievedTS(
  6031                         $testsettings[
'highscore_achieved_ts'] ?? $gamification_settings->getHighscoreAchievedTS()
  6032                     )->withHighscoreScore(
  6033                         (
bool) ($testsettings[
'highscore_score'] ?? $gamification_settings->getHighscoreScore())
  6034                     )->withHighscorePercentage(
  6035                         $testsettings[
'highscore_percentage'] ?? $gamification_settings->getHighscorePercentage()
  6036                     )->withHighscoreHints(
  6037                         (
bool) ($testsettings[
'highscore_hints'] ?? $gamification_settings->getHighscoreHints())
  6038                     )->withHighscoreWTime(
  6039                         (
bool) ($testsettings[
'highscore_wtime'] ?? $gamification_settings->getHighscoreWTime())
  6040                     )->withHighscoreOwnTable(
  6041                         (
bool) ($testsettings[
'highscore_own_table'] ?? $gamification_settings->getHighscoreOwnTable())
  6042                     )->withHighscoreTopTable(
  6043                         (
bool) ($testsettings[
'highscore_top_table'] ?? $gamification_settings->getHighscoreTopTable())
  6044                     )->withHighscoreTopNum(
  6045                         $testsettings[
'highscore_top_num'] ?? $gamification_settings->getHighscoreTopNum()
  6062         return DateTimeImmutable::createFromFormat(
'U', (
string) $date_time);
  6074         if (extension_loaded(
"tidy")) {
  6077                 "output-xml" => 
true,
  6078                 "numeric-entities" => true
  6081             $tidy->parseString($print_output, $config, 
'utf8');
  6082             $tidy->cleanRepair();
  6083             $print_output = tidy_get_output($tidy);
  6084             $print_output = preg_replace(
"/^.*?(<html)/", 
"\\1", $print_output);
  6086             $print_output = str_replace(
" ", 
" ", $print_output);
  6087             $print_output = str_replace(
"⊗", 
"X", $print_output);
  6089         $xsl = file_get_contents(
"./components/ILIAS/Test/xml/question2fo.xsl");
  6094             'font-family="Helvetica, unifont"',
  6095             'font-family="' . $this->
settings->get(
'rpc_pdf_font', 
'Helvetica, unifont') . 
'"',
  6099         $args = [ 
'/_xml' => $print_output, 
'/_xsl' => $xsl ];
  6100         $xh = xslt_create();
  6102         $output = xslt_process($xh, 
"arg:/_xml", 
"arg:/_xsl", null, $args, 
$params);
  6116         $content = preg_replace(
"/href=\".*?\"/", 
"", $content);
  6117         $printbody = 
new ilTemplate(
"tpl.il_as_tst_print_body.html", 
true, 
true, 
"components/ILIAS/Test");
  6119         $printbody->setVariable(
"ADM_CONTENT", $content);
  6120         $printbody->setCurrentBlock(
"css_file");
  6122         $printbody->parseCurrentBlock();
  6123         $printoutput = $printbody->get();
  6124         $html = str_replace(
"href=\"./", 
"href=\"" . ILIAS_HTTP_PATH . 
"/", $printoutput);
  6125         $html = preg_replace(
"/<div id=\"dontprint\">.*?<\\/div>/ims", 
"", $html);
  6126         if (extension_loaded(
"tidy")) {
  6129                 "output-xml" => 
true,
  6130                 "numeric-entities" => true
  6133             $tidy->parseString($html, $config, 
'utf8');
  6134             $tidy->cleanRepair();
  6135             $html = tidy_get_output($tidy);
  6136             $html = preg_replace(
"/^.*?(<html)/", 
"\\1", $html);
  6138             $html = str_replace(
" ", 
" ", $html);
  6139             $html = str_replace(
"⊗", 
"X", $html);
  6141         $html = preg_replace(
"/src=\".\\//ims", 
"src=\"" . ILIAS_HTTP_PATH . 
"/", $html);
  6153         $fp = fopen($fo_file, 
"w");
  6162                 $pdf_base64->scalar,
  6168             $this->
logger->info(__METHOD__ . 
': ' . $e->getMessage());
  6184         if ($pass === null) {
  6188         $row = self::getSingleManualFeedback((
int) $active_id, (
int) $question_id, (
int) $pass);
  6191             $feedback = $row[
'feedback'] ?? 
'';
  6200         $ilDB = $DIC[
'ilDB'];
  6202         $result = 
$ilDB->queryF(
  6203             "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
  6204             [
'integer', 
'integer', 
'integer'],
  6205             [$active_id, $question_id, $pass]
  6208         if (
$ilDB->numRows($result) === 1) {
  6209             $row = 
$ilDB->fetchAssoc($result);
  6211         } elseif (
$ilDB->numRows($result) > 1) {
  6212             $DIC->logger()->root()->warning(
  6213                 "WARNING: Multiple feedback entries on tst_manual_fb for " .
  6214                 "active_fi = $active_id , question_fi = $question_id and pass = $pass"  6231         $ilDB = $DIC[
'ilDB'];
  6234         $result = 
$ilDB->queryF(
  6235             "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
  6240         while ($row = 
$ilDB->fetchAssoc($result)) {
  6241             $active = $row[
'active_fi'];
  6242             $pass = $row[
'pass'];
  6243             $question = $row[
'question_fi'];
  6247             $feedback[$active][$pass][$question] = $row;
  6258         bool $finalized = 
false  6260         $feedback_old = self::getSingleManualFeedback($active_id, $question_id, $pass);
  6261         $this->db->manipulateF(
  6262             'DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s',
  6263             [
'integer', 
'integer', 
'integer'],
  6264             [$active_id, $question_id, $pass]
  6267         $this->
insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
  6279         $next_id = $this->db->nextId(
'tst_manual_fb');
  6281         $finalized_time = time();
  6284             'manual_feedback_id' => [ 
'integer', $next_id],
  6285             'active_fi' => [ 
'integer', $active_id],
  6286             'question_fi' => [ 
'integer', $question_id],
  6287             'pass' => [ 
'integer', $pass],
  6289             'tstamp' => [ 
'integer', time()]
  6292         if ($feedback_old !== [] && (
int) $feedback_old[
'finalized_evaluation'] === 1) {
  6293             $user = $feedback_old[
'finalized_by_usr_id'];
  6294             $finalized_time = $feedback_old[
'finalized_tstamp'];
  6297         if ($finalized === 
false) {
  6298             $update_default[
'finalized_evaluation'] = [
'integer', 0];
  6299             $update_default[
'finalized_by_usr_id'] = [
'integer', 0];
  6300             $update_default[
'finalized_tstamp'] = [
'integer', 0];
  6301         } elseif ($finalized === 
true) {
  6302             $update_default[
'finalized_evaluation'] = [
'integer', 1];
  6303             $update_default[
'finalized_by_usr_id'] = [
'integer', 
$user];
  6304             $update_default[
'finalized_tstamp'] = [
'integer', $finalized_time];
  6307         $this->db->insert(
'tst_manual_fb', $update_default);
  6309         if ($this->
logger->isLoggingEnabled()) {
  6310             $this->
logger->logScoringInteraction(
  6311                 $this->
logger->getInteractionFactory()->buildScoringInteraction(
  6314                     $this->
user->getId(),
  6315                     self::_getUserIdFromActiveId($active_id),
  6316                     TestScoringInteractionTypes::QUESTION_GRADED,
  6318                         AdditionalInformationGenerator::KEY_EVAL_FINALIZED => $this->
logger  6319                             ->getAdditionalInformationGenerator()->getTrueFalseTagForBool($finalized),
  6351         $this->test_id = $a_id;
  6364         if (count($participants)) {
  6365             foreach ($participants as $active_id => $user_rec) {
  6367                 $reached_points = 0;
  6370                 foreach ($this->questions as $value) {
  6372                     if (is_object($question)) {
  6373                         $max_points += $question->getMaximumPoints();
  6374                         $reached_points += $question->getReachedPoints($active_id, $pass);
  6375                         if ($max_points > 0) {
  6376                             $percentvalue = $reached_points / $max_points;
  6377                             if ($percentvalue < 0) {
  6378                                 $percentvalue = 0.0;
  6384                             $user_rec[
'firstname'] = 
"";
  6385                             $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
  6388                             "user_id" => $user_rec[
'usr_id'],
  6389                             "matriculation" => $user_rec[
'matriculation'],
  6390                             "lastname" => $user_rec[
'lastname'],
  6391                             "firstname" => $user_rec[
'firstname'],
  6392                             "login" => $user_rec[
'login'],
  6393                             "question_id" => $question->getId(),
  6394                             "question_title" => $question->getTitle(),
  6395                             "reached_points" => $reached_points,
  6396                             "max_points" => $max_points,
  6397                             "passed" => $user_rec[
'passed'] ? 
'1' : 
'0',
  6412         $ilDB = $DIC[
'ilDB'];
  6414         $result = 
$ilDB->queryF(
  6415             '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',
  6419         $rec = 
$ilDB->fetchAssoc($result);
  6420         return $rec[
'obj_id'] ?? null;
  6431         if (!$this->component_repository->getComponentByTypeAndName(
  6434         )->getPluginSlotById(
'qst')->hasPluginName($a_pname)) {
  6438         return $this->component_repository
  6439             ->getComponentByTypeAndName(
  6443             ->getPluginSlotById(
  6453         $result = $this->db->queryF(
  6454             "SELECT passed FROM tst_result_cache WHERE active_fi = %s",
  6458         if ($result->numRows()) {
  6459             $row = $this->db->fetchAssoc($result);
  6460             return $row[
'passed'];
  6463             $result_array = &$this->
getTestResult($active_id, $counted_pass);
  6464             return $result_array[
"test"][
"passed"];
  6474                         SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass  6475                         FROM tst_test_result  6476                         INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s  6477                         INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi  6478                         LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi  6479                         WHERE tst_test_result.question_fi = %s  6480                         ORDER BY usr_data.lastname ASC, usr_data.firstname ASC  6483         $result = $this->db->queryF(
  6485             [
'integer', 
'integer'],
  6486             [$test_id, $question_id]
  6490         while ($row = $this->db->fetchAssoc($result)) {
  6495             if (!array_key_exists($row[
"active_fi"], $foundusers)) {
  6496                 $foundusers[$row[
"active_fi"]] = [];
  6498             array_push($foundusers[$row[
"active_fi"]], [
"pass" => $row[
"pass"], 
"qid" => $row[
"question_fi"]]);
  6506         $found_participants = 
$data->getParticipants();
  6507         $results = [
'overview' => [], 
'questions' => []];
  6508         if ($found_participants !== []) {
  6509             $results[
'overview'][
'tst_stat_result_mark_median'] = 
$data->getStatistics()->getEvaluationDataOfMedianUser()?->getMark()?->getShortName() ?? 
'';
  6510             $results[
'overview'][
'tst_stat_result_rank_median'] = 
$data->getStatistics()->rankMedian();
  6511             $results[
'overview'][
'tst_stat_result_total_participants'] = 
$data->getStatistics()->count();
  6512             $results[
'overview'][
'tst_stat_result_median'] = 
$data->getStatistics()->median();
  6513             $results[
'overview'][
'tst_eval_total_persons'] = count($found_participants);
  6514             $total_finished = 
$data->getTotalFinishedParticipants();
  6515             $results[
'overview'][
'tst_eval_total_finished'] = $total_finished;
  6516             $results[
'overview'][
'tst_eval_total_finished_average_time'] =
  6521             $total_passed_reached = 0;
  6522             $total_passed_max = 0;
  6523             $total_passed_time = 0;
  6524             foreach ($found_participants as $userdata) {
  6525                 if ($userdata->getMark()?->getPassed()) {
  6527                     $total_passed_reached += $userdata->getReached();
  6528                     $total_passed_max += $userdata->getMaxpoints();
  6529                     $total_passed_time += $userdata->getTimeOnTask();
  6532             $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
  6533             $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
  6534             $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
  6535             $results[
'overview'][
'tst_eval_total_passed'] = $total_passed;
  6536             $results[
'overview'][
'tst_eval_total_passed_average_points'] = sprintf(
'%2.2f', $average_passed_reached)
  6537                 . 
' ' . strtolower(
'of') . 
' ' . sprintf(
'%2.2f', $average_passed_max);
  6538             $results[
'overview'][
'tst_eval_total_passed_average_time'] =
  6542         foreach (
$data->getQuestionTitles() as $question_id => $question_title) {
  6546             foreach ($found_participants as $userdata) {
  6547                 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
  6548                     if (is_object($userdata->getPass($i))) {
  6549                         $question = $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
  6550                         if (is_array($question)) {
  6552                             $reached += $question[
'reached'];
  6553                             $max += $question[
'points'];
  6558             $percent = $max ? $reached / $max * 100.0 : 0;
  6559             $results[
'questions'][$question_id] = [
  6561                 sprintf(
'%.2f', $answered ? $reached / $answered : 0) . 
' ' . strtolower($this->
lng->txt(
'of')) . 
' ' . sprintf(
'%.2f', $answered ? $max / $answered : 0),
  6562                 sprintf(
'%.2f', $percent) . 
'%',
  6564                 sprintf(
'%.2f', $answered ? $reached / $answered : 0),
  6565                 sprintf(
'%.2f', $answered ? $max / $answered : 0),
  6574         $diff_hours = floor($seconds / 3600);
  6575         $seconds -= $diff_hours * 3600;
  6576         $diff_minutes = floor($seconds / 60);
  6577         $seconds -= $diff_minutes * 60;
  6578         return sprintf(
'%02d:%02d:%02d', $diff_hours, $diff_minutes, $seconds);
  6586         return $this->export_factory->getExporter($this, 
'xml')
  6592         return $this->
getMainSettings()->getFinishingSettings()->getMailNotificationContentType();
  6600         $mail->sendSimpleNotification($owner_id, $this->
getTitle(), $usr_data);
  6609         $path = $this->export_factory->getExporter(
  6611             ExportImportTypes::SCORED_ATTEMPT
  6612         )->withFilterByActiveId($active_id)
  6615         $delivered_file_name = 
'result_' . $active_id . 
'.xlsx';
  6617         $fd->copyAttachmentFile(
$path, $delivered_file_name);
  6618         $file_names[] = $delivered_file_name;
  6620         $mail->sendAdvancedNotification($owner_id, $this->
getTitle(), $usr_data, $file_names);
  6622         if (count($file_names)) {
  6623             $fd->unlinkFiles($file_names);
  6633                         FROM            tst_result_cache  6634                         WHERE           active_fi = %s  6637         $result = $this->db->queryF(
  6643         if (!$result->numRows()) {
  6648                                 FROM            tst_result_cache  6649                                 WHERE           active_fi = %s  6652             $result = $this->db->queryF(
  6659         $row = $this->db->fetchAssoc($result);
  6666         return $this->
getMainSettings()->getFinishingSettings()->getAlwaysSendMailNotification();
  6671         return $this->
getScoreSettings()->getResultDetailsSettings()->getExportSettings();
  6686         $question_set_config = $this->question_set_config_factory->getQuestionSetConfig();
  6687         $reindexed_sequence_position_map = $question_set_config->reindexQuestionOrdering();
  6691         return $reindexed_sequence_position_map;
  6700         foreach (array_keys($order) as 
$id) {
  6704                                 UPDATE          tst_test_question  6706                                 WHERE           question_fi = %s  6709             $this->db->manipulateF(
  6711                 [
'integer', 
'integer'],
  6716         if ($this->
logger->isLoggingEnabled()) {
  6717             $this->
logger->logTestAdministrationInteraction(
  6718                 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
  6720                     $this->
user->getId(),
  6721                     TestAdministrationInteractionTypes::QUESTION_MOVED,
  6723                         AdditionalInformationGenerator::KEY_QUESTION_ORDER => $order
  6736         $IN_questions = $this->db->in(
'q1.question_id', array_keys($questions), 
false, 
'integer');
  6739                         SELECT          count(q1.question_id) cnt  6741                         FROM            qpl_questions q1  6743                         INNER JOIN      qpl_questions q2  6744                         ON                      q2.question_id = q1.original_id  6747                         AND                     q1.obj_fi = q2.obj_fi  6749         $rset = $this->db->query($query);
  6750         $row = $this->db->fetchAssoc($rset);
  6752         return $row[
'cnt'] > 0;
  6764         $ilDB = $DIC[
'ilDB'];
  6766         $result = 
$ilDB->queryF(
  6767             "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
  6768             " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
  6769             " WHERE user_fi=%s" .
  6770             " GROUP BY test_fi",
  6771             [
'integer', 
'integer'],
  6775         while ($row = 
$ilDB->fetchAssoc($result)) {
  6776             $obj_id = self::_getObjectIDFromTestID($row[
"test_fi"]);
  6777             $all[$obj_id] = (bool) $row[
"pass"];
  6794         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionHintsEnabled();
  6799         $this->activation_visibility = (bool) $a_value;
  6814         $this->activation_limited = (bool) $a_value;
  6818         ?
bool $is_activation_limited = 
false,
  6819         ?
int $activation_starting_time = null,
  6820         ?
int $activation_ending_time = null,
  6821         bool $activation_visibility = 
false,
  6823         if (!$this->ref_id) {
  6828         $is_activation_limited ??= 
false;
  6830         if (!$is_activation_limited) {
  6834             $item->setTimingStart($activation_starting_time);
  6835             $item->setTimingEnd($activation_ending_time);
  6836             $item->toggleVisible($activation_visibility);
  6839         $item->update($this->ref_id);
  6849         $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
  6850         if ($page_id !== null) {
  6855         $page_object->setParentId($this->
getId());
  6856         $new_page_id = $page_object->createPageWithNextId();
  6858             ->withIntroductionPageId($new_page_id);
  6862         return $new_page_id;
  6867         $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
  6868         if ($page_id !== null) {
  6873         $page_object->setParentId($this->
getId());
  6874         $new_page_id = $page_object->createPageWithNextId();
  6876             ->withConcludingRemarksPageId($new_page_id);
  6880         return $new_page_id;
  6885         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreEnabled();
  6899         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAnon();
  6920         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAchievedTS();
  6928         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreScore();
  6936         return $this->
getScoreSettings()->getGamificationSettings()->getHighscorePercentage();
  6944         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreHints();
  6952         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreWTime();
  6960         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreOwnTable();
  6968         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopTable();
  6977         return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopNum();
  6982         return $this->
getScoreSettings()->getGamificationSettings()->getHighScoreMode();
  6987         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled();
  6992         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getAutosaveEnabled();
  6997         return $this->
getScoreSettings()->getResultSummarySettings()->getPassDeletionAllowed();
  7002         return $this->
getMainSettings()->getFinishingSettings()->getShowAnswerOverview();
  7007         $this->activation_starting_time = $starting_time;
  7012         $this->activation_ending_time = $ending_time;
  7034         $result = $this->db->queryF(
  7035             "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",
  7039         while ($row = $this->db->fetchAssoc($result)) {
  7040             $times[$row[
'active_fi']] = $row[
'started'];
  7048         $result = $this->db->queryF(
  7049             "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",
  7053         while ($row = $this->db->fetchAssoc($result)) {
  7054             $times[$row[
'active_fi']] = $row[
'additionaltime'];
  7061         if ($active_id === 0) {
  7064         return $this->participant_repository
  7065             ->getParticipantByActiveId($this->
getTestId(), $active_id)
  7066             ?->getExtraTime() ?? 0;
  7072                         SELECT MAX(tst_pass_result.pass) + 1 max_res  7073                         FROM tst_pass_result  7074                         INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi  7075                         WHERE test_fi = ' . $this->db->quote($this->
getTestId(), 
'integer') . 
'  7077         $res = $this->db->query($query);
  7079         return (
int) 
$data[
'max_res'];
  7085         $ilDB = $DIC[
'ilDB'];
  7087         $exam_id_query = 
'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
  7088         $exam_id_result = 
$ilDB->queryF($exam_id_query, [ 
'integer', 
'integer' ], [ $active_id, $pass ]);
  7089         if (
$ilDB->numRows($exam_id_result) == 1) {
  7090             $exam_id_row = 
$ilDB->fetchAssoc($exam_id_result);
  7092             if ($exam_id_row[
'exam_id'] != null) {
  7093                 return $exam_id_row[
'exam_id'];
  7100     public static function buildExamId($active_id, $pass, $test_obj_id = null): string
  7107         if ($test_obj_id === null) {
  7108             $obj_id = self::_getObjectIDFromActiveID($active_id);
  7110             $obj_id = $test_obj_id;
  7113         $examId = 
'I' . $inst_id . 
'_T' . $obj_id . 
'_A' . $active_id . 
'_P' . $pass;
  7120         return $this->
getMainSettings()->getTestBehaviourSettings()->getExamIdInTestAttemptEnabled();
  7125         return $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults();
  7133                 ->withQuestionSetType($question_set_type)
  7139         return $this->
getMainSettings()->getGeneralSettings()->getQuestionSetType();
  7164         switch ($questionSetType) {
  7166                 return $lng->
txt(
'tst_question_set_type_fixed');
  7169                 return $lng->
txt(
'tst_question_set_type_random');
  7172         throw new ilTestException(
'invalid question set type value given: ' . $questionSetType);
  7187         $scoring->setPreserveManualScores($preserve_manscoring);
  7188         $scoring->recalculateSolutions();
  7194         $ilDB = $DIC[
'ilDB'];
  7199                         INNER JOIN tst_tests  7200                         ON test_id = test_fi  7204         $res = 
$ilDB->queryF($query, [
'integer'], [$userId]);
  7208         while ($row = 
$ilDB->fetchAssoc(
$res)) {
  7209             $objIds[] = (
int) $row[
'obj_fi'];
  7217         return $this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled();
  7233         if (!$this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled()) {
  7237         if (!self::isSkillManagementGloballyActivated()) {
  7248         if (self::$isSkillManagementGloballyActivated === null) {
  7251             self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
  7254         return self::$isSkillManagementGloballyActivated;
  7259         return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingStatusEnabled();
  7264         return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingMarkEnabled();
  7269         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled();
  7274         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled();
  7279         return $this->
getMainSettings()->getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion();
  7286         $ilDB = $DIC[
'ilDB'];
  7287         $ilUser = $DIC[
'ilUser'];
  7291         $active_id = $test_obj->getActiveIdOfUser($user_id);
  7296         $test_session_factory->reset();
  7298         $test_sequence_factory = 
new ilTestSequenceFactory($test_obj, 
$ilDB, TestDIC::dic()[
'question.general_properties.repository']);
  7300         $test_session = $test_session_factory->getSession($active_id);
  7301         $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $test_session->getPass());
  7310                         SELECT COUNT(test_question_id) cnt  7311                         FROM tst_test_question  7316         $questRes = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
  7318         $row = $this->db->fetchAssoc($questRes);
  7319         $questCount = $row[
'cnt'];
  7325                                 INNER JOIN tst_sequence tseq  7326                                         ON tseq.active_fi = tac.active_id  7327                                 WHERE tac.test_fi = %s  7330             $partRes = $this->db->queryF(
  7336             while ($row = $this->db->fetchAssoc($partRes)) {
  7337                 $sequence = @unserialize($row[
'sequence']);
  7343                 $sequence = array_filter($sequence, 
function ($value) use ($questCount) {
  7344                     return $value <= $questCount;
  7347                 $num_seq = count($sequence);
  7348                 if ($questCount > $num_seq) {
  7349                     $diff = $questCount - $num_seq;
  7350                     for ($i = 1; $i <= $diff; $i++) {
  7351                         $sequence[$num_seq + $i - 1] = $num_seq + $i;
  7355                 $new_sequence = serialize($sequence);
  7357                 $this->db->update(
'tst_sequence', [
  7358                     'sequence' => [
'clob', $new_sequence]
  7360                     'active_fi' => [
'integer', $row[
'active_fi']],
  7361                     'pass' => [
'integer', $row[
'pass']]
  7365             $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : []);
  7370                                 INNER JOIN tst_sequence tseq  7371                                         ON tseq.active_fi = tac.active_id  7372                                 WHERE tac.test_fi = %s  7375             $part_rest = $this->db->queryF(
  7381             while ($row = $this->db->fetchAssoc($part_rest)) {
  7382                 $this->db->update(
'tst_sequence', [
  7383                     'sequence' => [
'clob', $new_sequence]
  7385                     'active_fi' => [
'integer', $row[
'active_fi']],
  7386                     'pass' => [
'integer', $row[
'pass']]
  7407         return $this->global_settings_repo->getGlobalSettings();
  7412         if (!$this->main_settings) {
  7421         if (!$this->main_settings_repo) {
  7429         if (!$this->score_settings) {
  7438         if (!$this->score_settings_repo) {
  7448         if ($pass !== null) {
  7450                 SELECT          tst_pass_result.*,  7451                             tst_active.last_finished_pass  7452                 FROM            tst_pass_result  7453                 INNER JOIN  tst_active  7454                 on          tst_pass_result.active_fi = tst_active.active_id  7455                 WHERE           active_fi = %s  7459             $result = $this->db->queryF(
  7461                 [
'integer',
'integer'],
  7465             $test_pass_result_row = $this->db->fetchAssoc($result);
  7467             if (!is_array($test_pass_result_row)) {
  7468                 $test_pass_result_row = [];
  7470             $max = (float) ($test_pass_result_row[
'maxpoints'] ?? 0);
  7471             $reached = (float) ($test_pass_result_row[
'points'] ?? 0);
  7472             $percentage = ($max <= 0.0 || $reached <= 0.0) ? 0 : ($reached / $max) * 100.0;
  7474             $mark = $this->
getMarkSchema()->getMatchingMark($percentage);
  7475             $is_passed = $test_pass_result_row[
'last_finished_pass'] !== null
  7476                 && $pass <= $test_pass_result_row[
'last_finished_pass']
  7477                 && $mark->getPassed();
  7479             $hint_count = $test_pass_result_row[
'hint_count'] ?? 0;
  7480             $hint_points = $test_pass_result_row[
'hint_points'] ?? 0.0;
  7482             $user_test_result_update_callback = 
function () use ($active_id, $pass, $max, $reached, $is_passed, $hint_count, $hint_points, $mark) {
  7483                 $passed_once_before = 0;
  7484                 $query = 
'SELECT passed_once FROM tst_result_cache WHERE active_fi = %s';
  7485                 $res = $this->db->queryF($query, [
'integer'], [$active_id]);
  7486                 while ($passed_once_result_row = $this->db->fetchAssoc(
$res)) {
  7487                     $passed_once_before = (
int) $passed_once_result_row[
'passed_once'];
  7490                 $passed_once = (
int) ($is_passed || $passed_once_before);
  7492                 $this->db->manipulateF(
  7493                     'DELETE FROM tst_result_cache WHERE active_fi = %s',
  7498                 if ($reached < 0.0) {
  7502                 $mark_short_name = $mark->getShortName();
  7503                 if ($mark_short_name === 
'') {
  7504                     $mark_short_name = 
' ';
  7507                 $mark_official_name = $mark->getOfficialName();
  7508                 if ($mark_official_name === 
'') {
  7509                     $mark_official_name = 
' ';
  7515                         'active_fi' => [
'integer', $active_id],
  7516                         'pass' => [
'integer', $pass ?? 0],
  7517                         'max_points' => [
'float', $max],
  7518                         'reached_points' => [
'float', $reached],
  7519                         'mark_short' => [
'text', $mark_short_name],
  7520                         'mark_official' => [
'text', $mark_official_name],
  7521                         'passed_once' => [
'integer', $passed_once],
  7522                         'passed' => [
'integer', (
int) $is_passed],
  7523                         'failed' => [
'integer', (
int) !$is_passed],
  7524                         'tstamp' => [
'integer', time()],
  7525                         'hint_count' => [
'integer', $hint_count],
  7526                         'hint_points' => [
'float', $hint_points]
  7531             if (is_object($process_locker)) {
  7532                 $process_locker->executeUserTestResultUpdateLockOperation($user_test_result_update_callback);
  7534                 $user_test_result_update_callback();
  7543         int $test_obj_id = null
  7548         $result = $this->db->queryF(
  7550                         SELECT          SUM(r.points) reachedpoints,  7551                                                 SUM(r.hint_count) hint_count,  7552                                                 SUM(r.hint_points) hint_points,  7553                                                 COUNT(DISTINCT(r.question_fi)) answeredquestions,  7554                         pr.finalized_by finalized_by  7555                         FROM            tst_test_result r  7556             INNER JOIN  tst_pass_result pr  7557                 ON r.active_fi = pr.active_fi AND r.pass = pr.pass  7558                         WHERE           r.active_fi = %s  7561             [
'integer',
'integer'],
  7565         if ($result->numRows() > 0) {
  7566             $row = $this->db->fetchAssoc($result);
  7568             if ($row[
'reachedpoints'] === null
  7569                 || $row[
'reachedpoints'] < 0.0) {
  7570                 $row[
'reachedpoints'] = 0.0;
  7572             if ($row[
'hint_count'] === null) {
  7573                 $row[
'hint_count'] = 0;
  7575             if ($row[
'hint_points'] === null) {
  7576                 $row[
'hint_points'] = 0.0;
  7581             $update_pass_result_callback = 
function () use (
$data, $active_id, $pass, $row, $time, $exam_identifier) {
  7585                         'active_fi' => [
'integer', $active_id],
  7586                         'pass' => [
'integer', $pass]
  7589                         'points' => [
'float', $row[
'reachedpoints']],
  7590                         'maxpoints' => [
'float', 
$data[
'points']],
  7591                         'questioncount' => [
'integer', 
$data[
'count']],
  7592                         'answeredquestions' => [
'integer', $row[
'answeredquestions']],
  7593                         'workingtime' => [
'integer', $time],
  7594                         'tstamp' => [
'integer', time()],
  7595                         'hint_count' => [
'integer', $row[
'hint_count']],
  7596                         'hint_points' => [
'float', $row[
'hint_points']],
  7597                         'exam_id' => [
'text', $exam_identifier],
  7598                         'finalized_by' => [
'text', $row[
'finalized_by']]
  7604                 $process_locker->executeUserPassResultUpdateLockOperation($update_pass_result_callback);
  7606                 $update_pass_result_callback();
  7613             'active_fi' => $active_id,
  7615             'points' => $row[
'reachedpoints'],
  7616             'maxpoints' => 
$data[
'points'],
  7617             'questioncount' => 
$data[
'count'],
  7618             'answeredquestions' => $row[
'answeredquestions'],
  7619             'workingtime' => $time,
  7621             'hint_count' => $row[
'hint_count'],
  7622             'hint_points' => $row[
'hint_points'],
  7623             'exam_id' => $exam_identifier
  7628         bool $old_online_status,
  7629         bool $new_online_status
  7631         if (!$old_online_status && $new_online_status) {
  7633             $newsItem->setContext($this->
getId(), 
'tst');
  7635             $newsItem->setTitle(
'new_test_online');
  7636             $newsItem->setContentIsLangVar(
true);
  7637             $newsItem->setContent(
'');
  7638             $newsItem->setUserId($this->
user->getId());
  7640             $newsItem->create();
  7644         if ($old_online_status && !$new_online_status) {
  7650         if (!$new_online_status && $newsId > 0) {
  7652             $newsItem->setTitle(
'new_test_online');
  7653             $newsItem->setContentIsLangVar(
true);
  7654             $newsItem->setContent(
'');
  7655             $newsItem->update();
  7666         $query = 
'SELECT question_set_type FROM tst_tests WHERE obj_fi = %s';
  7668         $res = $DIC[
'ilDB']->queryF($query, [
'integer'], [$obj_id]);
  7670         $question_set_type = null;
  7672         while ($row = $DIC[
'ilDB']->fetchAssoc(
$res)) {
  7673             $question_set_type = $row[
'question_set_type'];
  7676         return $question_set_type === self::QUESTION_SET_TYPE_RANDOM;
  7681         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. 
 
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ilObjUser $user=null,)
 
exportFileItems($target_dir, &$expLog)
export files of file itmes 
 
TestAdministrationInteractionTypes
 
static _getObjectIDFromTestID($test_id)
Returns the ILIAS test object id for a given test id. 
 
A class defining mark schemas for assessment test objects. 
 
deliverPDFfromFO($fo, $title=null)
Delivers a PDF file from a XSL-FO string. 
 
isComplete(ilTestQuestionSetConfig $test_question_set_config)
 
storePropertyIsOnline(ilObjectPropertyIsOnline $property_is_online)
 
ilComponentRepository $component_repository
 
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test. 
 
exportXMLPageObjects(&$a_xml_writer, $inst, &$expLog)
export page objects to xml (see ilias_co.dtd) 
 
getUnfilteredEvaluationData()
 
isShowExamIdInTestPassEnabled()
 
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO. 
 
static deleteNewsOfContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Delete all news of a context. 
 
applyDefaults(array $test_defaults)
 
getTestBehaviourSettings()
 
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
 
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
 
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
 
A class defining marks for assessment test objects. 
 
getCompleteWorkingTimeOfParticipant($active_id)
Returns the complete working time in seconds for a test participant. 
 
This class handles all operations on files (attachments) in directory ilias_data/mail. 
 
setActivationStartingTime(?int $starting_time=null)
 
qtiMaterialToArray($a_material)
Reads an QTI material tag and creates a text string. 
 
TestManScoringDoneHelper $test_man_scoring_done_helper
 
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
 
getShowSolutionListOwnAnswers()
 
getPresentationMaterial()
 
getShowSolutionFeedback()
Returns if the feedback should be presented to the solution or not. 
 
removeTestResults(ilTestParticipantData $participant_data)
 
static lookupPassResultsUpdateTimestamp($active_id, $pass)
 
& getExistingQuestions($pass=null)
Get the id's of the questions which are already part of the test. 
 
bool $print_best_solution_with_result
 
isExecutable($test_session, $user_id, $allow_pass_increase=false)
Checks if the test is executable by the given user. 
 
loadQuestions(int $active_id=0, ?int $pass=null)
Load the test question id's from the database. 
 
getShowKioskModeParticipant()
 
static $isSkillManagementGloballyActivated
 
buildDateTimeImmutableFromPeriod(?string $period)
 
getQuestionSetTypeTranslation(ilLanguage $lng, $questionSetType)
 
saveCompleteStatus(ilTestQuestionSetConfig $test_question_set_config)
 
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed. 
 
getTestId()
Gets the database id of the additional test data. 
 
moveQuestions(array $move_questions, int $target_index, int $insert_mode)
 
static factory(string $a_package, int $a_timeout=0)
Creates an ilRpcClient instance to our ilServer. 
 
Class ilTestMailNotification. 
 
trait TestQuestionsImportTrait
 
getListOfQuestionsSettings()
Returns the settings for the list of questions options in the test properties This could contain one ...
 
createQuestionGUI($question_type, $question_id=-1)
Creates a question GUI instance of a given question type. 
 
TestLogViewer $log_viewer
 
getMailNotificationType()
 
getJavaScriptOutput()
Returns if Javascript should be chosen for drag & drop actions for the active user. 
 
const TIMINGS_DEACTIVATED
 
getShowSolutionAnswersOnly()
Returns if the full solution (including ILIAS content) should be presented to the solution or not...
 
static _lookupName(int $a_user_id)
lookup user name 
 
& createTestSequence($active_id, $pass, $shuffle)
 
getQuestionTitle($title, $nr=null, $points=null)
Returns the title of a test question and checks if the title output is allowed. 
 
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
 
$test_sequence
contains the test sequence data 
 
getXMLZip()
Get zipped xml file for test. 
 
inviteUser($user_id, $client_ip="")
Invites a user to a test. 
 
getAvailableQuestionpools(bool $use_object_id=false, ?bool $equal_points=false, bool $could_be_offline=false, bool $show_path=false, bool $with_questioncount=false, string $permission='read')
Returns the available question pools for the active user. 
 
evalTotalPersonsArray(string $name_sort_order='asc')
 
TestScoringInteractionTypes
 
& getInvitedUsers(int $user_id=0, $order="login, lastname, firstname")
Returns a list of all invited users in a test. 
 
ParticipantRepository $participant_repository
 
toXML()
Returns a QTI xml representation of the test. 
 
getAlwaysSendMailNotification()
 
GlobalSettingsRepository $global_settings_repo
 
setTemplate(int $template_id)
 
setActivationLimited($a_value)
 
static isManScoringDone(int $active_id)
 
setActivationEndingTime(?int $ending_time=null)
 
setTestId($a_id)
Sets the test ID. 
 
getUsrPassOverviewEnabled()
 
static _lookupRandomTest(int $obj_id)
 
isShowExamIdInTestResultsEnabled()
 
getProcessingTimeInSeconds(int $active_id=0)
 
static deliverData(string $a_data, string $a_filename, string $mime="application/octet-stream")
 
getCompleteWorkingTime($user_id)
Returns the complete working time in seconds a user worked on the test. 
 
getQuestionsOfPass(int $active_id, int $pass)
 
getImagePathWeb()
Returns the web image path for web accessable images of a test The image path is under the web access...
 
startingTimeReached()
Returns true if the starting time of a test is reached A starting time is not available for self asse...
 
questionMoveDown($question_id)
Moves a question down in order. 
 
getHighscoreWTime()
Gets if the column with the workingtime should be shown. 
 
getResultDetailsSettings()
 
hasAnyTestResult(ilTestSession $test_session)
 
getActiveIdOfUser($user_id="", $anonymous_id="")
Gets the active id of a given user. 
 
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id. 
 
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
 
getActiveParticipantList()
 
static _isPassed($user_id, $a_obj_id)
Returns TRUE if the user with the user id $user_id passed the test with the object id $a_obj_id...
 
buildName(?int $user_id, ?string $firstname, ?string $lastname)
Builds a user name for the output depending on test type and existence of the user. 
 
static _getBestPass($active_id)
Retrieves the best pass of a given user for a given test. 
 
evalTotalStartedAverageTime(?array $active_ids_to_filter=null)
 
saveToDb(bool $properties_only=false)
 
static _lookupTestObjIdForQuestionId(int $q_id)
Get test Object ID for question ID. 
 
withGeneralSettings(SettingsGeneral $settings)
 
static _lookupAnonymity($a_obj_id)
 
getTestResult(int $active_id, ?int $pass=null, bool $ordered_sequence=false, bool $consider_hidden_questions=true, bool $consider_optional_questions=true)
Calculates the results of a test for a given user and returns an array with all test results...
 
sort()
 description: > Example for rendering a Sort Glyph. 
 
getPotentialRandomTestQuestions()
 
getShowSolutionListComparison()
 
setQuestionSetSolved($value, $question_id, $user_id)
sets question solved state to value for given user_id 
 
Base Exception for all Exceptions relating to Modules/Test. 
 
getHighscoreTopTable()
Gets, if the top-rankings table should be shown. 
 
lookupQuestionSetTypeByActiveId(int $active_id)
 
updateTestPassResults(int $active_id, int $pass, ilAssQuestionProcessLocker $process_locker=null, int $test_obj_id=null)
 
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. 
 
static _getUserIdFromActiveId(int $active_id)
 
updateWorkingTime($times_id)
Update the working time of a test when a question is answered. 
 
getFixedQuestionSetTotalPoints()
 
secondsToHoursMinutesSecondsString(int $seconds)
 
getHtmlQuestionContentPurifier()
 
ExportImportFactory $export_factory
 
ilTestParticipantList $access_filtered_participant_list
 
getSpecificAnswerFeedback()
 
getImportMapping()
get array of (two) new created questions for import id 
 
static _getMaxPass($active_id)
Retrieves the maximum pass of a given user for a given test in which the user answered at least one q...
 
addDefaults($a_name)
Adds the defaults of this test to the test defaults. 
 
cloneObject(int $target_id, int $copy_id=0, bool $omit_tree=false)
Clone object. 
 
removeTestResultsByUserIds(array $user_ids)
 
static collectFileItems(ilPageObject $a_page, DOMDocument $a_domdoc)
Get all file items that are used within the page. 
 
static instantiateQuestion(int $question_id)
 
$metadata
A reference to an IMS compatible matadata set. 
 
checkQuestionParent(int $question_id)
 
Interface for html sanitizing functionality. 
 
evalStatistical($active_id)
Returns the statistical evaluation of the test for a specified user. 
 
removeQuestionWithResults(int $question_id, TestScoring $scoring)
 
static getSingleManualFeedback(int $active_id, int $question_id, int $pass)
 
getGamificationSettings()
 
getHighscoreHints()
Gets, if the column with the number of requested hints should be shown. 
 
getTotalPointsPassedArray()
Returns an array with the total points of all users who passed the test This array could be used for ...
 
cloneMetaData(ilObject $target_obj)
Copy meta data. 
 
getAccessFilteredParticipantList()
 
getVisitingTimeOfParticipant(int $active_id)
 
getQuestiontext($question_id)
Returns the question text for a given question. 
 
replaceMobsInPageImports(string $text, array $mappings)
 
static _lookupTitle(int $obj_id)
 
getAllQuestions($pass=null)
Returns all questions of a test in test order. 
 
getHighscoreAnon()
Gets if the highscores should be anonymized per setting. 
 
sendAdvancedNotification(int $active_id)
 
getTestParticipantsForManualScoring($filter=null)
 
fromXML(ilQTIAssessment $assessment, array $mappings)
Receives parameters from a QTI parser and creates a valid ILIAS test object. 
 
storeMarkSchema(MarkSchema $mark_schema)
 
static _prepareCloneSelection(array $ref_ids, string $new_type, bool $show_path=true)
Prepare copy wizard object selection. 
 
setActivationVisibility($a_value)
 
hasQuestionsWithoutQuestionpool()
 
evalTotalPersons()
Returns the number of persons who started the test. 
 
retrieveMobsFromLegacyImports(string $text, array $mobs, string $importdir)
 
getStartingTimeOfUser($active_id, $pass=null)
Returns the unix timestamp of the time a user started a test. 
 
sendSimpleNotification($active_id)
 
getShowSolutionPrintview()
Returns if the solution printview should be presented to the user or not. 
 
updateTestResultCache(int $active_id, ilAssQuestionProcessLocker $process_locker=null)
 
hasNrOfTriesRestriction()
returns if the numbers of tries have to be checked 
 
getAuthor()
Gets the authors name of the ilObjTest object. 
 
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user. 
 
getTestDefaults($test_defaults_id)
 
getShowPassDetails()
Returns if the pass details should be shown when a test is not finished. 
 
ilTestPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI  ilTestPageGUI: ilPublicUserProfile...
 
removeQuestion(int $question_id)
 
isTestFinishedToViewResults($active_id, $currentpass)
Returns true if an active user completed a test pass and did not start a new pass. 
 
getUserData($ids)
Returns a data of all users specified by id list. 
 
questionMoveUp($question_id)
Moves a question up in order. 
 
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively 
 
MainSettings $main_settings
 
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id 
 
static _getSolutionMaxPass(int $question_id, int $active_id)
Returns the maximum pass a users question solution. 
 
getShowSolutionSuggested()
 
isSkillServiceToBeConsidered()
Returns whether this test must consider skills, usually by providing appropriate extensions in the us...
 
static _getCountSystem($active_id)
 
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions 
 
getResultsForActiveId(int $active_id)
 
static createDirectory(string $a_dir, int $a_mod=0755)
create directory 
 
ilTestEditPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI  ilTestEditPageGUI: ilPublicUse...
 
isOfferingQuestionHintsEnabled()
 
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
 
Filesystem $filesystem_web
 
exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export media objects to xml (see ilias_co.dtd) 
 
Class ilObjForumAdministration. 
 
getAnsweredQuestionCount($active_id, $pass=null)
Retrieves the number of answered questions for a given user in a given test. 
 
getAvailableDefaults()
Returns the available test defaults for the active user. 
 
withIntroductionPageId(?int $introduction_page_id)
 
convertTimeToDateTimeImmutableIfNecessary(DateTimeImmutable|int|null $date_time)
 
static getInstanceByType(string $type)
 
static isSkillManagementGloballyActivated()
 
getAnswerFeedbackPoints()
 
canShowTestResults(ilTestSession $test_session)
 
createExportDirectory()
creates data directory for export files (data_dir/tst_data/tst_<id>/export, depending on data directo...
 
getAggregatedResultsData()
 
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object. 
 
static _getObjectsByOperations( $a_obj_type, string $a_operation, int $a_usr_id=0, int $limit=0)
Get all objects of a specific type and check access This function is not recursive, instead it parses the serialized rbac_pa entries. 
 
removeTestActives(array $active_ids)
 
copyQuestions(array $question_ids)
 
getStartingTimeOfParticipants()
Note, this function should only be used if absolutely necessary, since it perform joins on tables tha...
 
RequestDataCollector $testrequest
 
static getDataDir()
get data directory (outside webspace) 
 
getLastFinishedPassTimestamp()
 
getResultSummarySettings()
 
getShowSolutionSignature()
Returns if the signature field should be shown in the test results. 
 
static _lookupFinishedUserTests($a_user_id)
Gather all finished tests for user. 
 
pcArrayShuffle($array)
Shuffles the values of a given array. 
 
ilTestQuestionSetConfigFactory $question_set_config_factory
 
getMainSettingsRepository()
 
getCompleteEvaluationData($filterby='', $filtertext='')
 
static _lookupDescription(int $obj_id)
 
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
 
static _getTestIDFromObjectID($object_id)
Returns the ILIAS test id for a given object id. 
 
getInstantFeedbackSolution()
 
getAllTestResults($participants)
returns all test results for all participants 
 
removeQuestionsWithResults(array $question_ids)
 
isHighscoreAnon()
Gets if the highscores should be displayed anonymized. 
 
isInstantFeedbackAnswerFixationEnabled()
 
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests. 
 
storeActivationSettings(?bool $is_activation_limited=false, ?int $activation_starting_time=null, ?int $activation_ending_time=null, bool $activation_visibility=false,)
 
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
 
buildImportDirectoryFromImportFile(string $file_to_import)
 
getProcessingTimeForXML()
 
updatePassAndTestResults(array $active_ids)
 
duplicateQuestionForTest($question_id)
Takes a question and creates a copy of the question for use in the test. 
 
addIntroductionToSettingsFromImport(SettingsIntroduction $settings, array $material, string $importdir, array $mappings)
 
evalTotalParticipantsArray(string $name_sort_order='asc')
 
isScoreReportingEnabled()
 
getAvailableQuestions($arr_filter, $completeonly=0)
Calculates the available questions for a test. 
 
isForceInstantFeedbackEnabled()
 
getQuestionDataset($question_id)
Returns the dataset for a given question id. 
 
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory. 
 
withConcludingRemarksPageId(?int $concluding_remarks_page_id)
 
ilObjectProperties $object_properties
 
removeQuestions(array $question_ids)
 
getParticipantFunctionalitySettings()
 
removeTestResultsByActiveIds(array $active_ids)
 
A news item can be created by different sources. 
 
getGenericAnswerFeedback()
 
static _getScoreCutting(int $active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test...
 
removeQuestionFromSequences(int $question_id, array $active_ids, ilTestReindexedSequencePositionMap $reindexed_sequence_position_map)
 
addToNewsOnOnline(bool $old_online_status, bool $new_online_status)
 
static getItem(int $ref_id)
 
buildIso8601PeriodForExportCompatibility(DateTimeImmutable $date_time)
 
isQuestionSetConfigured()
 
getActivationStartingTime()
 
int $activation_ending_time
 
getTextAnswer($active_id, $question_id, $pass=null)
Returns the text answer of a given user for a given question. 
 
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test...
 
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename 
 
bool $activation_visibility
 
getParticipantsForTestAndQuestion($test_id, $question_id)
Creates an associated array with all active id's for a given test and original question id...
 
setTmpCopyWizardCopyId(int $tmpCopyWizardCopyId)
 
static _getAvailableTests($use_object_id=false)
Returns the available tests for the active user. 
 
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins 
 
__construct(Container $dic, ilPlugin $plugin)
 
static getFirstNewsIdForContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Get first new id of news set related to a certain context. 
 
getQuestionCountAndPointsForPassOfParticipant(int $active_id, int $pass)
 
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd) 
 
recalculateScores($preserve_manscoring=false)
 
clonePage(int $source_page_id)
 
getMailNotificationContentType()
 
ScoreSettings $score_settings
 
ScoreSettingsRepository $score_settings_repo
 
deleteDefaults($test_default_id)
 
endingTimeReached()
Returns true if the ending time of a test is reached An ending time is not available for self assessm...
 
getGeneralQuestionPropertiesRepository()
 
getActivationEndingTime()
 
getCompleteManualFeedback(int $question_id)
Retrieves the manual feedback for a question in a test. 
 
getParticipants()
Returns all persons who started the test. 
 
const QUESTION_SET_TYPE_FIXED
 
getConcludingRemarksPageId()
 
isActiveTestSubmitted($user_id=null)
returns if the active for user_id has been submitted 
 
modifyExportIdentifier($a_tag, $a_param, $a_value)
Returns the installation id for a given identifier. 
 
getQuestionTitlesAndIndexes()
Returns the titles of the test questions in question sequence. 
 
getIntroductionSettings()
 
getQuestionType($question_id)
Returns the question type of a question with a given id. 
 
static buildExamId($active_id, $pass, $test_obj_id=null)
 
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag. 
 
GeneralQuestionPropertiesRepository $questionrepository
 
isTestQuestion(int $question_id)
 
static _getPassScoring(int $active_id)
Gets the pass scoring type. 
 
& getCompleteWorkingTimeOfParticipants()
Returns the complete working time in seconds for all test participants. 
 
getNrOfResultsForPass($active_id, $pass)
Calculates the number of user results for a specific test pass. 
 
getQuestionBehaviourSettings()
 
ilComponentFactory $component_factory
 
addQTIMaterial(ilXmlWriter &$xml_writer, ?int $page_id, string $material='')
 
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content) 
 
isShowGradingStatusEnabled()
 
canShowSolutionPrintview($user_id=null)
 
getQuestionCountWithoutReloading()
 
getHighscoreScore()
Gets if the score column should be shown. 
 
static getTestObjIdsWithActiveForUserId($userId)
 
isPluginActive($a_pname)
Checks wheather or not a question plugin with a given name is active. 
 
isFollowupQuestionAnswerFixationEnabled()
 
saveManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized=false)
 
saveAuthorToMetadata($author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
 
static getManualFeedback(int $active_id, int $question_id, ?int $pass)
Retrieves the feedback comment for a question in a test if it is finalized. 
 
getScoreSettingsRepository()
 
static insertInstIntoID(string $a_value)
inserts installation id into ILIAS id 
 
getWorkingTimeOfParticipantForPass(int $active_id, int $pass)
 
deliverPDFfromHTML($content, $title=null)
Delivers a PDF file from XHTML. 
 
getDetailedTestResults($participants)
returns all test results for all participants 
 
static getInstance(int $obj_id)
 
static clear(string $a_var)
 
isNrOfTriesReached($tries)
returns if number of tries are reached 
 
Class ilObjectActivation. 
 
_getLastAccess(int $active_id)
 
setAccessFilteredParticipantList(ilTestParticipantList $access_filtered_participant_list)
 
static deleteRequestsByActiveIds($activeIds)
Deletes all hint requests relating to a testactive included in given active ids. 
 
insertManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized, array $feedback_old)
 
insertQuestion(int $question_id, bool $link_only=false)
 
reindexFixedQuestionOrdering()
 
static _getAvailableQuestionpools(bool $use_object_id=false, bool $equal_points=false, bool $could_be_offline=false, bool $showPath=false, bool $with_questioncount=false, string $permission='read', int $usr_id=0)
Returns the available question pools for the active user. 
 
ilTestParticipantAccessFilterFactory $participant_access_filter
 
withScoringSettings(SettingsScoring $settings)
 
userLookupFullName($user_id, $overwrite_anonymity=false, $sorted_order=false, $suffix="")
Returns the full name of a test user according to the anonymity status. 
 
static _getActiveIdOfUser($user_id="", $test_id="")
 
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
 
isMaxProcessingTimeReached(int $starting_time, int $active_id)
Returns whether the maximum processing time for a test is reached or not. 
 
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.