ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.ilObjTest.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Services/Object/classes/class.ilObject.php';
5require_once 'Modules/Test/classes/inc.AssessmentConstants.php';
6require_once 'Modules/Test/interfaces/interface.ilMarkSchemaAware.php';
7require_once 'Modules/Test/interfaces/interface.ilEctsGradesEnabled.php';
8require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionType.php';
9
21{
23
24 #region Properties
25
29 const QUESTION_SET_TYPE_FIXED = 'FIXED_QUEST_SET';
30
34 const QUESTION_SET_TYPE_RANDOM = 'RANDOM_QUEST_SET';
35
39 const QUESTION_SET_TYPE_DYNAMIC = 'DYNAMIC_QUEST_SET';
40
45
50
55
62
66 private $skillServiceEnabled = false;
67
71 private $resultFilterTaxIds = array();
72
80 protected $_kiosk;
81
87 public $test_id;
88
95
102 public $author;
103
109 public $metadata;
110
117
122
129 protected $introduction;
130
137
146
157
166
173
183
190
198
200
208
218
225
232
239
244
250 protected $starting_time;
251
256
262 protected $ending_time;
263
268 protected $ects_output = false;
269
274 protected $ects_fx = null;
275
280 protected $ects_grades = array();
281
282
290
297
304
312
319
326
333
338
344 protected $password;
345
350
356 protected $allowedUsers;
357
364
371
378
385
392
399
406
413
420
427
434
440 private $_showinfo;
441
447 private $_forcejs = true;
448
455
457
458 protected $mailnottype;
459
461
462 protected $poolUsage;
463
465
466 protected $oldOnlineStatus = null;
467
472
479
485 private $obligationsEnabled = null;
486
488
490
492
493 protected $autosave;
494
495 protected $autosave_ival;
496
503 private $passDeletionAllowed = null;
504
510 private $participantDataExist = null;
511
514
517
520
523
527 private $redirection_mode = 0;
528
532 private $redirection_url = null;
533
536
539
542
545
548
553
558
563
568
573
578
583
587 protected $pass_waiting = "00:000:00:00:00";
588 #endregion
589
598 public function __construct($a_id = 0, $a_call_by_reference = true)
599 {
600 global $DIC;
601 $ilUser = $DIC['ilUser'];
602 $lng = $DIC['lng'];
603 $this->type = "tst";
604
605 $lng->loadLanguageModule("assessment");
606 // Defaults:
607 include_once "./Modules/Test/classes/class.assMarkSchema.php";
608 $this->mark_schema = new ASS_MarkSchema();
609 $this->mark_schema->createSimpleSchema(
610 $lng->txt("failed_short"),
611 $lng->txt("failed_official"),
612 0,
613 0,
614 $lng->txt("passed_short"),
615 $lng->txt("passed_official"),
616 50,
617 1
618 );
619
620 $this->test_id = -1;
621 $this->author = $ilUser->fullname;
622 $this->introductionEnabled = false;
623 $this->introduction = "";
624 $this->questions = array();
625 $this->sequence_settings = TEST_FIXED_SEQUENCE;
626 $this->score_reporting = self::SCORE_REPORTING_FINISHED;
627 $this->instant_verification = 0;
628 $this->answer_feedback_points = 0;
629 $this->reporting_date = "";
630 $this->nr_of_tries = 0;
631 $this->_kiosk = 0;
632 $this->use_previous_answers = 1;
633 $this->title_output = 0;
634 $this->starting_time = "";
635 $this->ending_time = "";
636 $this->processing_time = "";
637 $this->enable_processing_time = "0";
638 $this->reset_processing_time = 0;
639 $this->ects_output = false;
640 $this->ects_fx = null;
641 $this->shuffle_questions = false;
642 $this->mailnottype = 0;
643 $this->exportsettings = 0;
644 $this->show_summary = 8;
645 $this->count_system = COUNT_PARTIAL_SOLUTIONS;
646 $this->mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED;
647 $this->score_cutting = SCORE_CUT_QUESTION;
648 $this->pass_scoring = SCORE_LAST_PASS;
649 $this->answer_feedback = 0;
650 $this->password = "";
651 $this->certificate_visibility = 0;
652 $this->allowedUsers = "";
653 $this->_showfinalstatement = false;
654 $this->_finalstatement = "";
655 $this->_showinfo = true;
656 $this->_forcejs = true;
657 $this->_customStyle = "";
658 $this->allowedUsersTimeGap = "";
659 $this->anonymity = 0;
660 $this->show_cancel = 0;
661 $this->show_marker = 0;
662 $this->fixed_participants = 0;
663 $this->setShowPassDetails(true);
664 $this->setShowSolutionDetails(true);
665 $this->setShowSolutionAnswersOnly(false);
666 $this->setShowSolutionSignature(false);
667 $this->testSession = false;
668 $this->testSequence = false;
669 $this->mailnotification = 0;
670 $this->poolUsage = 1;
671
672 $this->ects_grades = array(
673 'A' => 90,
674 'B' => 65,
675 'C' => 35,
676 'D' => 10,
677 'E' => 0
678 );
679
680 $this->autosave = false;
681 $this->autosave_ival = 30000;
682
683 $this->enable_examview = false;
684 $this->show_examview_html = false;
685 $this->show_examview_pdf = false;
686 $this->enable_archiving = false;
687
688 $this->express_mode = false;
689 $this->template_id = '';
690 $this->redirection_mode = 0;
691 $this->redirection_url = null;
692 $this->show_exam_id_in_test_pass_enabled = false;
693 $this->show_exam_id_in_test_results_enabled = false;
694 $this->sign_submission = false;
695 $this->char_selector_availability = 0;
696 $this->char_selector_definition = null;
697
698 $this->showGradingStatusEnabled = true;
699 $this->showGradingMarkEnabled = true;
700
701 $this->followupQuestionAnswerFixationEnabled = false;
702 $this->instantFeedbackAnswerFixationEnabled = false;
703
704 $this->testFinalBroken = false;
705
706 $this->tmpCopyWizardCopyId = null;
707
708 parent::__construct($a_id, $a_call_by_reference);
709 }
710
717 {
718 require_once 'Services/Utilities/classes/class.ilUtil.php';
719 return ilUtil::getASCIIFilename($this->getTitle());
720 }
721
725 public function getTmpCopyWizardCopyId()
726 {
728 }
729
734 {
735 $this->tmpCopyWizardCopyId = $tmpCopyWizardCopyId;
736 }
737
741 public function create()
742 {
743 $this->setOfflineStatus(true);
744 parent::create();
745
746 // meta data will be created by
747 // import parser
748 if (!$a_upload) {
749 $this->createMetaData();
750 }
751 }
752
759 public function update()
760 {
761 if (!parent::update()) {
762 return false;
763 }
764
765 // put here object specific stuff
766 $this->updateMetaData();
767 return true;
768 }
769
775 public function read()
776 {
777 parent::read();
778 $this->loadFromDb();
779 }
780
781
788 public function delete()
789 {
790 // always call parent delete function first!!
791 if (!parent::delete()) {
792 return false;
793 }
794
795 // delet meta data
796 $this->deleteMetaData();
797
798 //put here your module specific stuff
799 $this->deleteTest();
800
801 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentImportFails.php';
802 $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($this->getId());
803 $qsaImportFails->deleteRegisteredImportFails();
804 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdImportFails.php';
805 $sltImportFails = new ilTestSkillLevelThresholdImportFails($this->getId());
806 $sltImportFails->deleteRegisteredImportFails();
807
808 return true;
809 }
810
816 public function deleteTest()
817 {
818 global $DIC;
819 $tree = $DIC['tree'];
820 $ilDB = $DIC['ilDB'];
821 $ilPluginAdmin = $DIC['ilPluginAdmin'];
822 $lng = $DIC['lng'];
823
824 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
825 $participantData = new ilTestParticipantData($ilDB, $lng);
826 $participantData->load($this->getTestId());
827 $this->removeTestResults($participantData);
828
829 $affectedRows = $ilDB->manipulateF(
830 "DELETE FROM tst_mark WHERE test_fi = %s",
831 array('integer'),
832 array($this->getTestId())
833 );
834
835 $affectedRows = $ilDB->manipulateF(
836 "DELETE FROM tst_tests WHERE test_id = %s",
837 array('integer'),
838 array($this->getTestId())
839 );
840
841 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
842 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
843 $testQuestionSetConfigFactory->getQuestionSetConfig()->removeQuestionSetRelatedData();
844
845 // delete export files
846 include_once "./Services/Utilities/classes/class.ilUtil.php";
847 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
848 $directory = $tst_data_dir . "/tst_" . $this->getId();
849 if (is_dir($directory)) {
850 include_once "./Services/Utilities/classes/class.ilUtil.php";
851 ilUtil::delDir($directory);
852 }
853 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
854 $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
855 // remaining usages are not in text anymore -> delete them
856 // and media objects (note: delete method of ilObjMediaObject
857 // checks whether object is used in another context; if yes,
858 // the object is not deleted!)
859 foreach ($mobs as $mob) {
860 ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
861 if (ilObjMediaObject::_exists($mob)) {
862 $mob_obj = new ilObjMediaObject($mob);
863 $mob_obj->delete();
864 }
865 }
866 }
867
873 public function createExportDirectory()
874 {
875 include_once "./Services/Utilities/classes/class.ilUtil.php";
876 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
877 ilUtil::makeDir($tst_data_dir);
878 if (!is_writable($tst_data_dir)) {
879 $this->ilias->raiseError("Test Data Directory (" . $tst_data_dir
880 . ") not writeable.", $this->ilias->error_obj->MESSAGE);
881 }
882
883 // create learning module directory (data_dir/lm_data/lm_<id>)
884 $tst_dir = $tst_data_dir . "/tst_" . $this->getId();
885 ilUtil::makeDir($tst_dir);
886 if (!@is_dir($tst_dir)) {
887 $this->ilias->raiseError("Creation of Test Directory failed.", $this->ilias->error_obj->MESSAGE);
888 }
889 // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
890 $export_dir = $tst_dir . "/export";
891 ilUtil::makeDir($export_dir);
892 if (!@is_dir($export_dir)) {
893 $this->ilias->raiseError("Creation of Export Directory failed.", $this->ilias->error_obj->MESSAGE);
894 }
895 }
896
902 public function getExportDirectory()
903 {
904 include_once "./Services/Utilities/classes/class.ilUtil.php";
905 $export_dir = ilUtil::getDataDir() . "/tst_data" . "/tst_" . $this->getId() . "/export";
906 return $export_dir;
907 }
908
915 public function getExportFiles($dir)
916 {
917 // quit if import dir not available
918 if (!@is_dir($dir) || !is_writeable($dir)) {
919 return array();
920 }
921
922 $files = array();
923 foreach (new DirectoryIterator($dir) as $file) {
927 if ($file->isDir()) {
928 continue;
929 }
930
931 $files[] = $file->getBasename();
932 }
933
934 sort($files);
935
936 return $files;
937 }
938
942 public static function _setImportDirectory($a_import_dir = null)
943 {
944 if (strlen($a_import_dir)) {
945 $_SESSION["tst_import_dir"] = $a_import_dir;
946 } else {
947 unset($_SESSION["tst_import_dir"]);
948 }
949 }
950
957 public static function _getImportDirectory()
958 {
959 if (strlen($_SESSION["tst_import_dir"])) {
960 return $_SESSION["tst_import_dir"];
961 }
962 return null;
963 }
964
965 public function getImportDirectory()
966 {
968 }
969
975 public static function _createImportDirectory()
976 {
977 global $DIC;
978 $ilias = $DIC['ilias'];
979 include_once "./Services/Utilities/classes/class.ilUtil.php";
980 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
981 ilUtil::makeDir($tst_data_dir);
982
983 if (!is_writable($tst_data_dir)) {
984 $ilias->raiseError("Test Data Directory (" . $tst_data_dir
985 . ") not writeable.", $ilias->error_obj->FATAL);
986 }
987
988 // create test directory (data_dir/tst_data/tst_import)
989 $tst_dir = $tst_data_dir . "/tst_import";
990 ilUtil::makeDir($tst_dir);
991 if (!@is_dir($tst_dir)) {
992 $ilias->raiseError("Creation of test import directory failed.", $ilias->error_obj->FATAL);
993 }
994
995 // assert that this is empty and does not contain old data
996 ilUtil::delDir($tst_dir, true);
997
998 return $tst_dir;
999 }
1000
1008 {
1009 global $DIC;
1010 $ilDB = $DIC['ilDB'];
1011
1012 $result = $ilDB->queryF(
1013 "SELECT DISTINCT(qpl_qst_type.type_tag) foundtypes FROM qpl_questions, tst_test_result, qpl_qst_type, tst_active WHERE tst_test_result.question_fi = qpl_questions.question_id AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id AND tst_test_result.active_fi = tst_active.active_id AND tst_active.test_fi = %s",
1014 array('integer'),
1015 array($this->getTestId())
1016 );
1017 $hasSC = false;
1018 while ($row = $ilDB->fetchAssoc($result)) {
1019 if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1020 $hasSC = true;
1021 }
1022 }
1023 return $hasSC;
1024 }
1025
1032 public function isSingleChoiceTest()
1033 {
1034 global $DIC;
1035 $ilDB = $DIC['ilDB'];
1036
1037 $result = $ilDB->queryF(
1038 "SELECT DISTINCT(qpl_qst_type.type_tag) foundtypes FROM qpl_questions, tst_test_result, qpl_qst_type, tst_active WHERE tst_test_result.question_fi = qpl_questions.question_id AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id AND tst_test_result.active_fi = tst_active.active_id AND tst_active.test_fi = %s",
1039 array('integer'),
1040 array($this->getTestId())
1041 );
1042 if ($result->numRows() == 1) {
1043 $row = $ilDB->fetchAssoc($result);
1044 if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1045 return true;
1046 } else {
1047 return false;
1048 }
1049 }
1050 return false;
1051 }
1052
1060 {
1061 global $DIC;
1062 $ilDB = $DIC['ilDB'];
1063
1064 if (!$this->hasSingleChoiceQuestions()) {
1065 return false;
1066 }
1067
1068 $result = $ilDB->queryF(
1069 "
1070 SELECT DISTINCT(qpl_qst_sc.shuffle) foundshuffles
1071 FROM qpl_questions,
1072 qpl_qst_sc,
1073 tst_test_result,
1074 qpl_qst_type,
1075 tst_active
1076 WHERE tst_test_result.question_fi = qpl_questions.question_id
1077 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
1078 AND tst_test_result.active_fi = tst_active.active_id
1079 AND qpl_questions.question_id = qpl_qst_sc.question_fi
1080 AND tst_active.test_fi = %s
1081 AND qpl_qst_type.type_tag = %s
1082 ",
1083 array('integer', 'text'),
1084 array($this->getTestId(), 'assSingleChoice')
1085 );
1086 if ($result->numRows() == 1) {
1087 $row = $ilDB->fetchAssoc($result);
1088 return ($row['foundshuffles'] == 0);
1089 }
1090 return false;
1091 }
1092
1099 final public function isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
1100 {
1101 if (!count($this->mark_schema->mark_steps)) {
1102 return false;
1103 }
1104
1105 if (!$testQuestionSetConfig->isQuestionSetConfigured()) {
1106 return false;
1107 }
1108
1109 return true;
1110 }
1111
1118 public function _isComplete($obj_id)
1119 {
1120 global $DIC;
1121 $tree = $DIC['tree'];
1122 $ilDB = $DIC['ilDB'];
1123 $ilPluginAdmin = $DIC['ilPluginAdmin'];
1124
1125 $test = new ilObjTest($obj_id, false);
1126 $test->loadFromDb();
1127
1128 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1129 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
1130
1131 return $test->isComplete($testQuestionSetConfigFactory->getQuestionSetConfig());
1132 }
1133
1137 public function saveECTSStatus()
1138 {
1142 global $DIC;
1143 $ilDB = $DIC['ilDB'];
1144
1145 if ($this->getTestId() > 0) {
1146 $this->setECTSFX(preg_replace('/,/', '.', $this->getECTSFX()));
1147 if (!preg_match('/\d+/', $this->getECTSFX())) {
1148 $this->setECTSFX(null);
1149 }
1150
1151 $grades = $this->getECTSGrades();
1152 $ilDB->manipulateF(
1153 "UPDATE tst_tests
1154 SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s
1155 WHERE test_id = %s",
1156 array('text', 'float', 'float', 'float', 'float', 'float', 'float', 'integer'),
1157 array(
1158 (int) $this->getECTSOutput(),
1159 $grades['A'], $grades['B'], $grades['C'], $grades['D'], $grades['E'],
1160 $this->getECTSFX(),
1161 $this->getTestId()
1162 )
1163 );
1164 }
1165 }
1166
1171 public function saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
1172 {
1173 global $DIC;
1174 $ilDB = $DIC['ilDB'];
1175
1176 $complete = 0;
1177 if ($this->isComplete($testQuestionSetConfig)) {
1178 $complete = 1;
1179 }
1180 if ($this->getTestId() > 0) {
1181 $ilDB->manipulateF(
1182 "UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1183 array('text', 'integer'),
1184 array($complete, $this->test_id)
1185 );
1186 }
1187 }
1188
1194 public function getAllRTEContent()
1195 {
1196 $result = array();
1197 array_push($result, $this->getIntroduction());
1198 array_push($result, $this->getFinalStatement());
1199 return $result;
1200 }
1201
1207 public function cleanupMediaobjectUsage()
1208 {
1209 include_once("./Services/RTE/classes/class.ilRTE.php");
1210 $completecontent = "";
1211 foreach ($this->getAllRTEContent() as $content) {
1212 $completecontent .= $content;
1213 }
1215 $completecontent,
1216 $this->getType() . ":html",
1217 $this->getId()
1218 );
1219 }
1220
1226 public function saveToDb($properties_only = false)
1227 {
1228 global $DIC;
1229 $tree = $DIC['tree'];
1230 $ilDB = $DIC['ilDB'];
1231 $ilPluginAdmin = $DIC['ilPluginAdmin'];
1232
1233 // moved online_status to ilObjectActivation (see below)
1234
1235 // cleanup RTE images
1236 $this->cleanupMediaobjectUsage();
1237
1238 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1239 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
1240 $testQuestionSetConfig = $testQuestionSetConfigFactory->getQuestionSetConfig();
1241
1242 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1243 if ($this->test_id == -1) {
1244 // Create new dataset
1245 $next_id = $ilDB->nextId('tst_tests');
1246
1247 $ilDB->insert('tst_tests', array(
1248 'test_id' => array('integer', $next_id),
1249 'obj_fi' => array('integer', $this->getId()),
1250 'author' => array('text', $this->getAuthor()),
1251 'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1252 'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1253 'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1254 'showinfo' => array('integer', $this->getShowInfo()),
1255 'forcejs' => array('integer', $this->getForceJS()),
1256 'customstyle' => array('text', $this->getCustomStyle()),
1257 'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1258 'sequence_settings' => array('integer', $this->getSequenceSettings()),
1259 'score_reporting' => array('integer', $this->getScoreReporting()),
1260 'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1261 'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1262 'answer_feedback' => array('text', $this->getAnswerFeedback()),
1263 'anonymity' => array('text', $this->getAnonymity()),
1264 'show_cancel' => array('text', $this->getShowCancel()),
1265 'show_marker' => array('integer', $this->getShowMarker()),
1266 'fixed_participants' => array('text', $this->getFixedParticipants()),
1267 'nr_of_tries' => array('integer', $this->getNrOfTries()),
1268 'block_after_passed' => array('integer', (int) $this->isBlockPassesAfterPassedEnabled()),
1269 'kiosk' => array('integer', $this->getKiosk()),
1270 'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1271 'title_output' => array('text', $this->getTitleOutput()),
1272 'processing_time' => array('text', $this->getProcessingTime()),
1273 'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1274 'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1275 'reporting_date' => array('text', $this->getReportingDate()),
1276 'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1277 'starting_time' => array('integer', $this->getStartingTime()),
1278 'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1279 'ending_time' => array('integer', $this->getEndingTime()),
1280 'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1281 'ects_output' => array('text', $this->getECTSOutput()),
1282 'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1283 'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1284 'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1285 'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1286 'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1287 'ects_fx' => array('float', $this->getECTSFX()),
1288 'count_system' => array('text', $this->getCountSystem()),
1289 'mc_scoring' => array('text', $this->getMCScoring()),
1290 'score_cutting' => array('text', $this->getScoreCutting()),
1291 'pass_scoring' => array('text', $this->getPassScoring()),
1292 'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1293 'results_presentation' => array('integer', $this->getResultsPresentation()),
1294 'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1295 'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1296 'password' => array('text', $this->getPassword()),
1297 'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1298 'allowedusers' => array('integer', $this->getAllowedUsers()),
1299 'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1300 'mailnottype' => array('integer', $this->getMailNotificationType()),
1301 'exportsettings' => array('integer', $this->getExportSettings()),
1302 'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1303 'mailnotification' => array('integer', $this->getMailNotification()),
1304 'created' => array('integer', time()),
1305 'tstamp' => array('integer', time()),
1306 'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1307 'template_id' => array('integer', $this->getTemplate()),
1308 'pool_usage' => array('integer', $this->getPoolUsage()),
1309 'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1310 'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1311 'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1312 'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1313 'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1314 'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1315 'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1316 'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1317 'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1318 'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1319 'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1320 'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1321 'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1322 'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1323 'autosave' => array('integer', (int) $this->getAutosave()),
1324 'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1325 'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1326 'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1327 'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1328 'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1329 'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1330 'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1331 'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1332 'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1333 'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1334 'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1335 'question_set_type' => array('text', $this->getQuestionSetType()),
1336 'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1337 'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1338 'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1339 'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1340 'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1341 'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1342 'follow_qst_answer_fixation' => array('integer', (int) $this->isFollowupQuestionAnswerFixationEnabled()),
1343 'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1344 'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1345 'broken' => array('integer', (int) $this->isTestFinalBroken()),
1346 'pass_waiting' => array('text', (string) $this->getPassWaiting())
1347 ));
1348
1349 $this->test_id = $next_id;
1350
1352 $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1353 }
1354 } else {
1355 // Modify existing dataset
1356 $oldrow = array();
1358 $result = $ilDB->queryF(
1359 "SELECT * FROM tst_tests WHERE test_id = %s",
1360 array('integer'),
1361 array($this->test_id)
1362 );
1363 if ($result->numRows() == 1) {
1364 $oldrow = $ilDB->fetchAssoc($result);
1365 }
1366 }
1367
1368 $ilDB->update(
1369 'tst_tests',
1370 array(
1371 'author' => array('text', $this->getAuthor()),
1372 'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1373 'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1374 'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1375 'showinfo' => array('integer', $this->getShowInfo()),
1376 'forcejs' => array('integer', $this->getForceJS()),
1377 'customstyle' => array('text', $this->getCustomStyle()),
1378 'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1379 'sequence_settings' => array('integer', $this->getSequenceSettings()),
1380 'score_reporting' => array('integer', $this->getScoreReporting()),
1381 'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1382 'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1383 'answer_feedback' => array('text', $this->getGenericAnswerFeedback()),
1384 'anonymity' => array('text', $this->getAnonymity()),
1385 'show_cancel' => array('text', $this->getShowCancel()),
1386 'show_marker' => array('integer', $this->getShowMarker()),
1387 'fixed_participants' => array('text', $this->getFixedParticipants()),
1388 'nr_of_tries' => array('integer', $this->getNrOfTries()),
1389 'block_after_passed' => array('integer', (int) $this->isBlockPassesAfterPassedEnabled()),
1390 'kiosk' => array('integer', $this->getKiosk()),
1391 'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1392 'title_output' => array('text', $this->getTitleOutput()),
1393 'processing_time' => array('text', $this->getProcessingTime()),
1394 'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1395 'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1396 'reporting_date' => array('text', $this->getReportingDate()),
1397 'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1398 'starting_time' => array('integer', $this->getStartingTime()),
1399 'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1400 'ending_time' => array('integer', $this->getEndingTime()),
1401 'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1402 'ects_output' => array('text', $this->getECTSOutput()),
1403 'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1404 'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1405 'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1406 'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1407 'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1408 'ects_fx' => array('float', $this->getECTSFX()),
1409 'count_system' => array('text', $this->getCountSystem()),
1410 'mc_scoring' => array('text', $this->getMCScoring()),
1411 'score_cutting' => array('text', $this->getScoreCutting()),
1412 'pass_scoring' => array('text', $this->getPassScoring()),
1413 'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1414 'results_presentation' => array('integer', $this->getResultsPresentation()),
1415 'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1416 'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1417 'password' => array('text', $this->getPassword()),
1418 'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1419 'allowedusers' => array('integer', $this->getAllowedUsers()),
1420 'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1421 'mailnottype' => array('integer', $this->getMailNotificationType()),
1422 'exportsettings' => array('integer', $this->getExportSettings()),
1423 'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1424 'mailnotification' => array('integer', $this->getMailNotification()),
1425 'tstamp' => array('integer', time()),
1426 'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1427 'template_id' => array('integer', $this->getTemplate()),
1428 'pool_usage' => array('integer', $this->getPoolUsage()),
1429 'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1430 'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1431 'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1432 'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1433 'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1434 'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1435 'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1436 'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1437 'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1438 'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1439 'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1440 'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1441 'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1442 'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1443 'autosave' => array('integer', (int) $this->getAutosave()),
1444 'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1445 'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1446 'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1447 'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1448 'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1449 'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1450 'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1451 'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1452 'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1453 'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1454 'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1455 'question_set_type' => array('text', $this->getQuestionSetType()),
1456 'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1457 'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1458 'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1459 'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1460 'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1461 'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1462 'follow_qst_answer_fixation' => array('integer', (int) $this->isFollowupQuestionAnswerFixationEnabled()),
1463 'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1464 'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1465 'broken' => array('integer', (int) $this->isTestFinalBroken()),
1466 'pass_waiting' => array('text', (string) $this->getPassWaiting())
1467 ),
1468 array(
1469 'test_id' => array('integer', (int) $this->getTestId())
1470 )
1471 );
1472
1473 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1475 $logresult = $ilDB->queryF(
1476 "SELECT * FROM tst_tests WHERE test_id = %s",
1477 array('integer'),
1478 array($this->getTestId())
1479 );
1480 $newrow = array();
1481 if ($logresult->numRows() == 1) {
1482 $newrow = $ilDB->fetchAssoc($logresult);
1483 }
1484 $changed_fields = array();
1485 foreach ($oldrow as $key => $value) {
1486 if (strcmp($oldrow[$key], $newrow[$key]) != 0) {
1487 array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1488 }
1489 }
1490 $changes = join(", ", $changed_fields);
1491 if (count($changed_fields) > 0) {
1492 $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [" . $changes . "]");
1493 }
1494 }
1495 if ($this->evalTotalPersons() > 0) {
1496 // reset the finished status of participants if the nr of test passes did change
1497 if ($this->getNrOfTries() > 0) {
1498 // set all unfinished tests with nr of passes >= allowed passes finished
1499 $aresult = $ilDB->queryF(
1500 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
1501 array('integer', 'integer', 'integer'),
1502 array($this->getTestId(), $this->getNrOfTries(), 0)
1503 );
1504 while ($row = $ilDB->fetchAssoc($aresult)) {
1505 $ilDB->manipulateF(
1506 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1507 array('integer', 'timestamp', 'integer'),
1508 array(1, date('Y-m-d H:i:s'), $row["active_id"])
1509 );
1510 }
1511
1512 // set all finished tests with nr of passes < allowed passes not finished
1513 $aresult = $ilDB->queryF(
1514 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
1515 array('integer', 'integer', 'integer'),
1516 array($this->getTestId(), $this->getNrOfTries() - 1, 1)
1517 );
1518 while ($row = $ilDB->fetchAssoc($aresult)) {
1519 $ilDB->manipulateF(
1520 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1521 array('integer', 'timestamp', 'integer'),
1522 array(0, null, $row["active_id"])
1523 );
1524 }
1525 } else {
1526 // set all finished tests with nr of passes >= allowed passes not finished
1527 $aresult = $ilDB->queryF(
1528 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
1529 array('integer', 'integer'),
1530 array($this->getTestId(), 1)
1531 );
1532 while ($row = $ilDB->fetchAssoc($aresult)) {
1533 $ilDB->manipulateF(
1534 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1535 array('integer', 'timestamp', 'integer'),
1536 array(0, null, $row["active_id"])
1537 );
1538 }
1539 }
1540 }
1541 }
1542
1543 // news item creation/update/deletion
1544 include_once 'Services/News/classes/class.ilNewsItem.php';
1545 if (!$this->getOldOnlineStatus() && !$this->getOfflineStatus()) {
1546 global $DIC;
1547 $ilUser = $DIC['ilUser'];
1548 $newsItem = new ilNewsItem();
1549 $newsItem->setContext($this->getId(), 'tst');
1550 $newsItem->setPriority(NEWS_NOTICE);
1551 $newsItem->setTitle('new_test_online');
1552 $newsItem->setContentIsLangVar(true);
1553 $newsItem->setContent('');
1554 $newsItem->setUserId($ilUser->getId());
1555 $newsItem->setVisibility(NEWS_USERS);
1556 $newsItem->create();
1557 } elseif ($this->getOldOnlineStatus() && !$this->getOfflineStatus()) {
1558 ilNewsItem::deleteNewsOfContext($this->getId(), 'tst');
1559 } elseif (!$this->getOfflineStatus()) {
1560 $newsId = ilNewsItem::getFirstNewsIdForContext($this->getId(), 'tst');
1561 if ($newsId > 0) {
1562 $newsItem = new ilNewsItem($newsId);
1563 $newsItem->setTitle('new_test_online');
1564 $newsItem->setContentIsLangVar(true);
1565 $newsItem->setContent('');
1566 $newsItem->update();
1567 }
1568 }
1569
1570 // moved activation to ilObjectActivation
1571 if ($this->ref_id) {
1572 include_once "./Services/Object/classes/class.ilObjectActivation.php";
1573 ilObjectActivation::getItem($this->ref_id);
1574
1575 $item = new ilObjectActivation;
1576 if (!$this->isActivationLimited()) {
1578 } else {
1579 $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
1580 $item->setTimingStart($this->getActivationStartingTime());
1581 $item->setTimingEnd($this->getActivationEndingTime());
1582 $item->toggleVisible($this->getActivationVisibility());
1583 }
1584
1585 $item->update($this->ref_id);
1586 }
1587
1588 if (!$properties_only) {
1589 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
1590 $this->saveQuestionsToDb();
1591 }
1592
1593 $this->mark_schema->saveToDb($this->test_id);
1594 }
1595 }
1596
1603 public function saveQuestionsToDb()
1604 {
1605 global $DIC;
1606 $ilDB = $DIC['ilDB'];
1607
1608 $oldquestions = array();
1609 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1611 $result = $ilDB->queryF(
1612 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1613 array('integer'),
1614 array($this->getTestId())
1615 );
1616 if ($result->numRows() > 0) {
1617 while ($row = $ilDB->fetchAssoc($result)) {
1618 array_push($oldquestions, $row["question_fi"]);
1619 }
1620 }
1621 }
1622 // workaround for lost obligations
1623 // this method is called if a question is removed
1624 $currentQuestionsObligationsQuery = 'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
1625 $rset = $ilDB->queryF($currentQuestionsObligationsQuery, array('integer'), array($this->getTestId()));
1626 while ($row = $ilDB->fetchAssoc($rset)) {
1627 $obligatoryQuestionState[$row['question_fi']] = $row['obligatory'];
1628 }
1629 // delete existing category relations
1630 $affectedRows = $ilDB->manipulateF(
1631 "DELETE FROM tst_test_question WHERE test_fi = %s",
1632 array('integer'),
1633 array($this->getTestId())
1634 );
1635 // create new category relations
1636 foreach ($this->questions as $key => $value) {
1637 // workaround for import witout obligations information
1638 if (!isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value])) {
1639 $obligatoryQuestionState[$value] = 0;
1640 }
1641
1642 // insert question
1643 $next_id = $ilDB->nextId('tst_test_question');
1644 $ilDB->insert('tst_test_question', array(
1645 'test_question_id' => array('integer', $next_id),
1646 'test_fi' => array('integer', $this->getTestId()),
1647 'question_fi' => array('integer', $value),
1648 'sequence' => array('integer', $key),
1649 'obligatory' => array('integer', $obligatoryQuestionState[$value]),
1650 'tstamp' => array('integer', time())
1651 ));
1652 }
1653 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1655 $result = $ilDB->queryF(
1656 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1657 array('integer'),
1658 array($this->getTestId())
1659 );
1660 $newquestions = array();
1661 if ($result->numRows() > 0) {
1662 while ($row = $ilDB->fetchAssoc($result)) {
1663 array_push($newquestions, $row["question_fi"]);
1664 }
1665 }
1666 foreach ($oldquestions as $index => $question_id) {
1667 if (strcmp($newquestions[$index], $question_id) != 0) {
1668 $pos = array_search($question_id, $newquestions);
1669 if ($pos === false) {
1670 $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1671 } else {
1672 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index + 1) . " => " . ($pos + 1), $question_id);
1673 }
1674 }
1675 }
1676 foreach ($newquestions as $index => $question_id) {
1677 if (array_search($question_id, $oldquestions) === false) {
1678 $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index + 1), $question_id);
1679 }
1680 }
1681 }
1682 }
1683
1689 protected function isNewRandomTest()
1690 {
1691 global $DIC;
1692 $ilDB = $DIC['ilDB'];
1693 $result = $ilDB->queryF(
1694 'SELECT copy_id FROM tst_rnd_cpy WHERE tst_fi = %s',
1695 array('integer'),
1696 array($this->getTestId())
1697 );
1698 return $result->numRows() > 0;
1699 }
1700
1713 public function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = null)
1714 {
1715 global $DIC;
1716 $rbacsystem = $DIC['rbacsystem'];
1717 $ilDB = $DIC['ilDB'];
1718
1719 // retrieve object id instead of ref id if necessary
1720 if (($questionpool != 0) && (!$use_obj_id)) {
1721 $questionpool = ilObject::_lookupObjId($questionpool);
1722 }
1723
1724 // get original ids of all existing questions in the test
1725 $result = $ilDB->queryF(
1726 "SELECT qpl_questions.original_id FROM qpl_questions, tst_test_question WHERE qpl_questions.question_id = tst_test_question.question_fi AND qpl_questions.tstamp > 0 AND tst_test_question.test_fi = %s",
1727 array("integer"),
1728 array($this->getTestId())
1729 );
1730 $original_ids = array();
1731 $paramtypes = array();
1732 $paramvalues = array();
1733 while ($row = $ilDB->fetchAssoc($result)) {
1734 array_push($original_ids, $row['original_id']);
1735 }
1736
1737 $available = "";
1738 // get a list of all available questionpools
1739 if (($questionpool == 0) && (!is_array($qpls))) {
1740 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1741 $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = true, $equal_points = false, $could_be_offline = false, $showPath = false, $with_questioncount = false, "read", ilObject::_lookupOwner($this->getId())));
1742 if (count($available_pools)) {
1743 $available = " AND " . $ilDB->in('obj_fi', $available_pools, false, 'integer');
1744 } else {
1745 return array();
1746 }
1747 }
1748
1749 $constraint_qpls = "";
1750 $result_array = array();
1751 if ($questionpool == 0) {
1752 if (is_array($qpls)) {
1753 if (count($qpls) > 0) {
1754 $constraint_qpls = " AND " . $ilDB->in('obj_fi', $qpls, false, 'integer');
1755 }
1756 }
1757 }
1758
1759 $original_clause = "";
1760 if (count($original_ids)) {
1761 $original_clause = " AND " . $ilDB->in('question_id', $original_ids, true, 'integer');
1762 }
1763
1764 if ($questionpool == 0) {
1765 $result = $ilDB->queryF(
1766 "SELECT question_id FROM qpl_questions WHERE original_id IS NULL $available $constraint_qpls AND owner > %s AND complete = %s $original_clause",
1767 array('integer', 'text'),
1768 array(0, "1")
1769 );
1770 } else {
1771 $result = $ilDB->queryF(
1772 "SELECT question_id FROM qpl_questions WHERE original_id IS NULL AND obj_fi = %s AND owner > %s AND complete = %s $original_clause",
1773 array('integer','integer', 'text'),
1774 array($questionpool, 0, "1")
1775 );
1776 }
1777 $found_ids = array();
1778 while ($row = $ilDB->fetchAssoc($result)) {
1779 array_push($found_ids, $row['question_id']);
1780 }
1781 $nr_of_questions = ($nr_of_questions > count($found_ids)) ? count($found_ids) : $nr_of_questions;
1782 if ($nr_of_questions == 0) {
1783 return array();
1784 }
1785 $rand_keys = array_rand($found_ids, $nr_of_questions);
1786 $result = array();
1787 if (is_array($rand_keys)) {
1788 foreach ($rand_keys as $key) {
1789 $result[$found_ids[$key]] = $found_ids[$key];
1790 }
1791 } else {
1792 $result[$found_ids[$rand_keys]] = $found_ids[$rand_keys];
1793 }
1794 return $result;
1795 }
1796
1804 public function getNrOfResultsForPass($active_id, $pass)
1805 {
1806 global $DIC;
1807 $ilDB = $DIC['ilDB'];
1808
1809 $result = $ilDB->queryF(
1810 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1811 array('integer','integer'),
1812 array($active_id, $pass)
1813 );
1814 return $result->numRows();
1815 }
1816
1827 public function hasRandomQuestionsForPass($active_id, $pass)
1828 {
1829 global $DIC;
1830 $ilDB = $DIC['ilDB'];
1831 $result = $ilDB->queryF(
1832 "SELECT test_random_question_id FROM tst_test_rnd_qst WHERE active_fi = %s AND pass = %s",
1833 array('integer','integer'),
1834 array($active_id, $pass)
1835 );
1836 return ($result->numRows() > 0) ? true : false;
1837 }
1838
1842 public function loadFromDb()
1843 {
1844 global $DIC;
1845 $ilDB = $DIC['ilDB'];
1846
1847 $result = $ilDB->queryF(
1848 "SELECT * FROM tst_tests WHERE obj_fi = %s",
1849 array('integer'),
1850 array($this->getId())
1851 );
1852 if ($result->numRows() == 1) {
1853 $data = $ilDB->fetchObject($result);
1854 $this->setTestId($data->test_id);
1855 if (strlen($this->getAuthor()) == 0) {
1856 $this->saveAuthorToMetadata($data->author);
1857 }
1858 $this->setAuthor($data->author);
1859 include_once("./Services/RTE/classes/class.ilRTE.php");
1860 $this->setIntroductionEnabled($data->intro_enabled);
1862 $this->setShowInfo($data->showinfo);
1864 $this->setForceJS($data->forcejs);
1865 $this->setCustomStyle($data->customstyle);
1866 $this->setShowFinalStatement($data->showfinalstatement);
1867 $this->setSequenceSettings($data->sequence_settings);
1868 $this->setScoreReporting($data->score_reporting);
1869 $this->setInstantFeedbackSolution($data->instant_verification);
1870 $this->setAnswerFeedbackPoints($data->answer_feedback_points);
1871 $this->setAnswerFeedback($data->answer_feedback);
1872 $this->setAnonymity($data->anonymity);
1873 $this->setShowCancel($data->show_cancel);
1874 $this->setShowMarker($data->show_marker);
1875 $this->setFixedParticipants($data->fixed_participants);
1876 $this->setNrOfTries($data->nr_of_tries);
1877 $this->setBlockPassesAfterPassedEnabled((bool) $data->block_after_passed);
1878 $this->setKiosk($data->kiosk);
1879 $this->setUsePreviousAnswers($data->use_previous_answers);
1880 $this->setRedirectionMode($data->redirection_mode);
1881 $this->setRedirectionUrl($data->redirection_url);
1882 $this->setTitleOutput($data->title_output);
1883 $this->setProcessingTime($data->processing_time);
1884 $this->setEnableProcessingTime($data->enable_processing_time);
1885 $this->setResetProcessingTime($data->reset_processing_time);
1886 $this->setReportingDate($data->reporting_date);
1887 $this->setShuffleQuestions($data->shuffle_questions);
1888 $this->setResultsPresentation($data->results_presentation);
1889 $this->setStartingTimeEnabled($data->starting_time_enabled);
1890 $this->setStartingTime($data->starting_time);
1891 $this->setEndingTimeEnabled($data->ending_time_enabled);
1892 $this->setEndingTime($data->ending_time);
1893 $this->setListOfQuestionsSettings($data->show_summary);
1894 $this->setECTSOutput($data->ects_output);
1895 $this->setECTSGrades(
1896 array(
1897 "A" => $data->ects_a,
1898 "B" => $data->ects_b,
1899 "C" => $data->ects_c,
1900 "D" => $data->ects_d,
1901 "E" => $data->ects_e
1902 )
1903 );
1904 $this->setECTSFX($data->ects_fx);
1905 $this->mark_schema->flush();
1906 $this->mark_schema->loadFromDb($this->getTestId());
1907 $this->setCountSystem($data->count_system);
1908 $this->setMCScoring($data->mc_scoring);
1909 $this->setMailNotification($data->mailnotification);
1910 $this->setMailNotificationType($data->mailnottype);
1911 $this->setExportSettings($data->exportsettings);
1912 $this->setScoreCutting($data->score_cutting);
1913 $this->setPasswordEnabled($data->password_enabled);
1914 $this->setPassword($data->password);
1915 $this->setLimitUsersEnabled($data->limit_users_enabled);
1916 $this->setAllowedUsers($data->allowedusers);
1917 $this->setAllowedUsersTimeGap($data->alloweduserstimegap);
1918 $this->setPassScoring($data->pass_scoring);
1919 $this->setObligationsEnabled($data->obligations_enabled);
1920 $this->setOfferingQuestionHintsEnabled($data->offer_question_hints);
1921 $this->setCertificateVisibility($data->certificate_visibility);
1922 $this->setEnabledViewMode($data->enabled_view_mode);
1923 $this->setTemplate($data->template_id);
1924 $this->setPoolUsage($data->pool_usage);
1925 $this->setPrintBestSolutionWithResult((bool) $data->print_bs_with_res);
1926 $this->setHighscoreEnabled((bool) $data->highscore_enabled);
1927 $this->setHighscoreAnon((bool) $data->highscore_anon);
1928 $this->setHighscoreAchievedTS((bool) $data->highscore_achieved_ts);
1929 $this->setHighscoreScore((bool) $data->highscore_score);
1930 $this->setHighscorePercentage((bool) $data->highscore_percentage);
1931 $this->setHighscoreHints((bool) $data->highscore_hints);
1932 $this->setHighscoreWTime((bool) $data->highscore_wtime);
1933 $this->setHighscoreOwnTable((bool) $data->highscore_own_table);
1934 $this->setHighscoreTopTable((bool) $data->highscore_top_table);
1935 $this->setHighscoreTopNum((int) $data->highscore_top_num);
1936 $this->setOldOnlineStatus((bool) !$this->getOfflineStatus());
1937 $this->setSpecificAnswerFeedback((int) $data->specific_feedback);
1938 $this->setAutosave((bool) $data->autosave);
1939 $this->setAutosaveIval((int) $data->autosave_ival);
1940 $this->setPassDeletionAllowed($data->pass_deletion_allowed);
1941 $this->setEnableExamview((bool) $data->enable_examview);
1942 $this->setShowExamviewHtml((bool) $data->show_examview_html);
1943 $this->setShowExamviewPdf((bool) $data->show_examview_pdf);
1944 $this->setEnableArchiving((bool) $data->enable_archiving);
1945 $this->setShowExamIdInTestPassEnabled((bool) $data->examid_in_test_pass);
1946 $this->setShowExamIdInTestResultsEnabled((bool) $data->examid_in_test_res);
1947 $this->setSignSubmission((bool) $data->sign_submission);
1948 $this->setQuestionSetType($data->question_set_type);
1949 $this->setCharSelectorAvailability((int) $data->char_selector_availability);
1950 $this->setCharSelectorDefinition($data->char_selector_definition);
1951 $this->setSkillServiceEnabled((bool) $data->skill_service);
1952 $this->setResultFilterTaxIds(strlen($data->result_tax_filters) ? unserialize($data->result_tax_filters) : array());
1953 $this->setShowGradingStatusEnabled((bool) $data->show_grading_status);
1954 $this->setShowGradingMarkEnabled((bool) $data->show_grading_mark);
1955 $this->setFollowupQuestionAnswerFixationEnabled((bool) $data->follow_qst_answer_fixation);
1956 $this->setInstantFeedbackAnswerFixationEnabled((bool) $data->inst_fb_answer_fixation);
1957 $this->setForceInstantFeedbackEnabled((bool) $data->force_inst_fb);
1958 $this->setTestFinalBroken((bool) $data->broken);
1959 $this->setPassWaiting($data->pass_waiting);
1960 $this->loadQuestions();
1961 }
1962
1963 // moved activation to ilObjectActivation
1964 if ($this->ref_id) {
1965 include_once "./Services/Object/classes/class.ilObjectActivation.php";
1966 $activation = ilObjectActivation::getItem($this->ref_id);
1967 switch ($activation["timing_type"]) {
1969 $this->setActivationLimited(true);
1970 $this->setActivationStartingTime($activation["timing_start"]);
1971 $this->setActivationEndingTime($activation["timing_end"]);
1972 $this->setActivationVisibility($activation["visible"]);
1973 break;
1974
1975 default:
1976 $this->setActivationLimited(false);
1977 break;
1978 }
1979 }
1980 }
1981
1988 public function loadQuestions($active_id = "", $pass = null)
1989 {
1990 global $DIC;
1991 $ilUser = $DIC['ilUser'];
1992 $ilDB = $DIC['ilDB'];
1993
1994 $this->questions = array();
1995 if ($this->isRandomTest()) {
1996 if (strcmp($active_id, "") == 0) {
1997 $active_id = $this->getActiveIdOfUser($ilUser->getId());
1998 }
1999 if (is_null($pass)) {
2000 $pass = self::_getPass($active_id);
2001 }
2002 $result = $ilDB->queryF(
2003 "SELECT tst_test_rnd_qst.* FROM tst_test_rnd_qst, qpl_questions WHERE tst_test_rnd_qst.active_fi = %s AND qpl_questions.question_id = tst_test_rnd_qst.question_fi AND tst_test_rnd_qst.pass = %s ORDER BY sequence",
2004 array('integer', 'integer'),
2005 array($active_id, $pass)
2006 );
2007 // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
2008 // is only one test pass (pass = 0) in tst_test_rnd_qst while with ILIAS 3.8 there are questions for every test pass.
2009 // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
2010 // no questions are present for a newer pass.
2011 if ($result->numRows() == 0) {
2012 $result = $ilDB->queryF(
2013 "SELECT tst_test_rnd_qst.* FROM tst_test_rnd_qst, qpl_questions WHERE tst_test_rnd_qst.active_fi = %s AND qpl_questions.question_id = tst_test_rnd_qst.question_fi AND tst_test_rnd_qst.pass = 0 ORDER BY sequence",
2014 array('integer'),
2015 array($active_id)
2016 );
2017 }
2018 } else {
2019 $result = $ilDB->queryF(
2020 "SELECT tst_test_question.* FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND qpl_questions.question_id = tst_test_question.question_fi ORDER BY sequence",
2021 array('integer'),
2022 array($this->test_id)
2023 );
2024 }
2025 $index = 1;
2026 while ($data = $ilDB->fetchAssoc($result)) {
2027 $this->questions[$index++] = $data["question_fi"];
2028 }
2029 }
2030
2034 public function isIntroductionEnabled()
2035 {
2037 }
2038
2043 {
2044 $this->introductionEnabled = $introductionEnabled;
2045 }
2046
2053 public function getIntroduction()
2054 {
2055 return (strlen($this->introduction)) ? $this->introduction : null;
2056 }
2057
2065 public function setIntroduction($introduction = "")
2066 {
2067 if (is_null($introduction)) {
2068 $introduction = '';
2069 }
2070 $this->introduction = $this->getHtmlQuestionContentPurifier()->purify($introduction);
2071 }
2072
2073
2081 public function setFinalStatement($a_statement = "")
2082 {
2083 if (is_null($a_statement)) {
2084 $a_statement = '';
2085 }
2086 $this->_finalstatement = $this->getHtmlQuestionContentPurifier()->purify($a_statement);
2087 }
2088
2096 public function setShowInfo($a_info = 1)
2097 {
2098 $this->_showinfo = ($a_info) ? 1 : 0;
2099 }
2100
2108 public function setForceJS($a_js = 1)
2109 {
2110 $this->_forcejs = ($a_js) ? 1 : 0;
2111 }
2112
2120 public function setCustomStyle($a_customStyle = null)
2121 {
2122 $this->_customStyle = $a_customStyle;
2123 }
2124
2132 public function getCustomStyle()
2133 {
2134 return (strlen($this->_customStyle)) ? $this->_customStyle : null;
2135 }
2136
2144 public function getCustomStyles()
2145 {
2146 $css_path = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2147 $css_path = str_replace("ta.css", "customstyles", $css_path) . "/";
2148 $customstyles = array();
2149 if (is_dir($css_path)) {
2150 $results = array();
2151 include_once "./Services/Utilities/classes/class.ilFileUtils.php";
2153 if (is_array($results["file"])) {
2154 foreach ($results["file"] as $filename) {
2155 if (strpos($filename, ".css")) {
2156 array_push($customstyles, $filename);
2157 }
2158 }
2159 }
2160 }
2161 return $customstyles;
2162 }
2163
2171 public function getTestStyleLocation($mode = "output")
2172 {
2173 if (strlen($this->getCustomStyle())) {
2174 $default = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2175 $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $default);
2176 if (file_exists($custom)) {
2177 $custom = ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2178 $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $custom);
2179 return $custom;
2180 } else {
2181 return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2182 }
2183 } else {
2184 return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2185 }
2186 }
2187
2195 public function setShowFinalStatement($show = 0)
2196 {
2197 $this->_showfinalstatement = ($show) ? 1 : 0;
2198 }
2199
2206 public function getFinalStatement()
2207 {
2208 return (strlen($this->_finalstatement)) ? $this->_finalstatement : null;
2209 }
2210
2218 public function getShowInfo()
2219 {
2220 return ($this->_showinfo) ? 1 : 0;
2221 }
2222
2230 public function getForceJS()
2231 {
2232 return ($this->_forcejs) ? 1 : 0;
2233 }
2234
2242 public function getShowFinalStatement()
2243 {
2244 return ($this->_showfinalstatement) ? 1 : 0;
2245 }
2246
2254 public function getTestId()
2255 {
2256 return $this->test_id;
2257 }
2258
2262 public function getECTSOutput()
2263 {
2264 return ($this->ects_output) ? 1 : 0;
2265 }
2266
2270 public function setECTSOutput($a_ects_output)
2271 {
2272 $this->ects_output = $a_ects_output ? 1 : 0;
2273 }
2274
2278 public function getECTSFX()
2279 {
2280 return (strlen($this->ects_fx)) ? $this->ects_fx : null;
2281 }
2282
2286 public function setECTSFX($a_ects_fx)
2287 {
2288 $this->ects_fx = $a_ects_fx;
2289 }
2290
2294 public function getECTSGrades()
2295 {
2296 return $this->ects_grades;
2297 }
2298
2302 public function setECTSGrades(array $a_ects_grades)
2303 {
2304 $this->ects_grades = $a_ects_grades;
2305 }
2306
2312 public function getSequenceSettings()
2313 {
2314 return ($this->sequence_settings) ? $this->sequence_settings : 0;
2315 }
2316
2323 {
2324 $this->sequence_settings = $sequence_settings;
2325 }
2326
2330 public function isPostponingEnabled()
2331 {
2332 return (bool) $this->getSequenceSettings();
2333 }
2334
2338 public function setPostponingEnabled($postponingEnabled)
2339 {
2340 $this->setSequenceSettings((int) $postponingEnabled);
2341 }
2342
2351 {
2352 $this->score_reporting = $score_reporting;
2353 }
2354
2362 public function setInstantFeedbackSolution($instant_feedback = 0)
2363 {
2364 switch ($instant_feedback) {
2365 case 1:
2366 $this->instant_verification = 1;
2367 break;
2368 default:
2369 $this->instant_verification = 0;
2370 break;
2371 }
2372 }
2373
2382 {
2383 switch ($answer_feedback) {
2384 case 1:
2385 $this->answer_feedback = 1;
2386 break;
2387 default:
2388 $this->answer_feedback = 0;
2389 break;
2390 }
2391 }
2392
2398 public function setGenericAnswerFeedback($generic_answer_feedback = 0)
2399 {
2400 switch ($generic_answer_feedback) {
2401 case 1:
2402 $this->answer_feedback = 1;
2403 break;
2404 default:
2405 $this->answer_feedback = 0;
2406 break;
2407 }
2408 }
2409
2418 {
2419 switch ($answer_feedback_points) {
2420 case 1:
2421 $this->answer_feedback_points = 1;
2422 break;
2423 default:
2424 $this->answer_feedback_points = 0;
2425 break;
2426 }
2427 }
2428
2434 {
2435 if (!$reporting_date) {
2436 $this->reporting_date = '';
2437 $this->setECTSOutput(false);
2438 } else {
2439 $this->reporting_date = $reporting_date;
2440 }
2441 }
2442
2448
2456 public function getScoreReporting()
2457 {
2458 return ($this->score_reporting) ? $this->score_reporting : 0;
2459 }
2460
2461 public function isScoreReportingEnabled()
2462 {
2463 switch ($this->getScoreReporting()) {
2468
2469 return true;
2470
2472 default:
2473
2474 return false;
2475 }
2476 }
2477
2486 {
2487 return ($this->instant_verification) ? $this->instant_verification : 0;
2488 }
2489
2498 public function getAnswerFeedback()
2499 {
2500 return ($this->answer_feedback) ? $this->answer_feedback : 0;
2501 }
2502
2510 {
2511 return ($this->answer_feedback) ? $this->answer_feedback : 0;
2512 }
2513
2521 public function getAnswerFeedbackPoints()
2522 {
2523 return ($this->answer_feedback_points) ? $this->answer_feedback_points : 0;
2524 }
2525
2533 public function getCountSystem()
2534 {
2535 return ($this->count_system) ? $this->count_system : 0;
2536 }
2537
2545 public static function _getCountSystem($active_id)
2546 {
2547 global $DIC;
2548 $ilDB = $DIC['ilDB'];
2549 $result = $ilDB->queryF(
2550 "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",
2551 array('integer'),
2552 array($active_id)
2553 );
2554 if ($result->numRows()) {
2555 $row = $ilDB->fetchAssoc($result);
2556 return $row["count_system"];
2557 }
2558 return false;
2559 }
2560
2568 public function getMCScoring()
2569 {
2570 return ($this->mc_scoring) ? $this->mc_scoring : 0;
2571 }
2572
2580 public function getScoreCutting()
2581 {
2582 return ($this->score_cutting) ? $this->score_cutting : 0;
2583 }
2584
2592 public function getPassScoring()
2593 {
2594 return ($this->pass_scoring) ? $this->pass_scoring : 0;
2595 }
2596
2604 public static function _getPassScoring($active_id)
2605 {
2606 global $DIC;
2607 $ilDB = $DIC['ilDB'];
2608 $result = $ilDB->queryF(
2609 "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",
2610 array('integer'),
2611 array($active_id)
2612 );
2613 if ($result->numRows()) {
2614 $row = $ilDB->fetchAssoc($result);
2615 return $row["pass_scoring"];
2616 }
2617 return 0;
2618 }
2619
2627 public static function _getMCScoring($active_id)
2628 {
2629 global $DIC;
2630 $ilDB = $DIC['ilDB'];
2631 $result = $ilDB->queryF(
2632 "SELECT tst_tests.mc_scoring FROM tst_tests, tst_active WHERE tst_active.active_id = %s AND tst_active.test_fi = tst_tests.test_id",
2633 array('integer'),
2634 array($active_id)
2635 );
2636 if ($result->numRows()) {
2637 $row = $ilDB->fetchAssoc($result);
2638 return $row["mc_scoring"];
2639 }
2640 return false;
2641 }
2642
2650 public static function _getScoreCutting($active_id)
2651 {
2652 global $DIC;
2653 $ilDB = $DIC['ilDB'];
2654 $result = $ilDB->queryF(
2655 "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",
2656 array('integer'),
2657 array($active_id)
2658 );
2659 if ($result->numRows()) {
2660 $row = $ilDB->fetchAssoc($result);
2661 return $row["score_cutting"];
2662 }
2663 return false;
2664 }
2665
2673 public function getReportingDate()
2674 {
2675 return (strlen($this->reporting_date)) ? $this->reporting_date : null;
2676 }
2677
2685 public function getNrOfTries()
2686 {
2687 return ($this->nr_of_tries) ? $this->nr_of_tries : 0;
2688 }
2689
2694 {
2696 }
2697
2702 {
2703 $this->blockPassesAfterPassedEnabled = $blockPassesAfterPassedEnabled;
2704 }
2705
2713 public function getKiosk()
2714 {
2715 return ($this->_kiosk) ? $this->_kiosk : 0;
2716 }
2717
2718
2726 public function setKiosk($kiosk = 0)
2727 {
2728 $this->_kiosk = $kiosk;
2729 }
2730
2738 public function getKioskMode()
2739 {
2740 if (($this->_kiosk & 1) > 0) {
2741 return true;
2742 } else {
2743 return false;
2744 }
2745 }
2746
2754 public function setKioskMode($a_kiosk = false)
2755 {
2756 if ($a_kiosk) {
2757 $this->_kiosk = $this->_kiosk | 1;
2758 } else {
2759 if ($this->getKioskMode()) {
2760 $this->_kiosk = $this->_kiosk ^ 1;
2761 }
2762 }
2763 }
2764
2772 public function getShowKioskModeTitle()
2773 {
2774 if (($this->_kiosk & 2) > 0) {
2775 return true;
2776 } else {
2777 return false;
2778 }
2779 }
2780
2787 public function setShowKioskModeTitle($a_title = false)
2788 {
2789 if ($a_title) {
2790 $this->_kiosk = $this->_kiosk | 2;
2791 } else {
2792 if ($this->getShowKioskModeTitle()) {
2793 $this->_kiosk = $this->_kiosk ^ 2;
2794 }
2795 }
2796 }
2797
2806 {
2807 if (($this->_kiosk & 4) > 0) {
2808 return true;
2809 } else {
2810 return false;
2811 }
2812 }
2813
2820 public function setShowKioskModeParticipant($a_participant = false)
2821 {
2822 if ($a_participant) {
2823 $this->_kiosk = $this->_kiosk | 4;
2824 } else {
2825 if ($this->getShowKioskModeParticipant()) {
2826 $this->_kiosk = $this->_kiosk ^ 4;
2827 }
2828 }
2829 }
2830
2838 public function getUsePreviousAnswers()
2839 {
2840 return ($this->use_previous_answers) ? $this->use_previous_answers : 0;
2841 }
2842
2850 public function getTitleOutput()
2851 {
2852 return ($this->title_output) ? $this->title_output : 0;
2853 }
2854
2863 public function _getTitleOutput($active_id)
2864 {
2865 global $DIC;
2866 $ilDB = $DIC['ilDB'];
2867
2868 $result = $ilDB->queryF(
2869 "SELECT tst_tests.title_output FROM tst_tests, tst_active WHERE tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s",
2870 array('integer'),
2871 array($active_id)
2872 );
2873 if ($result->numRows()) {
2874 $row = $ilDB->fetchAssoc($result);
2875 return $row["title_output"];
2876 }
2877 return 0;
2878 }
2879
2880 // hey: prevPassSolutions - serious (nonstatic) identifier, for use in high level controller gui
2881 public function isPreviousSolutionReuseEnabled($activeId)
2882 {
2883 // checks if allowed in general and if enabled by participant
2884 return self::_getUsePreviousAnswers($activeId, true);
2885 }
2886 // hey.
2887
2897 public static function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
2898 {
2899 global $DIC;
2900 $ilDB = $DIC['ilDB'];
2901 $ilUser = $DIC['ilUser'];
2902
2904
2905 $result = $ilDB->queryF(
2906 "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",
2907 array("integer"),
2908 array($active_id)
2909 );
2910 if ($result->numRows()) {
2911 $row = $ilDB->fetchAssoc($result);
2912 $use_previous_answers = $row["use_previous_answers"];
2913 }
2914
2915 if ($use_previous_answers == 1) {
2916 if ($user_active_user_setting) {
2917 $res = $ilUser->getPref("tst_use_previous_answers");
2918 if ($res !== false) {
2920 }
2921 }
2922 }
2923 return $use_previous_answers;
2924 }
2925
2933 public function getProcessingTime()
2934 {
2935 return (strlen($this->processing_time)) ? $this->processing_time : null;
2936 }
2937
2945 {
2946 if (strlen($this->processing_time)) {
2947 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2948 if ((int) $matches[1] + (int) $matches[2] + (int) $matches[3] == 0) {
2949 return $this->getEstimatedWorkingTime();
2950 } else {
2951 return array(
2952 'hh' => $matches[1],
2953 'mm' => $matches[2],
2954 'ss' => $matches[3],
2955 );
2956 }
2957 }
2958 }
2959 return $this->getEstimatedWorkingTime();
2960 }
2961
2963 {
2964 if (strlen($this->processing_time)) {
2965 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2966 return ($matches[1] * 60) + $matches[2];
2967 }
2968 }
2969
2971 }
2972
2980 public function getProcessingTimeInSeconds($active_id = "")
2981 {
2982 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches)) {
2983 $extratime = $this->getExtraTime($active_id) * 60;
2984 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
2985 } else {
2986 return 0;
2987 }
2988 }
2989
2998 {
2999 if ($this->getEndingTime() != 0) {
3000 $ending = $this->getEndingTime();
3001 $now = time();
3002 return $ending - $now;
3003 } else {
3004 return 0;
3005 }
3006 }
3007
3015 public function getEnableProcessingTime()
3016 {
3017 return ($this->enable_processing_time) ? $this->enable_processing_time : 0;
3018 }
3019
3027 public function getResetProcessingTime()
3028 {
3029 return ($this->reset_processing_time) ? $this->reset_processing_time : 0;
3030 }
3031
3035 public function isStartingTimeEnabled()
3036 {
3038 }
3039
3044 {
3045 $this->starting_time_enabled = $starting_time_enabled;
3046 }
3047
3055 public function getStartingTime()
3056 {
3057 return ($this->starting_time != 0) ? $this->starting_time : 0;
3058 }
3059
3067 public function setStartingTime($starting_time = null)
3068 {
3069 $this->starting_time = $starting_time;
3070 }
3071
3075 public function isEndingTimeEnabled()
3076 {
3078 }
3079
3084 {
3085 $this->ending_time_enabled = $ending_time_enabled;
3086 }
3087
3095 public function getEndingTime()
3096 {
3097 return ($this->ending_time != 0) ? $this->ending_time : 0;
3098 }
3099
3107 public function setEndingTime($ending_time = null)
3108 {
3109 $this->ending_time = $ending_time;
3110 }
3111
3119 public function setNrOfTries($nr_of_tries = 0)
3120 {
3121 $this->nr_of_tries = $nr_of_tries;
3122 }
3123
3132 {
3134 $this->use_previous_answers = 1;
3135 } else {
3136 $this->use_previous_answers = 0;
3137 }
3138 }
3139
3141 {
3142 $this->redirection_mode = $redirection_mode;
3143 }
3144 public function getRedirectionMode()
3145 {
3147 }
3148 public function setRedirectionUrl($redirection_url = null)
3149 {
3150 $this->redirection_url = $redirection_url;
3151 }
3152 public function getRedirectionUrl()
3153 {
3155 }
3156
3164 public function setTitleOutput($title_output = 0)
3165 {
3166 switch ($title_output) {
3167 case 1:
3168 $this->title_output = 1;
3169 break;
3170 case 2:
3171 $this->title_output = 2;
3172 break;
3173 default:
3174 $this->title_output = 0;
3175 break;
3176 }
3177 }
3178
3186 public function setProcessingTime($processing_time = "00:00:00")
3187 {
3188 $this->processing_time = $processing_time;
3189 }
3190
3191 public function setProcessingTimeByMinutes($minutes)
3192 {
3193 $this->processing_time = sprintf("%02d:%02d:00", floor($minutes / 60), $minutes % 60);
3194 }
3195
3203 public function setEnableProcessingTime($enable = 0)
3204 {
3205 if ($enable) {
3206 $this->enable_processing_time = "1";
3207 } else {
3208 $this->enable_processing_time = "0";
3209 }
3210 }
3211
3219 public function setResetProcessingTime($reset = 0)
3220 {
3221 if ($reset) {
3222 $this->reset_processing_time = 1;
3223 } else {
3224 $this->reset_processing_time = 0;
3225 }
3226 }
3227
3235 public function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3236 {
3237 $this->count_system = $a_count_system;
3238 }
3239
3243 public function isPasswordEnabled()
3244 {
3246 }
3247
3252 {
3253 $this->passwordEnabled = $passwordEnabled;
3254 }
3255
3263 public function getPassword()
3264 {
3265 return (strlen($this->password)) ? $this->password : null;
3266 }
3267
3275 public function setPassword($a_password = null)
3276 {
3277 $this->password = $a_password;
3278 }
3279
3287 public function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3288 {
3289 $this->score_cutting = $a_score_cutting;
3290 }
3291
3299 public function setMCScoring($a_mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED)
3300 {
3301 $this->mc_scoring = $a_mc_scoring;
3302 }
3303
3311 public function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3312 {
3313 switch ($a_pass_scoring) {
3314 case SCORE_BEST_PASS:
3315 $this->pass_scoring = SCORE_BEST_PASS;
3316 break;
3317 default:
3318 $this->pass_scoring = SCORE_LAST_PASS;
3319 break;
3320 }
3321 }
3322
3326 public function getPassWaiting()
3327 {
3328 return $this->pass_waiting;
3329 }
3330
3335 {
3336 $this->pass_waiting = $pass_waiting;
3337 }
3341 public function isPassWaitingEnabled()
3342 {
3343 if (array_sum(explode(':', $this->getPassWaiting())) > 0) {
3344 return true;
3345 }
3346 return false;
3347 }
3348
3354 public function removeQuestionFromSequences($questionId, $activeIds, ilTestReindexedSequencePositionMap $reindexedSequencePositionMap)
3355 {
3356 global $DIC; /* @var ILIAS\DI\Container $DIC */
3357
3358 $testSequenceFactory = new ilTestSequenceFactory(
3359 $DIC->database(),
3360 $DIC->language(),
3361 $DIC['ilPluginAdmin'],
3362 $this
3363 );
3364
3365 foreach ($activeIds as $activeId) {
3366 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
3367 $passSelector->setActiveId($activeId);
3368
3369 foreach ($passSelector->getExistingPasses() as $pass) {
3370 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $pass);
3371 $testSequence->loadFromDb();
3372
3373 $testSequence->removeQuestion($questionId, $reindexedSequencePositionMap);
3374 $testSequence->saveToDb();
3375 }
3376 }
3377 }
3378
3382 public function removeQuestions($removeQuestionIds)
3383 {
3384 foreach ($removeQuestionIds as $value) {
3385 $this->removeQuestion($value);
3386 }
3387
3389 }
3390
3398 public function removeQuestion($question_id)
3399 {
3400 $question = &ilObjTest::_instanciateQuestion($question_id);
3401 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3403 $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3404 }
3405 $question->delete($question_id);
3406 }
3407
3417 {
3418 $this->removeTestResultsByUserIds($userIds);
3419
3420 global $DIC;
3421 $ilDB = $DIC['ilDB'];
3422 $lng = $DIC['lng'];
3423
3424 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3425 $participantData = new ilTestParticipantData($ilDB, $lng);
3426 $participantData->setUserIdsFilter($userIds);
3427 $participantData->load($this->getTestId());
3428
3429 $this->removeTestActives($participantData->getActiveIds());
3430 }
3431
3432 public function removeTestResults(ilTestParticipantData $participantData)
3433 {
3434 if (count($participantData->getAnonymousActiveIds())) {
3435 $this->removeTestResultsByActiveIds($participantData->getAnonymousActiveIds());
3436 }
3437
3438 if (count($participantData->getUserIds())) {
3439 /* @var ilTestLP $testLP */
3440 require_once 'Services/Object/classes/class.ilObjectLP.php';
3441 $testLP = ilObjectLP::getInstance($this->getId());
3442 $testLP->setTestObject($this);
3443 $testLP->resetLPDataForUserIds($participantData->getUserIds(), false);
3444 }
3445
3446 if (count($participantData->getActiveIds())) {
3447 $this->removeTestActives($participantData->getActiveIds());
3448 }
3449 }
3450
3451 public function removeTestResultsByUserIds($userIds)
3452 {
3453 global $DIC;
3454 $ilDB = $DIC['ilDB'];
3455 $lng = $DIC['lng'];
3456
3457 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3458 $participantData = new ilTestParticipantData($ilDB, $lng);
3459 $participantData->setUserIdsFilter($userIds);
3460 $participantData->load($this->getTestId());
3461
3462 $IN_userIds = $ilDB->in('usr_id', $participantData->getUserIds(), false, 'integer');
3463 $ilDB->manipulateF(
3464 "DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
3465 array('text'),
3466 array("tst_password_" . $this->getTestId())
3467 );
3468
3469 if (count($participantData->getActiveIds())) {
3470 $this->removeTestResultsByActiveIds($participantData->getActiveIds());
3471 }
3472 }
3473
3474 public function removeTestResultsByActiveIds($activeIds)
3475 {
3476 global $DIC;
3477 $ilDB = $DIC['ilDB'];
3478
3479 $IN_activeIds = $ilDB->in('active_fi', $activeIds, false, 'integer');
3480
3481 $ilDB->manipulate("DELETE FROM tst_solutions WHERE $IN_activeIds");
3482 $ilDB->manipulate("DELETE FROM tst_qst_solved WHERE $IN_activeIds");
3483 $ilDB->manipulate("DELETE FROM tst_test_result WHERE $IN_activeIds");
3484 $ilDB->manipulate("DELETE FROM tst_pass_result WHERE $IN_activeIds");
3485 $ilDB->manipulate("DELETE FROM tst_result_cache WHERE $IN_activeIds");
3486 $ilDB->manipulate("DELETE FROM tst_sequence WHERE $IN_activeIds");
3487 $ilDB->manipulate("DELETE FROM tst_times WHERE $IN_activeIds");
3488
3489 if ($this->isRandomTest()) {
3490 $ilDB->manipulate("DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
3491 } elseif ($this->isDynamicTest()) {
3492 $ilDB->manipulate("DELETE FROM tst_seq_qst_tracking WHERE $IN_activeIds");
3493 $ilDB->manipulate("DELETE FROM tst_seq_qst_answstatus WHERE $IN_activeIds");
3494 $ilDB->manipulate("DELETE FROM tst_seq_qst_postponed WHERE $IN_activeIds");
3495 $ilDB->manipulate("DELETE FROM tst_seq_qst_checked WHERE $IN_activeIds");
3496 }
3497
3498 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3499
3500 foreach ($activeIds as $active_id) {
3501 // remove file uploads
3502 if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id")) {
3503 ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3504 }
3505
3507 $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3508 }
3509 }
3510
3511 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3513 }
3514
3515 public function removeTestActives($activeIds)
3516 {
3517 global $DIC;
3518 $ilDB = $DIC['ilDB'];
3519
3520 $IN_activeIds = $ilDB->in('active_id', $activeIds, false, 'integer');
3521 $ilDB->manipulate("DELETE FROM tst_active WHERE $IN_activeIds");
3522 }
3523
3531 public function questionMoveUp($question_id)
3532 {
3533 global $DIC;
3534 $ilDB = $DIC['ilDB'];
3535
3536 // Move a question up in sequence
3537 $result = $ilDB->queryF(
3538 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3539 array('integer', 'integer'),
3540 array($this->getTestId(), $question_id)
3541 );
3542 $data = $ilDB->fetchObject($result);
3543 if ($data->sequence > 1) {
3544 // OK, it's not the top question, so move it up
3545 $result = $ilDB->queryF(
3546 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3547 array('integer','integer'),
3548 array($this->getTestId(), $data->sequence - 1)
3549 );
3550 $data_previous = $ilDB->fetchObject($result);
3551 // change previous dataset
3552 $affectedRows = $ilDB->manipulateF(
3553 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3554 array('integer','integer'),
3555 array($data->sequence, $data_previous->test_question_id)
3556 );
3557 // move actual dataset up
3558 $affectedRows = $ilDB->manipulateF(
3559 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3560 array('integer','integer'),
3561 array($data->sequence - 1, $data->test_question_id)
3562 );
3563 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3565 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence - 1), $question_id);
3566 }
3567 }
3568 $this->loadQuestions();
3569 }
3570
3578 public function questionMoveDown($question_id)
3579 {
3580 global $DIC;
3581 $ilDB = $DIC['ilDB'];
3582
3583 // Move a question down in sequence
3584 $result = $ilDB->queryF(
3585 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3586 array('integer','integer'),
3587 array($this->getTestId(), $question_id)
3588 );
3589 $data = $ilDB->fetchObject($result);
3590 $result = $ilDB->queryF(
3591 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3592 array('integer','integer'),
3593 array($this->getTestId(), $data->sequence + 1)
3594 );
3595 if ($result->numRows() == 1) {
3596 // OK, it's not the last question, so move it down
3597 $data_next = $ilDB->fetchObject($result);
3598 // change next dataset
3599 $affectedRows = $ilDB->manipulateF(
3600 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3601 array('integer','integer'),
3602 array($data->sequence, $data_next->test_question_id)
3603 );
3604 // move actual dataset down
3605 $affectedRows = $ilDB->manipulateF(
3606 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3607 array('integer','integer'),
3608 array($data->sequence + 1, $data->test_question_id)
3609 );
3610 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3612 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence + 1), $question_id);
3613 }
3614 }
3615 $this->loadQuestions();
3616 }
3617
3625 public function duplicateQuestionForTest($question_id)
3626 {
3627 global $DIC;
3628 $ilUser = $DIC['ilUser'];
3629 $question = &ilObjTest::_instanciateQuestion($question_id);
3630 $duplicate_id = $question->duplicate(true, null, null, null, $this->getId());
3631
3632 return $duplicate_id;
3633 }
3634
3643 public function insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly = false)
3644 {
3645 global $DIC;
3646 $ilDB = $DIC['ilDB'];
3647 #var_dump($question_id);
3648 if ($linkOnly) {
3649 $duplicate_id = $question_id;
3650 } else {
3651 $duplicate_id = $this->duplicateQuestionForTest($question_id);
3652 }
3653
3654 // get maximum sequence index in test
3655 $result = $ilDB->queryF(
3656 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
3657 array('integer'),
3658 array($this->getTestId())
3659 );
3660 $sequence = 1;
3661
3662 if ($result->numRows() == 1) {
3663 $data = $ilDB->fetchObject($result);
3664 $sequence = $data->seq + 1;
3665 }
3666
3667 $next_id = $ilDB->nextId('tst_test_question');
3668 $affectedRows = $ilDB->manipulateF(
3669 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
3670 array('integer', 'integer','integer','integer','integer'),
3671 array($next_id, $this->getTestId(), $duplicate_id, $sequence, time())
3672 );
3673 if ($affectedRows == 1) {
3674 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3676 $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3677 }
3678 }
3679 // remove test_active entries, because test has changed
3680 $affectedRows = $ilDB->manipulateF(
3681 "DELETE FROM tst_active WHERE test_fi = %s",
3682 array('integer'),
3683 array($this->getTestId())
3684 );
3685 $this->loadQuestions();
3686 $this->saveCompleteStatus($testQuestionSetConfig);
3687 return $duplicate_id;
3688 }
3689
3697 public function &getQuestionTitles()
3698 {
3699 $titles = array();
3700 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3701 global $DIC;
3702 $ilDB = $DIC['ilDB'];
3703 $result = $ilDB->queryF(
3704 "SELECT qpl_questions.title FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ORDER BY tst_test_question.sequence",
3705 array('integer'),
3706 array($this->getTestId())
3707 );
3708 while ($row = $ilDB->fetchAssoc($result)) {
3709 array_push($titles, $row["title"]);
3710 }
3711 }
3712 return $titles;
3713 }
3714
3723 {
3724 $titles = array();
3725 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3726 global $DIC;
3727 $ilDB = $DIC['ilDB'];
3728 $result = $ilDB->queryF(
3729 "SELECT qpl_questions.title, qpl_questions.question_id FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ORDER BY tst_test_question.sequence",
3730 array('integer'),
3731 array($this->getTestId())
3732 );
3733 while ($row = $ilDB->fetchAssoc($result)) {
3734 $titles[$row['question_id']] = $row["title"];
3735 }
3736 }
3737 return $titles;
3738 }
3739
3740 // fau: testNav - add number parameter (to show if title should not be shown)
3750 public function getQuestionTitle($title, $nr = null)
3751 {
3752 if ($this->getTitleOutput() == 2) {
3753 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC) {
3754 // avoid legacy setting combination: ctm without question titles
3755 return $title;
3756 } elseif (isset($nr)) {
3757 return $this->lng->txt("ass_question") . ' ' . $nr;
3758 } else {
3759 return $this->lng->txt("ass_question");
3760 }
3761 } else {
3762 return $title;
3763 }
3764 }
3765 // fau.
3766
3775 public function getQuestionDataset($question_id)
3776 {
3777 global $DIC;
3778 $ilDB = $DIC['ilDB'];
3779
3780 $result = $ilDB->queryF(
3781 "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",
3782 array('integer'),
3783 array($question_id)
3784 );
3785 $row = $ilDB->fetchObject($result);
3786 return $row;
3787 }
3788
3795 public function &getExistingQuestions($pass = null)
3796 {
3797 global $DIC;
3798 $ilUser = $DIC['ilUser'];
3799 $ilDB = $DIC['ilDB'];
3800
3801 $existing_questions = array();
3802 $active_id = $this->getActiveIdOfUser($ilUser->getId());
3803 if ($this->isRandomTest()) {
3804 if (is_null($pass)) {
3805 $pass = 0;
3806 }
3807 $result = $ilDB->queryF(
3808 "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",
3809 array('integer','integer'),
3810 array($active_id, $pass)
3811 );
3812 } else {
3813 $result = $ilDB->queryF(
3814 "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",
3815 array('integer'),
3816 array($this->getTestId())
3817 );
3818 }
3819 while ($data = $ilDB->fetchObject($result)) {
3820 if ($data->original_id === null) {
3821 continue;
3822 }
3823
3824 array_push($existing_questions, $data->original_id);
3825 }
3826 return $existing_questions;
3827 }
3828
3836 public function getQuestionType($question_id)
3837 {
3838 global $DIC;
3839 $ilDB = $DIC['ilDB'];
3840
3841 if ($question_id < 1) {
3842 return -1;
3843 }
3844 $result = $ilDB->queryF(
3845 "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",
3846 array('integer'),
3847 array($question_id)
3848 );
3849 if ($result->numRows() == 1) {
3850 $data = $ilDB->fetchObject($result);
3851 return $data->type_tag;
3852 } else {
3853 return "";
3854 }
3855 }
3856
3863 public function startWorkingTime($active_id, $pass)
3864 {
3865 global $DIC;
3866 $ilDB = $DIC['ilDB'];
3867
3868 $next_id = $ilDB->nextId('tst_times');
3869 $affectedRows = $ilDB->manipulateF(
3870 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
3871 array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'),
3872 array($next_id, $active_id, strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"), $pass, time())
3873 );
3874 return $next_id;
3875 }
3876
3883 public function updateWorkingTime($times_id)
3884 {
3885 global $DIC;
3886 $ilDB = $DIC['ilDB'];
3887
3888 $affectedRows = $ilDB->manipulateF(
3889 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
3890 array('timestamp', 'integer', 'integer'),
3891 array(strftime("%Y-%m-%d %H:%M:%S"), time(), $times_id)
3892 );
3893 }
3894
3901 public function &getWorkedQuestions($active_id, $pass = null)
3902 {
3903 global $DIC;
3904 $ilUser = $DIC['ilUser'];
3905 $ilDB = $DIC['ilDB'];
3906
3907 if (is_null($pass)) {
3908 $result = $ilDB->queryF(
3909 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3910 array('integer','integer'),
3911 array($active_id, 0)
3912 );
3913 } else {
3914 $result = $ilDB->queryF(
3915 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3916 array('integer','integer'),
3917 array($active_id, $pass)
3918 );
3919 }
3920 $result_array = array();
3921 while ($row = $ilDB->fetchAssoc($result)) {
3922 array_push($result_array, $row["question_fi"]);
3923 }
3924 return $result_array;
3925 }
3926
3935 public function isTestFinishedToViewResults($active_id, $currentpass)
3936 {
3937 $num = ilObjTest::lookupPassResultsUpdateTimestamp($active_id, $currentpass);
3938 return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ? true : false;
3939 }
3940
3947 public function &getAllQuestions($pass = null)
3948 {
3949 global $DIC;
3950 $ilUser = $DIC['ilUser'];
3951 $ilDB = $DIC['ilDB'];
3952
3953 $result_array = array();
3954 if ($this->isRandomTest()) {
3955 $active_id = $this->getActiveIdOfUser($ilUser->getId());
3956 $this->loadQuestions($active_id, $pass);
3957 if (count($this->questions) == 0) {
3958 return $result_array;
3959 }
3960 if (is_null($pass)) {
3961 $pass = self::_getPass($active_id);
3962 }
3963 $result = $ilDB->queryF(
3964 "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 " . $ilDB->in('qpl_questions.question_id', $this->questions, false, 'integer'),
3965 array('integer','integer'),
3966 array($active_id, $pass)
3967 );
3968 } else {
3969 if (count($this->questions) == 0) {
3970 return $result_array;
3971 }
3972 $result = $ilDB->query("SELECT qpl_questions.* FROM qpl_questions, tst_test_question WHERE tst_test_question.question_fi = qpl_questions.question_id AND " . $ilDB->in('qpl_questions.question_id', $this->questions, false, 'integer'));
3973 }
3974 while ($row = $ilDB->fetchAssoc($result)) {
3975 $result_array[$row["question_id"]] = $row;
3976 }
3977 return $result_array;
3978 }
3979
3988 public function getActiveIdOfUser($user_id = "", $anonymous_id = "")
3989 {
3990 global $DIC;
3991 $ilDB = $DIC['ilDB'];
3992 $ilUser = $DIC['ilUser'];
3993
3994 if (!$user_id) {
3995 $user_id = $ilUser->getId();
3996 }
3997 if (($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()]))) {
3998 $result = $ilDB->queryF(
3999 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4000 array('integer','integer','text'),
4001 array($user_id, $this->test_id, $_SESSION["tst_access_code"][$this->getTestId()])
4002 );
4003 } elseif (strlen($anonymous_id)) {
4004 $result = $ilDB->queryF(
4005 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4006 array('integer','integer','text'),
4007 array($user_id, $this->test_id, $anonymous_id)
4008 );
4009 } else {
4010 if ($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) {
4011 return null;
4012 }
4013 $result = $ilDB->queryF(
4014 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4015 array('integer','integer'),
4016 array($user_id, $this->test_id)
4017 );
4018 }
4019 if ($result->numRows()) {
4020 $row = $ilDB->fetchAssoc($result);
4021 return $row["active_id"];
4022 } else {
4023 return 0;
4024 }
4025 }
4026
4035 public static function _getActiveIdOfUser($user_id = "", $test_id = "")
4036 {
4037 global $DIC;
4038 $ilDB = $DIC['ilDB'];
4039 $ilUser = $DIC['ilUser'];
4040
4041 if (!$user_id) {
4042 $user_id = $ilUser->id;
4043 }
4044 if (!$test_id) {
4045 return "";
4046 }
4047 $result = $ilDB->queryF(
4048 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4049 array('integer', 'integer'),
4050 array($user_id, $test_id)
4051 );
4052 if ($result->numRows()) {
4053 $row = $ilDB->fetchAssoc($result);
4054 return $row["active_id"];
4055 } else {
4056 return "";
4057 }
4058 }
4059
4066 public function pcArrayShuffle($array)
4067 {
4068 $keys = array_keys($array);
4069 shuffle($keys);
4070 $result = array();
4071 foreach ($keys as $key) {
4072 $result[$key] = $array[$key];
4073 }
4074 return $result;
4075 }
4076
4084 public function &getTestResult($active_id, $pass = null, $ordered_sequence = false, $considerHiddenQuestions = true, $considerOptionalQuestions = true)
4085 {
4086 global $DIC;
4087 $tree = $DIC['tree'];
4088 $ilDB = $DIC['ilDB'];
4089 $lng = $DIC['lng'];
4090 $ilPluginAdmin = $DIC['ilPluginAdmin'];
4091
4092 $results = $this->getResultsForActiveId($active_id);
4093
4094 if (is_null($pass)) {
4095 $pass = $results['pass'];
4096 }
4097
4098 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
4099 $testSessionFactory = new ilTestSessionFactory($this);
4100 $testSession = $testSessionFactory->getSession($active_id);
4101
4102 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4103 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
4104 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $pass);
4105
4106 if ($this->isDynamicTest()) {
4107 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4108 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
4109 $dynamicQuestionSetConfig->loadFromDb();
4110
4111 $testSequence->loadFromDb($dynamicQuestionSetConfig);
4112 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4113
4114 $sequence = $testSequence->getUserSequenceQuestions();
4115 } else {
4116 $testSequence->setConsiderHiddenQuestionsEnabled($considerHiddenQuestions);
4117 $testSequence->setConsiderOptionalQuestionsEnabled($considerOptionalQuestions);
4118
4119 $testSequence->loadFromDb();
4120 $testSequence->loadQuestions();
4121
4122 if ($ordered_sequence) {
4123 $sequence = $testSequence->getOrderedSequenceQuestions();
4124 } else {
4125 $sequence = $testSequence->getUserSequenceQuestions();
4126 }
4127 }
4128
4129 $arrResults = array();
4130
4131 $query = "
4132 SELECT tst_test_result.question_fi,
4133 tst_test_result.points reached,
4134 tst_test_result.hint_count requested_hints,
4135 tst_test_result.hint_points hint_points,
4136 tst_test_result.answered answered
4137
4138 FROM tst_test_result
4139
4140 LEFT JOIN tst_solutions
4141 ON tst_solutions.active_fi = tst_test_result.active_fi
4142 AND tst_solutions.question_fi = tst_test_result.question_fi
4143
4144 WHERE tst_test_result.active_fi = %s
4145 AND tst_test_result.pass = %s
4146 ";
4147
4148 $solutionresult = $ilDB->queryF(
4149 $query,
4150 array('integer', 'integer'),
4151 array($active_id, $pass)
4152 );
4153
4154 while ($row = $ilDB->fetchAssoc($solutionresult)) {
4155 $arrResults[ $row['question_fi'] ] = $row;
4156 }
4157
4158 $numWorkedThrough = count($arrResults);
4159
4160 require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4161
4162 $IN_question_ids = $ilDB->in('qpl_questions.question_id', $sequence, false, 'integer');
4163
4164 $query = "
4165 SELECT qpl_questions.*,
4166 qpl_qst_type.type_tag,
4167 qpl_sol_sug.question_fi has_sug_sol
4168
4169 FROM qpl_qst_type,
4170 qpl_questions
4171
4172 LEFT JOIN qpl_sol_sug
4173 ON qpl_sol_sug.question_fi = qpl_questions.question_id
4174
4175 WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi
4176 AND $IN_question_ids
4177 ";
4178
4179 $result = $ilDB->query($query);
4180
4181 $unordered = array();
4182
4183 $key = 1;
4184
4185 $obligationsAnswered = true;
4186
4187 while ($row = $ilDB->fetchAssoc($result)) {
4188 $percentvalue = (
4189 $row['points'] ? $arrResults[ $row['question_id'] ]['reached'] / $row['points'] : 0
4190 );
4191
4192 if ($percentvalue < 0) {
4193 $percentvalue = 0.0;
4194 }
4195
4196 $data = array(
4197 "nr" => "$key",
4198 "title" => ilUtil::prepareFormOutput($row['title']),
4199 "max" => round($row['points'], 2),
4200 "reached" => round($arrResults[$row['question_id']]['reached'], 2),
4201 'requested_hints' => $arrResults[$row['question_id']]['requested_hints'],
4202 'hint_points' => $arrResults[$row['question_id']]['hint_points'],
4203 "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4204 "solution" => ($row['has_sug_sol']) ? assQuestion::_getSuggestedSolutionOutput($row['question_id']) : '',
4205 "type" => $row["type_tag"],
4206 "qid" => $row['question_id'],
4207 "original_id" => $row["original_id"],
4208 "workedthrough" => isset($arrResults[$row['question_id']]) ? 1 : 0,
4209 'answered' => $arrResults[$row['question_id']]['answered']
4210 );
4211
4212 if (!$arrResults[ $row['question_id'] ]['answered']) {
4213 $obligationsAnswered = false;
4214 }
4215
4216 $unordered[ $row['question_id'] ] = $data;
4217
4218 $key++;
4219 }
4220
4221 $numQuestionsTotal = count($unordered);
4222
4223 $pass_max = 0;
4224 $pass_reached = 0;
4225 $pass_requested_hints = 0;
4226 $pass_hint_points = 0;
4227 $key = 1;
4228
4229 $found = array();
4230
4231 foreach ($sequence as $qid) {
4232 // building pass point sums based on prepared data
4233 // for question that exists in users qst sequence
4234 $pass_max += round($unordered[$qid]['max'], 2);
4235 $pass_reached += round($unordered[$qid]['reached'], 2);
4236 $pass_requested_hints += $unordered[$qid]['requested_hints'];
4237 $pass_hint_points += $unordered[$qid]['hint_points'];
4238
4239 // pickup prepared data for question
4240 // that exists in users qst sequence
4241 $unordered[$qid]['nr'] = $key;
4242 array_push($found, $unordered[$qid]);
4243
4244 // increment key counter
4245 $key++;
4246 }
4247
4248 $unordered = null;
4249
4250 if ($this->getScoreCutting() == 1) {
4251 if ($results['reached_points'] < 0) {
4252 $results['reached_points'] = 0;
4253 }
4254
4255 if ($pass_reached < 0) {
4256 $pass_reached = 0;
4257 }
4258 }
4259
4260 $found['pass']['total_max_points'] = $pass_max;
4261 $found['pass']['total_reached_points'] = $pass_reached;
4262 $found['pass']['total_requested_hints'] = $pass_requested_hints;
4263 $found['pass']['total_hint_points'] = $pass_hint_points;
4264 $found['pass']['percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
4265 $found['pass']['obligationsAnswered'] = $obligationsAnswered;
4266 $found['pass']['num_workedthrough'] = $numWorkedThrough;
4267 $found['pass']['num_questions_total'] = $numQuestionsTotal;
4268
4269 $found["test"]["total_max_points"] = $results['max_points'];
4270 $found["test"]["total_reached_points"] = $results['reached_points'];
4271 $found["test"]["total_requested_hints"] = $results['hint_count'];
4272 $found["test"]["total_hint_points"] = $results['hint_points'];
4273 $found["test"]["result_pass"] = $results['pass'];
4274 $found['test']['result_tstamp'] = $results['tstamp'];
4275 $found['test']['obligations_answered'] = $results['obligations_answered'];
4276
4277 if ((!$found['pass']['total_reached_points']) or (! $found['pass']['total_max_points'])) {
4278 $percentage = 0.0;
4279 } else {
4280 $percentage = ($found['pass']['total_reached_points'] / $found['pass']['total_max_points']) * 100.0;
4281
4282 if ($percentage < 0) {
4283 $percentage = 0.0;
4284 }
4285 }
4286
4287 $found["test"]["passed"] = $results['passed'];
4288
4289 return $found;
4290 }
4291
4298 public function evalTotalPersons()
4299 {
4300 global $DIC;
4301 $ilDB = $DIC['ilDB'];
4302
4303 $result = $ilDB->queryF(
4304 "SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
4305 array('integer'),
4306 array($this->getTestId())
4307 );
4308 $row = $ilDB->fetchAssoc($result);
4309 return $row["total"];
4310 }
4311
4318 public function getCompleteWorkingTime($user_id)
4319 {
4320 global $DIC;
4321 $ilDB = $DIC['ilDB'];
4322
4323 $result = $ilDB->queryF(
4324 "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",
4325 array('integer','integer'),
4326 array($this->getTestId(), $user_id)
4327 );
4328 $time = 0;
4329 while ($row = $ilDB->fetchAssoc($result)) {
4330 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4331 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4332 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4333 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4334 $time += ($epoch_2 - $epoch_1);
4335 }
4336 return $time;
4337 }
4338
4346 {
4347 return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4348 }
4349
4358 {
4359 global $DIC;
4360 $ilDB = $DIC['ilDB'];
4361
4362 $result = $ilDB->queryF(
4363 "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",
4364 array('integer'),
4365 array($test_id)
4366 );
4367 $time = 0;
4368 $times = array();
4369 while ($row = $ilDB->fetchAssoc($result)) {
4370 if (!array_key_exists($row["active_fi"], $times)) {
4371 $times[$row["active_fi"]] = 0;
4372 }
4373 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4374 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4375 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4376 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4377 $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4378 }
4379 return $times;
4380 }
4381
4388 public function getCompleteWorkingTimeOfParticipant($active_id)
4389 {
4390 global $DIC;
4391 $ilDB = $DIC['ilDB'];
4392
4393 $result = $ilDB->queryF(
4394 "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",
4395 array('integer','integer'),
4396 array($this->getTestId(), $active_id)
4397 );
4398 $time = 0;
4399 while ($row = $ilDB->fetchAssoc($result)) {
4400 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4401 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4402 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4403 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4404 $time += ($epoch_2 - $epoch_1);
4405 }
4406 return $time;
4407 }
4408
4415 public static function _getWorkingTimeOfParticipantForPass($active_id, $pass)
4416 {
4417 global $DIC;
4418 $ilDB = $DIC['ilDB'];
4419
4420 $result = $ilDB->queryF(
4421 "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4422 array('integer','integer'),
4423 array($active_id, $pass)
4424 );
4425 $time = 0;
4426 while ($row = $ilDB->fetchAssoc($result)) {
4427 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4428 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4429 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4430 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4431 $time += ($epoch_2 - $epoch_1);
4432 }
4433 return $time;
4434 }
4435
4443 public function getVisitTimeOfParticipant($active_id)
4444 {
4445 return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4446 }
4447
4456 public function _getVisitTimeOfParticipant($test_id, $active_id)
4457 {
4458 global $DIC;
4459 $ilDB = $DIC['ilDB'];
4460
4461 $result = $ilDB->queryF(
4462 "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.started",
4463 array('integer','integer'),
4464 array($test_id, $active_id)
4465 );
4466 $firstvisit = 0;
4467 $lastvisit = 0;
4468 while ($row = $ilDB->fetchAssoc($result)) {
4469 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4470 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4471 if ($firstvisit == 0 || $epoch_1 < $firstvisit) {
4472 $firstvisit = $epoch_1;
4473 }
4474 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4475 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4476 if ($epoch_2 > $lastvisit) {
4477 $lastvisit = $epoch_2;
4478 }
4479 }
4480 return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4481 }
4482
4489 public function &evalStatistical($active_id)
4490 {
4491 global $DIC;
4492 $ilDB = $DIC['ilDB'];
4493 // $ilBench = $DIC['ilBench'];
4494 $pass = ilObjTest::_getResultPass($active_id);
4495 $test_result = &$this->getTestResult($active_id, $pass);
4496 $result = $ilDB->queryF(
4497 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
4498 array('integer'),
4499 array($active_id)
4500 );
4501 $times = array();
4502 $first_visit = 0;
4503 $last_visit = 0;
4504 while ($row = $ilDB->fetchObject($result)) {
4505 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4506 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4507 if (!$first_visit) {
4508 $first_visit = $epoch_1;
4509 }
4510 if ($epoch_1 < $first_visit) {
4511 $first_visit = $epoch_1;
4512 }
4513 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4514 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4515 if (!$last_visit) {
4516 $last_visit = $epoch_2;
4517 }
4518 if ($epoch_2 > $last_visit) {
4519 $last_visit = $epoch_2;
4520 }
4521 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4522 }
4523 $max_time = 0;
4524 foreach ($times as $key => $value) {
4525 $max_time += $value;
4526 }
4527 if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"])) {
4528 $percentage = 0.0;
4529 } else {
4530 $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4531 if ($percentage < 0) {
4532 $percentage = 0.0;
4533 }
4534 }
4535 $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4536 $first_date = getdate($first_visit);
4537 $last_date = getdate($last_visit);
4538 $qworkedthrough = 0;
4539 foreach ($test_result as $key => $value) {
4540 if (preg_match("/\d+/", $key)) {
4541 $qworkedthrough += $value["workedthrough"];
4542 }
4543 }
4544 if (!$qworkedthrough) {
4545 $atimeofwork = 0;
4546 } else {
4547 $atimeofwork = $max_time / $qworkedthrough;
4548 }
4549
4550 $obligationsAnswered = $test_result["test"]["obligations_answered"];
4551
4552 $result_mark = "";
4553 $passed = "";
4554
4555 if ($mark_obj) {
4556 $result_mark = $mark_obj->getShortName();
4557
4558 if ($mark_obj->getPassed() && $obligationsAnswered) {
4559 $passed = 1;
4560 } else {
4561 $passed = 0;
4562 }
4563 }
4564 $percent_worked_through = 0;
4565 if (count($this->questions)) {
4566 $percent_worked_through = $qworkedthrough / count($this->questions);
4567 }
4568 $result_array = array(
4569 "qworkedthrough" => $qworkedthrough,
4570 "qmax" => count($this->questions),
4571 "pworkedthrough" => $percent_worked_through,
4572 "timeofwork" => $max_time,
4573 "atimeofwork" => $atimeofwork,
4574 "firstvisit" => $first_date,
4575 "lastvisit" => $last_date,
4576 "resultspoints" => $test_result["test"]["total_reached_points"],
4577 "maxpoints" => $test_result["test"]["total_max_points"],
4578 "resultsmarks" => $result_mark,
4579 "passed" => $passed,
4580 "distancemedian" => "0"
4581 );
4582 foreach ($test_result as $key => $value) {
4583 if (preg_match("/\d+/", $key)) {
4584 $result_array[$key] = $value;
4585 }
4586 }
4587 return $result_array;
4588 }
4589
4597 public function &getTotalPointsPassedArray()
4598 {
4599 $totalpoints_array = array();
4600 $all_users = &$this->evalTotalParticipantsArray();
4601 foreach ($all_users as $active_id => $user_name) {
4602 $test_result = &$this->getTestResult($active_id);
4603 $reached = $test_result["test"]["total_reached_points"];
4604 $total = $test_result["test"]["total_max_points"];
4605 $percentage = $total != 0 ? $reached / $total : 0;
4606 $mark = $this->mark_schema->getMatchingMark($percentage * 100.0);
4607
4608 $obligationsAnswered = $test_result["test"]["obligations_answered"];
4609
4610 if ($mark) {
4611 if ($mark->getPassed() && $obligationsAnswered) {
4612 array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4613 }
4614 }
4615 }
4616 return $totalpoints_array;
4617 }
4618
4624 public function &getParticipants()
4625 {
4626 global $DIC;
4627 $ilDB = $DIC['ilDB'];
4628 $result = $ilDB->queryF(
4629 "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",
4630 array('integer'),
4631 array($this->getTestId())
4632 );
4633 $persons_array = array();
4634 while ($row = $ilDB->fetchAssoc($result)) {
4635 $name = $this->lng->txt("anonymous");
4636 $fullname = $this->lng->txt("anonymous");
4637 $login = "";
4638 if (!$this->getAnonymity()) {
4639 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4640 $name = $this->lng->txt("deleted_user");
4641 $fullname = $this->lng->txt("deleted_user");
4642 $login = $this->lng->txt("unknown");
4643 } else {
4644 $login = $row["login"];
4645 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4646 $name = $this->lng->txt("anonymous");
4647 $fullname = $this->lng->txt("anonymous");
4648 } else {
4649 $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4650 $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4651 }
4652 }
4653 }
4654 $persons_array[$row["active_id"]] = array(
4655 "name" => $name,
4656 "fullname" => $fullname,
4657 "login" => $login
4658 );
4659 }
4660 return $persons_array;
4661 }
4662
4669 public function &evalTotalPersonsArray($name_sort_order = "asc")
4670 {
4671 global $DIC;
4672 $ilDB = $DIC['ilDB'];
4673 $result = $ilDB->queryF(
4674 "SELECT 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),
4675 array('integer'),
4676 array($this->getTestId())
4677 );
4678 $persons_array = array();
4679 while ($row = $ilDB->fetchAssoc($result)) {
4680 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row["active_id"])) {
4681 continue;
4682 }
4683
4684 if ($this->getAnonymity()) {
4685 $persons_array[$row["active_id"]] = $this->lng->txt("anonymous");
4686 } else {
4687 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4688 $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4689 } else {
4690 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4691 $persons_array[$row["active_id"]] = $row["lastname"];
4692 } else {
4693 $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4694 }
4695 }
4696 }
4697 }
4698 return $persons_array;
4699 }
4700
4707 public function &evalTotalParticipantsArray($name_sort_order = "asc")
4708 {
4709 global $DIC;
4710 $ilDB = $DIC['ilDB'];
4711 $result = $ilDB->queryF(
4712 "SELECT tst_active.active_id, usr_data.login, 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),
4713 array('integer'),
4714 array($this->getTestId())
4715 );
4716 $persons_array = array();
4717 while ($row = $ilDB->fetchAssoc($result)) {
4718 if ($this->getAnonymity()) {
4719 $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("anonymous"));
4720 } else {
4721 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4722 $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4723 } else {
4724 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4725 $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4726 } else {
4727 $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4728 }
4729 }
4730 }
4731 }
4732 return $persons_array;
4733 }
4734
4741 public function &getQuestionsOfTest($active_id)
4742 {
4743 global $DIC;
4744 $ilDB = $DIC['ilDB'];
4745 if ($this->isRandomTest()) {
4746 $ilDB->setLimit($this->getQuestionCount(), 0);
4747 $result = $ilDB->queryF(
4748 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4749 "tst_test_rnd_qst.pass, qpl_questions.points " .
4750 "FROM tst_test_rnd_qst, qpl_questions " .
4751 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4752 "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4753 array('integer'),
4754 array($active_id)
4755 );
4756 } else {
4757 $result = $ilDB->queryF(
4758 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4759 "qpl_questions.points " .
4760 "FROM tst_test_question, tst_active, qpl_questions " .
4761 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4762 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4763 array('integer'),
4764 array($active_id)
4765 );
4766 }
4767 $qtest = array();
4768 if ($result->numRows()) {
4769 while ($row = $ilDB->fetchAssoc($result)) {
4770 array_push($qtest, $row);
4771 }
4772 }
4773 return $qtest;
4774 }
4775
4782 public function &getQuestionsOfPass($active_id, $pass)
4783 {
4784 global $DIC;
4785 $ilDB = $DIC['ilDB'];
4786 if ($this->isRandomTest()) {
4787 $ilDB->setLimit($this->getQuestionCount(), 0);
4788 $result = $ilDB->queryF(
4789 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4790 "qpl_questions.points " .
4791 "FROM tst_test_rnd_qst, qpl_questions " .
4792 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4793 "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
4794 "ORDER BY tst_test_rnd_qst.sequence",
4795 array('integer', 'integer'),
4796 array($active_id, $pass)
4797 );
4798 } else {
4799 $result = $ilDB->queryF(
4800 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4801 "qpl_questions.points " .
4802 "FROM tst_test_question, tst_active, qpl_questions " .
4803 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4804 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4805 array('integer'),
4806 array($active_id)
4807 );
4808 }
4809 $qpass = array();
4810 if ($result->numRows()) {
4811 while ($row = $ilDB->fetchAssoc($result)) {
4812 array_push($qpass, $row);
4813 }
4814 }
4815 return $qpass;
4816 }
4817
4822
4827 {
4829 }
4830
4835 {
4836 $this->accessFilteredParticipantList = $accessFilteredParticipantList;
4837 }
4838
4843 {
4844 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
4845 require_once 'Modules/Test/classes/class.ilTestParticipantAccessFilter.php';
4846
4847 $list = new ilTestParticipantList($this);
4848 $list->initializeFromDbRows($this->getTestParticipants());
4849
4850 $list = $list->getAccessFilteredList(
4852 );
4853
4854 return $list;
4855 }
4856
4857 public function getUnfilteredEvaluationData()
4858 {
4860 global $DIC;
4861
4862 $ilDB = $DIC->database();
4863
4864 include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
4865 include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
4866 include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
4867
4868 $data = new ilTestEvaluationData($this);
4869
4870 $query = "
4871 SELECT tst_test_result.*,
4872 qpl_questions.original_id,
4873 qpl_questions.title questiontitle,
4874 qpl_questions.points maxpoints
4875
4876 FROM tst_test_result, qpl_questions, tst_active
4877
4878 WHERE tst_active.active_id = tst_test_result.active_fi
4879 AND qpl_questions.question_id = tst_test_result.question_fi
4880 AND tst_active.test_fi = %s
4881
4882 ORDER BY tst_active.active_id ASC, tst_test_result.pass ASC, tst_test_result.tstamp DESC
4883 ";
4884
4885 $result = $ilDB->queryF(
4886 $query,
4887 array('integer'),
4888 array($this->getTestId())
4889 );
4890
4891 $pass = null;
4892 $checked = array();
4893 $datasets = 0;
4894 $questionData = [];
4895
4896 while ($row = $ilDB->fetchAssoc($result)) {
4897 $participantObject = $data->getParticipant($row["active_fi"]);
4898
4899 if (!($participantObject instanceof ilTestEvaluationUserData)) {
4900 continue;
4901 }
4902
4903 $passObject = $participantObject->getPass($row["pass"]);
4904
4905 if (!($passObject instanceof ilTestEvaluationPassData)) {
4906 continue;
4907 }
4908
4909 $passObject->addAnsweredQuestion(
4910 $row["question_fi"],
4911 $row["maxpoints"],
4912 $row["points"],
4913 $row['answered'],
4914 null,
4915 $row['manual']
4916 );
4917 }
4918
4919 foreach (array_keys($data->getParticipants()) as $active_id) {
4920 if ($this->isRandomTest()) {
4921 for ($testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++) {
4922 $ilDB->setLimit($this->getQuestionCount(), 0);
4923
4924 $query = "
4925 SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, qpl_questions.original_id,
4926 tst_test_rnd_qst.pass, qpl_questions.points, qpl_questions.title
4927 FROM tst_test_rnd_qst, qpl_questions
4928 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
4929 AND tst_test_rnd_qst.pass = %s
4930 AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence
4931 ";
4932
4933 $result = $ilDB->queryF(
4934 $query,
4935 array('integer','integer'),
4936 array($testpass, $active_id)
4937 );
4938
4939 if ($result->numRows()) {
4940 while ($row = $ilDB->fetchAssoc($result)) {
4941 $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
4942
4943 $data->getParticipant($active_id)->addQuestion(
4944 $row["original_id"],
4945 $row["question_fi"],
4946 $row["points"],
4947 $row["sequence"],
4948 $tpass
4949 );
4950
4951 $data->addQuestionTitle($row["question_fi"], $row["title"]);
4952 }
4953 }
4954 }
4955 } elseif ($this->isDynamicTest()) {
4956 $lastPass = $data->getParticipant($active_id)->getLastPass();
4957 for ($testpass = 0; $testpass <= $lastPass; $testpass++) {
4958 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4959 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig(
4960 $DIC->repositoryTree(),
4961 $DIC->database(),
4962 $DIC['ilPluginAdmin'],
4963 $this
4964 );
4965 $dynamicQuestionSetConfig->loadFromDb();
4966
4967 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4968 $testSequenceFactory = new ilTestSequenceFactory($DIC->database(), $DIC->language(), $DIC['ilPluginAdmin'], $this);
4969 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $testpass);
4970
4971 $testSequence->loadFromDb($dynamicQuestionSetConfig);
4972 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4973
4974 $sequence = (array) $testSequence->getUserSequenceQuestions();
4975
4976 $questionsIdsToRequest = array_diff(array_values($sequence), array_values($questionData));
4977 if (count($questionsIdsToRequest) > 0) {
4978 $questionIdsCondition = ' ' . $DIC->database()->in('question_id', array_values($questionsIdsToRequest), false, 'integer') . ' ';
4979
4980 $res = $DIC->database()->queryF(
4981 "
4982 SELECT *
4983 FROM qpl_questions
4984 WHERE {$questionIdsCondition}",
4985 array('integer'),
4986 array($active_id)
4987 );
4988 while ($row = $DIC->database()->fetchAssoc($res)) {
4989 $questionData[$row['question_id']] = $row;
4990 $data->addQuestionTitle($row['question_id'], $row['title']);
4991 }
4992 }
4993
4994 foreach ($sequence as $questionId) {
4995 if (!isset($questionData[$questionId])) {
4996 continue;
4997 }
4998
4999 $row = $questionData[$questionId];
5000
5001 $data->getParticipant(
5002 $active_id
5003 )->addQuestion(
5004 $row['original_id'],
5005 $row['question_id'],
5006 $row['points'],
5007 null,
5008 $testpass
5009 );
5010 }
5011 }
5012 } else {
5013 $query = "
5014 SELECT tst_test_question.sequence, tst_test_question.question_fi,
5015 qpl_questions.points, qpl_questions.title, qpl_questions.original_id
5016 FROM tst_test_question, tst_active, qpl_questions
5017 WHERE tst_test_question.question_fi = qpl_questions.question_id
5018 AND tst_active.active_id = %s
5019 AND tst_active.test_fi = tst_test_question.test_fi
5020 ORDER BY tst_test_question.sequence
5021 ";
5022
5023 $result = $ilDB->queryF(
5024 $query,
5025 array('integer'),
5026 array($active_id)
5027 );
5028
5029 if ($result->numRows()) {
5030 $questionsbysequence = array();
5031
5032 while ($row = $ilDB->fetchAssoc($result)) {
5033 $questionsbysequence[$row["sequence"]] = $row;
5034 }
5035
5036 $seqresult = $ilDB->queryF(
5037 "SELECT * FROM tst_sequence WHERE active_fi = %s",
5038 array('integer'),
5039 array($active_id)
5040 );
5041
5042 while ($seqrow = $ilDB->fetchAssoc($seqresult)) {
5043 $questionsequence = unserialize($seqrow["sequence"]);
5044
5045 foreach ($questionsequence as $sidx => $seq) {
5046 $data->getParticipant($active_id)->addQuestion(
5047 $questionsbysequence[$seq]["original_id"],
5048 $questionsbysequence[$seq]["question_fi"],
5049 $questionsbysequence[$seq]["points"],
5050 $sidx + 1,
5051 $seqrow["pass"]
5052 );
5053
5054 $data->addQuestionTitle(
5055 $questionsbysequence[$seq]["question_fi"],
5056 $questionsbysequence[$seq]["title"]
5057 );
5058 }
5059 }
5060 }
5061 }
5062 }
5063
5064 if ($this->getECTSOutput()) {
5065 $passed_array = &$this->getTotalPointsPassedArray();
5066 }
5067
5068 foreach (array_keys($data->getParticipants()) as $active_id) {
5069 $tstUserData = $data->getParticipant($active_id);
5070
5071 $percentage = $tstUserData->getReachedPointsInPercent();
5072
5073 $obligationsAnswered = $tstUserData->areObligationsAnswered();
5074
5075 $mark = $this->mark_schema->getMatchingMark($percentage);
5076
5077 if (is_object($mark)) {
5078 $tstUserData->setMark($mark->getShortName());
5079 $tstUserData->setMarkOfficial($mark->getOfficialName());
5080
5081 $tstUserData->setPassed(
5082 $mark->getPassed() && $tstUserData->areObligationsAnswered()
5083 );
5084 }
5085
5086 if ($this->getECTSOutput()) {
5087 $ects_mark = $this->getECTSGrade(
5088 $passed_array,
5089 $tstUserData->getReached(),
5090 $tstUserData->getMaxPoints()
5091 );
5092
5093 $tstUserData->setECTSMark($ects_mark);
5094 }
5095
5096 $visitingTime = &$this->getVisitTimeOfParticipant($active_id);
5097
5098 $tstUserData->setFirstVisit($visitingTime["firstvisit"]);
5099 $tstUserData->setLastVisit($visitingTime["lastvisit"]);
5100 }
5101
5102 return $data;
5103 }
5104
5105 public static function _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
5106 {
5107 global $DIC;
5108 $ilDB = $DIC['ilDB'];
5109
5111
5112 switch ($questionSetType) {
5114
5115 $res = $ilDB->queryF(
5116 "
5117 SELECT COUNT(qpl_questions.question_id) qcount,
5118 SUM(qpl_questions.points) qsum
5119 FROM tst_active
5120 INNER JOIN tst_tests
5121 ON tst_tests.test_id = tst_active.test_fi
5122 INNER JOIN tst_dyn_quest_set_cfg
5123 ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
5124 INNER JOIN qpl_questions
5125 ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
5126 AND qpl_questions.original_id IS NULL
5127 AND qpl_questions.complete = %s
5128 WHERE tst_active.active_id = %s
5129 ",
5130 array('integer', 'integer'),
5131 array(1, $active_id)
5132 );
5133
5134 break;
5135
5137
5138 $res = $ilDB->queryF(
5139 "
5140 SELECT tst_test_rnd_qst.pass,
5141 COUNT(tst_test_rnd_qst.question_fi) qcount,
5142 SUM(qpl_questions.points) qsum
5143
5144 FROM tst_test_rnd_qst,
5145 qpl_questions
5146
5147 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
5148 AND tst_test_rnd_qst.active_fi = %s
5149 AND pass = %s
5150
5151 GROUP BY tst_test_rnd_qst.active_fi,
5152 tst_test_rnd_qst.pass
5153 ",
5154 array('integer', 'integer'),
5155 array($active_id, $pass)
5156 );
5157
5158 break;
5159
5161
5162 $res = $ilDB->queryF(
5163 "
5164 SELECT COUNT(tst_test_question.question_fi) qcount,
5165 SUM(qpl_questions.points) qsum
5166
5167 FROM tst_test_question,
5168 qpl_questions,
5169 tst_active
5170
5171 WHERE tst_test_question.question_fi = qpl_questions.question_id
5172 AND tst_test_question.test_fi = tst_active.test_fi
5173 AND tst_active.active_id = %s
5174
5175 GROUP BY tst_test_question.test_fi
5176 ",
5177 array('integer'),
5178 array($active_id)
5179 );
5180
5181 break;
5182
5183 default:
5184
5185 throw new ilTestException("not supported question set type: $questionSetType");
5186 }
5187
5188 $row = $ilDB->fetchAssoc($res);
5189
5190 if (is_array($row)) {
5191 return array("count" => $row["qcount"], "points" => $row["qsum"]);
5192 }
5193
5194 return array("count" => 0, "points" => 0);
5195 }
5196
5197 public function &getCompleteEvaluationData($withStatistics = true, $filterby = "", $filtertext = "")
5198 {
5199 include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5200 include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5201 include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5202 $data = $this->getUnfilteredEvaluationData();
5203 if ($withStatistics) {
5204 $data->calculateStatistics();
5205 }
5206 $data->setFilter($filterby, $filtertext);
5207 return $data;
5208 }
5209
5216 public function &evalResultsOverview()
5217 {
5218 return $this->_evalResultsOverview($this->getTestId());
5219 }
5220
5228 {
5229 global $DIC;
5230 $ilDB = $DIC['ilDB'];
5231
5232 $result = $ilDB->queryF(
5233 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5234 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5235 "qpl_questions.points maxpoints " .
5236 "FROM tst_test_result, qpl_questions, tst_active " .
5237 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5238 "WHERE tst_active.active_id = tst_test_result.active_fi " .
5239 "AND qpl_questions.question_id = tst_test_result.question_fi " .
5240 "AND tst_active.test_fi = %s " .
5241 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5242 array('integer'),
5243 array($test_id)
5244 );
5245 $overview = array();
5246 while ($row = $ilDB->fetchAssoc($result)) {
5247 if (!array_key_exists($row["active_fi"], $overview)) {
5248 $overview[$row["active_fi"]] = array();
5249 $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5250 $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5251 $overview[$row["active_fi"]]["title"] = $row["title"];
5252 $overview[$row["active_fi"]]["login"] = $row["login"];
5253 $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5254 $overview[$row["active_fi"]]["started"] = $row["started"];
5255 $overview[$row["active_fi"]]["finished"] = $row["finished"];
5256 }
5257 if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5258 $overview[$row["active_fi"]][$row["pass"]] = array();
5259 $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5260 $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5261 }
5262 array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5263 $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5264 }
5265 return $overview;
5266 }
5267
5275 public function &evalResultsOverviewOfParticipant($active_id)
5276 {
5277 global $DIC;
5278 $ilDB = $DIC['ilDB'];
5279
5280 $result = $ilDB->queryF(
5281 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5282 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5283 "qpl_questions.points maxpoints " .
5284 "FROM tst_test_result, qpl_questions, tst_active " .
5285 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5286 "WHERE tst_active.active_id = tst_test_result.active_fi " .
5287 "AND qpl_questions.question_id = tst_test_result.question_fi " .
5288 "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5289 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5290 array('integer', 'integer'),
5291 array($this->getTestId(), $active_id)
5292 );
5293 $overview = array();
5294 while ($row = $ilDB->fetchAssoc($result)) {
5295 if (!array_key_exists($row["active_fi"], $overview)) {
5296 $overview[$row["active_fi"]] = array();
5297 $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5298 $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5299 $overview[$row["active_fi"]]["title"] = $row["title"];
5300 $overview[$row["active_fi"]]["login"] = $row["login"];
5301 $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5302 $overview[$row["active_fi"]]["started"] = $row["started"];
5303 $overview[$row["active_fi"]]["finished"] = $row["finished"];
5304 }
5305 if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5306 $overview[$row["active_fi"]][$row["pass"]] = array();
5307 $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5308 $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5309 }
5310 array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5311 $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5312 }
5313 return $overview;
5314 }
5315
5327 public function buildName($user_id, $firstname, $lastname, $title)
5328 {
5329 $name = "";
5330 if (strlen($firstname . $lastname . $title) == 0) {
5331 $name = $this->lng->txt("deleted_user");
5332 } else {
5333 if ($user_id == ANONYMOUS_USER_ID) {
5334 $name = $lastname;
5335 } else {
5336 $name = trim($lastname . ", " . $firstname . " " . $title);
5337 }
5338 if ($this->getAnonymity()) {
5339 $name = $this->lng->txt("anonymous");
5340 }
5341 }
5342 return $name;
5343 }
5344
5357 public function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5358 {
5359 global $DIC;
5360 $lng = $DIC['lng'];
5361 $name = "";
5362 if (strlen($firstname . $lastname . $title) == 0) {
5363 $name = $lng->txt("deleted_user");
5364 } else {
5365 if ($user_id == ANONYMOUS_USER_ID) {
5366 $name = $lastname;
5367 } else {
5368 $name = trim($lastname . ", " . $firstname . " " . $title);
5369 }
5370 if ($is_anonymous) {
5371 $name = $lng->txt("anonymous");
5372 }
5373 }
5374 return $name;
5375 }
5376
5383 public function evalTotalStartedAverageTime($activeIdsFilter = null)
5384 {
5385 global $DIC; /* @var ILIAS\DI\Container $DIC */
5386
5387 $query = "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
5388
5389 if (is_array($activeIdsFilter) && count($activeIdsFilter)) {
5390 $query .= " AND " . $DIC->database()->in('active_id', $activeIdsFilter, false, 'integer');
5391 }
5392
5393 $result = $DIC->database()->queryF($query, array('integer'), array($this->getTestId()));
5394 $times = array();
5395 while ($row = $DIC->database()->fetchObject($result)) {
5396 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5397 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5398 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5399 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5400 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5401 }
5402 $max_time = 0;
5403 $counter = 0;
5404 foreach ($times as $key => $value) {
5405 $max_time += $value;
5406 $counter++;
5407 }
5408 if ($counter) {
5409 $average_time = round($max_time / $counter);
5410 } else {
5411 $average_time = 0;
5412 }
5413 return $average_time;
5414 }
5415
5422 public function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = false, $with_questioncount = false, $permission = "read")
5423 {
5424 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5425 return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5426 }
5427
5434 public function getEstimatedWorkingTime()
5435 {
5436 $time_in_seconds = 0;
5437 foreach ($this->questions as $question_id) {
5438 $question = &ilObjTest::_instanciateQuestion($question_id);
5439 $est_time = $question->getEstimatedWorkingTime();
5440 $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5441 }
5442 $hours = (int) ($time_in_seconds / 3600) ;
5443 $time_in_seconds = $time_in_seconds - ($hours * 3600);
5444 $minutes = (int) ($time_in_seconds / 60);
5445 $time_in_seconds = $time_in_seconds - ($minutes * 60);
5446 $result = array("hh" => $hours, "mm" => $minutes, "ss" => $time_in_seconds);
5447 return $result;
5448 }
5449
5456 public function getImagePath()
5457 {
5458 return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5459 }
5460
5467 public function getImagePathWeb()
5468 {
5469 include_once "./Services/Utilities/classes/class.ilUtil.php";
5470 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
5471 return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir);
5472 }
5473
5482 public function &createQuestionGUI($question_type, $question_id = -1)
5483 {
5484 if ((!$question_type) and ($question_id > 0)) {
5485 $question_type = $this->getQuestionType($question_id);
5486 }
5487
5488 if (!strlen($question_type)) {
5489 return null;
5490 }
5491
5492 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5493 assQuestion::_includeClass($question_type, 1);
5494
5495 $question_type_gui = assQuestion::getGuiClassNameByQuestionType($question_type);
5496 $question = new $question_type_gui();
5497
5498 if ($question_id > 0) {
5499 $question->object->loadFromDb($question_id);
5500
5501 global $DIC;
5502 $ilCtrl = $DIC['ilCtrl'];
5503 $ilDB = $DIC['ilDB'];
5504 $ilUser = $DIC['ilUser'];
5505 $lng = $DIC['lng'];
5506
5507 $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
5508 $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
5509
5510 $assSettings = new ilSetting('assessment');
5511 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
5512 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
5513 $processLockerFactory->setQuestionId($question->object->getId());
5514 $processLockerFactory->setUserId($ilUser->getId());
5515 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
5516 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
5517 $question->object->setProcessLocker($processLockerFactory->getLocker());
5518 }
5519
5520 return $question;
5521 }
5522
5532 public static function _instanciateQuestion($question_id)
5533 {
5534 if (strcmp($question_id, "") != 0) {
5535 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5536 return assQuestion::_instanciateQuestion($question_id);
5537 }
5538 }
5539
5548 public function moveQuestions($move_questions, $target_index, $insert_mode)
5549 {
5550 $this->questions = array_values($this->questions);
5551 $array_pos = array_search($target_index, $this->questions);
5552 if ($insert_mode == 0) {
5553 $part1 = array_slice($this->questions, 0, $array_pos);
5554 $part2 = array_slice($this->questions, $array_pos);
5555 } elseif ($insert_mode == 1) {
5556 $part1 = array_slice($this->questions, 0, $array_pos + 1);
5557 $part2 = array_slice($this->questions, $array_pos + 1);
5558 }
5559 foreach ($move_questions as $question_id) {
5560 if (!(array_search($question_id, $part1) === false)) {
5561 unset($part1[array_search($question_id, $part1)]);
5562 }
5563 if (!(array_search($question_id, $part2) === false)) {
5564 unset($part2[array_search($question_id, $part2)]);
5565 }
5566 }
5567 $part1 = array_values($part1);
5568 $part2 = array_values($part2);
5569 $new_array = array_values(array_merge($part1, $move_questions, $part2));
5570 $this->questions = array();
5571 $counter = 1;
5572 foreach ($new_array as $question_id) {
5573 $this->questions[$counter] = $question_id;
5574 $counter++;
5575 }
5576 $this->saveQuestionsToDb();
5577 }
5578
5579
5587 public function startingTimeReached()
5588 {
5589 if ($this->isStartingTimeEnabled() && $this->getStartingTime() != 0) {
5590 $now = time();
5591 if ($now < $this->getStartingTime()) {
5592 return false;
5593 }
5594 }
5595 return true;
5596 }
5597
5605 public function endingTimeReached()
5606 {
5607 if ($this->isEndingTimeEnabled() && $this->getEndingTime() != 0) {
5608 $now = time();
5609 if ($now > $this->getEndingTime()) {
5610 return true;
5611 }
5612 }
5613 return false;
5614 }
5615
5621 public function getAvailableQuestions($arrFilter, $completeonly = 0)
5622 {
5623 global $DIC;
5624 $pluginAdmin = $DIC['ilPluginAdmin'];
5625 $lng = $DIC['lng'];
5626 $ilUser = $DIC['ilUser'];
5627 $ilDB = $DIC['ilDB'];
5628
5629 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5630 $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = true, $equal_points = false, $could_be_offline = false, $showPath = false, $with_questioncount = false));
5631 $available = "";
5632 if (count($available_pools)) {
5633 $available = " AND " . $ilDB->in('qpl_questions.obj_fi', $available_pools, false, 'integer');
5634 } else {
5635 return array();
5636 }
5637 if ($completeonly) {
5638 $available .= " AND qpl_questions.complete = " . $ilDB->quote("1", 'text');
5639 }
5640
5641 $where = "";
5642 if (is_array($arrFilter)) {
5643 if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title'])) {
5644 $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
5645 }
5646 if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description'])) {
5647 $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
5648 }
5649 if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author'])) {
5650 $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
5651 }
5652 if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type'])) {
5653 $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
5654 }
5655 if (array_key_exists('qpl', $arrFilter) && strlen($arrFilter['qpl'])) {
5656 $where .= " AND " . $ilDB->like('object_data.title', 'text', "%%" . $arrFilter['qpl'] . "%%");
5657 }
5658 }
5659
5660 $original_ids = &$this->getExistingQuestions();
5661 $original_clause = " qpl_questions.original_id IS NULL";
5662 if (count($original_ids)) {
5663 $original_clause = " qpl_questions.original_id IS NULL AND " . $ilDB->in('qpl_questions.question_id', $original_ids, true, 'integer');
5664 }
5665
5666 $query_result = $ilDB->query("
5667 SELECT qpl_questions.*, qpl_questions.tstamp,
5668 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,
5669 object_data.title parent_title
5670 FROM qpl_questions, qpl_qst_type, object_data
5671 WHERE $original_clause $available
5672 AND object_data.obj_id = qpl_questions.obj_fi
5673 AND qpl_questions.tstamp > 0
5674 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
5675 $where
5676 ");
5677 $rows = array();
5678 $types = $this->getQuestionTypeTranslations();
5679 if ($query_result->numRows()) {
5680 while ($row = $ilDB->fetchAssoc($query_result)) {
5682
5683 if (!$row['plugin']) {
5684 $row[ 'ttype' ] = $lng->txt($row[ "type_tag" ]);
5685
5686 $rows[] = $row;
5687 continue;
5688 }
5689
5690 if (!$pluginAdmin->isActive(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name'])) {
5691 continue;
5692 }
5693
5694 $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name']);
5695 $row[ 'ttype' ] = $pl->getQuestionTypeTranslation();
5696
5697 $rows[] = $row;
5698 }
5699 }
5700 return $rows;
5701 }
5702
5707 public function fromXML(ilQTIAssessment $assessment)
5708 {
5709 unset($_SESSION["import_mob_xhtml"]);
5710
5711 $this->setDescription($assessment->getComment());
5712 $this->setTitle($assessment->getTitle());
5713
5714 $this->setIntroductionEnabled(false);
5715 foreach ($assessment->objectives as $objectives) {
5716 foreach ($objectives->materials as $material) {
5717 $intro = $this->QTIMaterialToString($material);
5718 $this->setIntroduction($intro);
5719 $this->setIntroductionEnabled(strlen($intro) > 0);
5720 }
5721 }
5722
5723 if (
5724 $assessment->getPresentationMaterial() &&
5725 $assessment->getPresentationMaterial()->getFlowMat(0) &&
5726 $assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)
5727 ) {
5728 $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)));
5729 }
5730
5731 foreach ($assessment->assessmentcontrol as $assessmentcontrol) {
5732 switch ($assessmentcontrol->getSolutionswitch()) {
5733 case "Yes":
5735 break;
5736 default:
5738 break;
5739 }
5740 }
5741
5742 $this->setStartingTimeEnabled(false);
5743 $this->setEndingTimeEnabled(false);
5744 $this->setPasswordEnabled(false);
5745 $this->setLimitUsersEnabled(false);
5746
5747 foreach ($assessment->qtimetadata as $metadata) {
5748 switch ($metadata["label"]) {
5749 case "test_type":
5750 // for old tests with a test type
5751 $type = $metadata["entry"];
5752 switch ($type) {
5753 case 1:
5754 // assessment
5755 $this->setAnonymity(1);
5756 break;
5757 case 2:
5758 // self assessment
5759 break;
5760 case 4:
5761 // online exam
5762 $this->setFixedParticipants(1);
5764 $this->setShowSolutionPrintview(1);
5765 break;
5766 case 5:
5767 // varying random test
5768 break;
5769 }
5770 break;
5771 case "sequence_settings":
5772 $this->setSequenceSettings($metadata["entry"]);
5773 break;
5774 case "solution_details":
5775 $this->setShowSolutionDetails((int) $metadata["entry"]);
5776 break;
5777 case "print_bs_with_res":
5778 $this->setPrintBestSolutionWithResult((int) $metadata["entry"]);
5779 break;
5780 case "author":
5781 $this->setAuthor($metadata["entry"]);
5782 break;
5783 case "nr_of_tries":
5784 $this->setNrOfTries($metadata["entry"]);
5785 break;
5786 case 'block_after_passed':
5787 $this->setBlockPassesAfterPassedEnabled((bool) $metadata['entry']);
5788 break;
5789 case "pass_waiting":
5790 $this->setPassWaiting($metadata["entry"]);
5791 break;
5792 case "kiosk":
5793 $this->setKiosk($metadata["entry"]);
5794 break;
5795 case "showfinalstatement":
5796 $this->setShowFinalStatement($metadata["entry"]);
5797 break;
5798 case "showinfo":
5799 $this->setShowInfo($metadata["entry"]);
5800 break;
5801 case "forcejs":
5802 $this->setForceJS($metadata["entry"]);
5803 break;
5804 case "customstyle":
5805 $this->setCustomStyle($metadata["entry"]);
5806 break;
5807
5808 case "highscore_enabled":
5809 $this->setHighscoreEnabled($metadata["entry"]);
5810 break;
5811
5812 case "highscore_anon":
5813 $this->setHighscoreAnon($metadata["entry"]);
5814 break;
5815
5816 case "highscore_achieved_ts":
5817 $this->setHighscoreAchievedTS($metadata["entry"]);
5818 break;
5819
5820 case "highscore_score":
5821 $this->setHighscoreScore($metadata["entry"]);
5822 break;
5823
5824 case "highscore_percentage":
5825 $this->setHighscorePercentage($metadata["entry"]);
5826 break;
5827
5828 case "highscore_hints":
5829 $this->setHighscoreHints($metadata["entry"]);
5830 break;
5831
5832 case "highscore_wtime":
5833 $this->setHighscoreWTime($metadata["entry"]);
5834 break;
5835
5836 case "highscore_own_table":
5837 $this->setHighscoreOwnTable($metadata["entry"]);
5838 break;
5839
5840 case "highscore_top_table":
5841 $this->setHighscoreTopTable($metadata["entry"]);
5842 break;
5843
5844 case "highscore_top_num":
5845 $this->setHighscoreTopNum($metadata["entry"]);
5846 break;
5847
5848 case "hide_previous_results":
5849 if ($metadata["entry"] == 0) {
5850 $this->setUsePreviousAnswers(1);
5851 } else {
5852 $this->setUsePreviousAnswers(0);
5853 }
5854 break;
5855 case "use_previous_answers":
5856 $this->setUsePreviousAnswers($metadata["entry"]);
5857 break;
5858 case "answer_feedback":
5859 $this->setAnswerFeedback($metadata["entry"]);
5860 break;
5861 case "hide_title_points":
5862 $this->setTitleOutput($metadata["entry"]);
5863 break;
5864 case "title_output":
5865 $this->setTitleOutput($metadata["entry"]);
5866 break;
5867 case "question_set_type":
5868 $this->setQuestionSetType($metadata["entry"]);
5869 break;
5870 case "random_test":
5871 if ($metadata["entry"]) {
5872 $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
5873 } else {
5874 $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
5875 }
5876 break;
5877 case "results_presentation":
5878 $this->setResultsPresentation($metadata["entry"]);
5879 break;
5880 case "reset_processing_time":
5881 $this->setResetProcessingTime($metadata["entry"]);
5882 break;
5883 case "instant_verification":
5884 $this->setInstantFeedbackSolution($metadata["entry"]);
5885 break;
5886 case "follow_qst_answer_fixation":
5887 $this->setFollowupQuestionAnswerFixationEnabled((bool) $metadata["entry"]);
5888 break;
5889 case "instant_feedback_answer_fixation":
5890 $this->setInstantFeedbackAnswerFixationEnabled((bool) $metadata["entry"]);
5891 break;
5892 case "force_instant_feedback":
5893 $this->setForceInstantFeedbackEnabled((bool) $metadata["entry"]);
5894 break;
5895 case "answer_feedback_points":
5896 $this->setAnswerFeedbackPoints($metadata["entry"]);
5897 break;
5898 case "anonymity":
5899 $this->setAnonymity($metadata["entry"]);
5900 break;
5901 case "use_pool":
5902 $this->setPoolUsage((int) $metadata["entry"]);
5903 break;
5904 case "show_cancel":
5905 $this->setShowCancel($metadata["entry"]);
5906 break;
5907 case "show_marker":
5908 $this->setShowMarker($metadata["entry"]);
5909 break;
5910 case "fixed_participants":
5911 $this->setFixedParticipants($metadata["entry"]);
5912 break;
5913 case "score_reporting":
5914 $this->setScoreReporting($metadata["entry"]);
5915 break;
5916 case "shuffle_questions":
5917 $this->setShuffleQuestions($metadata["entry"]);
5918 break;
5919 case "count_system":
5920 $this->setCountSystem($metadata["entry"]);
5921 break;
5922 case "mc_scoring":
5923 $this->setMCScoring($metadata["entry"]);
5924 break;
5925 case "mailnotification":
5926 $this->setMailNotification($metadata["entry"]);
5927 break;
5928 case "mailnottype":
5929 $this->setMailNotificationType($metadata["entry"]);
5930 break;
5931 case "exportsettings":
5932 $this->setExportSettings($metadata['entry']);
5933 break;
5934 case "score_cutting":
5935 $this->setScoreCutting($metadata["entry"]);
5936 break;
5937 case "password":
5938 $this->setPassword($metadata["entry"]);
5939 $this->setPasswordEnabled(strlen($metadata["entry"]) > 0);
5940 break;
5941 case "allowedUsers":
5942 $this->setAllowedUsers($metadata["entry"]);
5943 $this->setLimitUsersEnabled((int) $metadata["entry"] > 0);
5944 break;
5945 case "allowedUsersTimeGap":
5946 $this->setAllowedUsersTimeGap($metadata["entry"]);
5947 break;
5948 case "pass_scoring":
5949 $this->setPassScoring($metadata["entry"]);
5950 break;
5951 case 'pass_deletion_allowed':
5952 $this->setPassDeletionAllowed((int) $metadata['entry']);
5953 break;
5954 case "show_summary":
5955 $this->setListOfQuestionsSettings($metadata["entry"]);
5956 break;
5957 case "reporting_date":
5958 $iso8601period = $metadata["entry"];
5959 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5960 $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
5961 }
5962 break;
5963 case 'enable_processing_time':
5964 $this->setEnableProcessingTime($metadata['entry']);
5965 break;
5966 case "processing_time":
5967 $this->setProcessingTime($metadata['entry']);
5968 break;
5969 case "starting_time":
5970 $iso8601period = $metadata["entry"];
5971 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5972 $date_time = new ilDateTime(sprintf("%02d-%02d-%02d %02d:%02d:%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]), IL_CAL_DATETIME);
5973 $this->setStartingTime($date_time->get(IL_CAL_UNIX));
5974 $this->setStartingTimeEnabled(true);
5975 }
5976 break;
5977 case "ending_time":
5978 $iso8601period = $metadata["entry"];
5979 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5980 $date_time = new ilDateTime(sprintf("%02d-%02d-%02d %02d:%02d:%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]), IL_CAL_DATETIME);
5981 $this->setEndingTime($date_time->get(IL_CAL_UNIX));
5982 $this->setEndingTimeEnabled(true);
5983 }
5984 break;
5985 case "enable_examview":
5986 $this->setEnableExamview($metadata["entry"]);
5987 break;
5988 case 'show_examview_html':
5989 $this->setShowExamviewHtml($metadata['entry']);
5990 break;
5991 case 'show_examview_pdf':
5992 $this->setShowExamviewPdf($metadata['entry']);
5993 break;
5994 case 'redirection_mode':
5995 $this->setRedirectionMode($metadata['entry']);
5996 break;
5997 case 'redirection_url':
5998 $this->setRedirectionUrl($metadata['entry']);
5999 break;
6000 case 'examid_in_kiosk':
6001 case 'examid_in_test_pass':
6002 $this->setShowExamIdInTestPassEnabled($metadata['entry']);
6003 break;
6004 case 'show_exam_id':
6005 case 'examid_in_test_res':
6006 $this->setShowExamIdInTestResultsEnabled($metadata['entry']);
6007 break;
6008 case 'enable_archiving':
6009 $this->setEnableArchiving($metadata['entry']);
6010 break;
6011 case 'sign_submission':
6012 $this->setSignSubmission($metadata['entry']);
6013 break;
6014 case 'char_selector_availability':
6015 $this->setCharSelectorAvailability($metadata['entry']);
6016 break;
6017 case 'char_selector_definition':
6018 $this->setCharSelectorDefinition($metadata['entry']);
6019 break;
6020 case 'skill_service':
6021 $this->setSkillServiceEnabled((bool) $metadata['entry']);
6022 break;
6023 case 'result_tax_filters':
6024 $this->setResultFilterTaxIds(strlen($metadata['entry']) ? unserialize($metadata['entry']) : array());
6025 break;
6026 case 'show_grading_status':
6027 $this->setShowGradingStatusEnabled((bool) $metadata['entry']);
6028 break;
6029 case 'show_grading_mark':
6030 $this->setShowGradingMarkEnabled((bool) $metadata['entry']);
6031 break;
6032 case 'activation_limited':
6033 $this->setActivationLimited($metadata['entry']);
6034 break;
6035 case 'activation_start_time':
6036 $this->setActivationStartingTime($metadata['entry']);
6037 break;
6038 case 'activation_end_time':
6039 $this->setActivationEndingTime($metadata['entry']);
6040 break;
6041 case 'activation_visibility':
6042 $this->setActivationVisibility($metadata['entry']);
6043 break;
6044 case 'autosave':
6045 $this->setAutosave($metadata['entry']);
6046 break;
6047 case 'autosave_ival':
6048 $this->setAutosaveIval($metadata['entry']);
6049 break;
6050 case 'offer_question_hints':
6051 $this->setOfferingQuestionHintsEnabled($metadata['entry']);
6052 break;
6053 case 'instant_feedback_specific':
6054 $this->setSpecificAnswerFeedback($metadata['entry']);
6055 break;
6056 case 'obligations_enabled':
6057 $this->setObligationsEnabled($metadata['entry']);
6058 break;
6059 }
6060 if (preg_match("/mark_step_\d+/", $metadata["label"])) {
6061 $xmlmark = $metadata["entry"];
6062 preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
6063 $mark_short = $matches[1];
6064 preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
6065 $mark_official = $matches[1];
6066 preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
6067 $mark_percentage = $matches[1];
6068 preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
6069 $mark_passed = $matches[1];
6070 $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
6071 }
6072 }
6073 // handle the import of media objects in XHTML code
6074 if (is_array($_SESSION["import_mob_xhtml"])) {
6075 include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6076 include_once "./Services/RTE/classes/class.ilRTE.php";
6077 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
6078 foreach ($_SESSION["import_mob_xhtml"] as $mob) {
6079 $importfile = ilObjTest::_getImportDirectory() . '/' . $_SESSION["tst_import_subdir"] . '/' . $mob["uri"];
6080 if (file_exists($importfile)) {
6081 $media_object = &ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false);
6082 ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
6083 $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
6084 $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
6085 } else {
6086 global $DIC;
6087 $ilLog = $DIC['ilLog'];
6088 $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
6089 }
6090 }
6091 $this->saveToDb();
6092 }
6093 }
6094
6100 public function toXML()
6101 {
6102 include_once("./Services/Xml/classes/class.ilXmlWriter.php");
6103 $a_xml_writer = new ilXmlWriter;
6104 // set xml header
6105 $a_xml_writer->xmlHeader();
6106 $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
6107 $a_xml_writer->xmlStartTag("questestinterop");
6108
6109 $attrs = array(
6110 "ident" => "il_" . IL_INST_ID . "_tst_" . $this->getTestId(),
6111 "title" => $this->getTitle()
6112 );
6113 $a_xml_writer->xmlStartTag("assessment", $attrs);
6114 // add qti comment
6115 $a_xml_writer->xmlElement("qticomment", null, $this->getDescription());
6116
6117 // add qti duration
6118 if ($this->enable_processing_time) {
6119 preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
6120 $a_xml_writer->xmlElement("duration", null, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
6121 }
6122
6123 // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
6124 $a_xml_writer->xmlStartTag("qtimetadata");
6125 $a_xml_writer->xmlStartTag("qtimetadatafield");
6126 $a_xml_writer->xmlElement("fieldlabel", null, "ILIAS_VERSION");
6127 $a_xml_writer->xmlElement("fieldentry", null, $this->ilias->getSetting("ilias_version"));
6128 $a_xml_writer->xmlEndTag("qtimetadatafield");
6129
6130 // anonymity
6131 $a_xml_writer->xmlStartTag("qtimetadatafield");
6132 $a_xml_writer->xmlElement("fieldlabel", null, "anonymity");
6133 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnonymity()));
6134 $a_xml_writer->xmlEndTag("qtimetadatafield");
6135
6136 $a_xml_writer->xmlStartTag("qtimetadatafield");
6137 $a_xml_writer->xmlElement("fieldlabel", null, "use_pool");
6138 $a_xml_writer->xmlElement("fieldentry", null, $this->getPoolUsage() ? 1 : 0);
6139 $a_xml_writer->xmlEndTag("qtimetadatafield");
6140
6141 // question set type (fixed, random, dynamic, ...)
6142 $a_xml_writer->xmlStartTag("qtimetadatafield");
6143 $a_xml_writer->xmlElement("fieldlabel", null, "question_set_type");
6144 $a_xml_writer->xmlElement("fieldentry", null, $this->getQuestionSetType());
6145 $a_xml_writer->xmlEndTag("qtimetadatafield");
6146
6147 // sequence settings
6148 $a_xml_writer->xmlStartTag("qtimetadatafield");
6149 $a_xml_writer->xmlElement("fieldlabel", null, "sequence_settings");
6150 $a_xml_writer->xmlElement("fieldentry", null, $this->getSequenceSettings());
6151 $a_xml_writer->xmlEndTag("qtimetadatafield");
6152
6153 // author
6154 $a_xml_writer->xmlStartTag("qtimetadatafield");
6155 $a_xml_writer->xmlElement("fieldlabel", null, "author");
6156 $a_xml_writer->xmlElement("fieldentry", null, $this->getAuthor());
6157 $a_xml_writer->xmlEndTag("qtimetadatafield");
6158
6159 // reset processing time
6160 $a_xml_writer->xmlStartTag("qtimetadatafield");
6161 $a_xml_writer->xmlElement("fieldlabel", null, "reset_processing_time");
6162 $a_xml_writer->xmlElement("fieldentry", null, $this->getResetProcessingTime());
6163 $a_xml_writer->xmlEndTag("qtimetadatafield");
6164
6165 // count system
6166 $a_xml_writer->xmlStartTag("qtimetadatafield");
6167 $a_xml_writer->xmlElement("fieldlabel", null, "count_system");
6168 $a_xml_writer->xmlElement("fieldentry", null, $this->getCountSystem());
6169 $a_xml_writer->xmlEndTag("qtimetadatafield");
6170
6171 // multiple choice scoring
6172 $a_xml_writer->xmlStartTag("qtimetadatafield");
6173 $a_xml_writer->xmlElement("fieldlabel", null, "mc_scoring");
6174 $a_xml_writer->xmlElement("fieldentry", null, $this->getMCScoring());
6175 $a_xml_writer->xmlEndTag("qtimetadatafield");
6176
6177 // multiple choice scoring
6178 $a_xml_writer->xmlStartTag("qtimetadatafield");
6179 $a_xml_writer->xmlElement("fieldlabel", null, "score_cutting");
6180 $a_xml_writer->xmlElement("fieldentry", null, $this->getScoreCutting());
6181 $a_xml_writer->xmlEndTag("qtimetadatafield");
6182
6183 // multiple choice scoring
6184 $a_xml_writer->xmlStartTag("qtimetadatafield");
6185 $a_xml_writer->xmlElement("fieldlabel", null, "password");
6186 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassword());
6187 $a_xml_writer->xmlEndTag("qtimetadatafield");
6188
6189 // allowed users
6190 $a_xml_writer->xmlStartTag("qtimetadatafield");
6191 $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsers");
6192 $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsers());
6193 $a_xml_writer->xmlEndTag("qtimetadatafield");
6194
6195 // allowed users time gap
6196 $a_xml_writer->xmlStartTag("qtimetadatafield");
6197 $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsersTimeGap");
6198 $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsersTimeGap());
6199 $a_xml_writer->xmlEndTag("qtimetadatafield");
6200
6201 // pass scoring
6202 $a_xml_writer->xmlStartTag("qtimetadatafield");
6203 $a_xml_writer->xmlElement("fieldlabel", null, "pass_scoring");
6204 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassScoring());
6205 $a_xml_writer->xmlEndTag("qtimetadatafield");
6206
6207 $a_xml_writer->xmlStartTag('qtimetadatafield');
6208 $a_xml_writer->xmlElement('fieldlabel', null, 'pass_deletion_allowed');
6209 $a_xml_writer->xmlElement('fieldentry', null, (int) $this->isPassDeletionAllowed());
6210 $a_xml_writer->xmlEndTag('qtimetadatafield');
6211
6212 // score reporting date
6213 if ($this->getReportingDate()) {
6214 $a_xml_writer->xmlStartTag("qtimetadatafield");
6215 $a_xml_writer->xmlElement("fieldlabel", null, "reporting_date");
6216 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6217 $a_xml_writer->xmlElement("fieldentry", null, sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6218 $a_xml_writer->xmlEndTag("qtimetadatafield");
6219 }
6220 // number of tries
6221 $a_xml_writer->xmlStartTag("qtimetadatafield");
6222 $a_xml_writer->xmlElement("fieldlabel", null, "nr_of_tries");
6223 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getNrOfTries()));
6224 $a_xml_writer->xmlEndTag("qtimetadatafield");
6225
6226 // number of tries
6227 $a_xml_writer->xmlStartTag('qtimetadatafield');
6228 $a_xml_writer->xmlElement('fieldlabel', null, 'block_after_passed');
6229 $a_xml_writer->xmlElement('fieldentry', null, (int) $this->isBlockPassesAfterPassedEnabled());
6230 $a_xml_writer->xmlEndTag('qtimetadatafield');
6231
6232 // pass_waiting
6233 $a_xml_writer->xmlStartTag("qtimetadatafield");
6234 $a_xml_writer->xmlElement("fieldlabel", null, "pass_waiting");
6235 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassWaiting());
6236 $a_xml_writer->xmlEndTag("qtimetadatafield");
6237
6238 // kiosk
6239 $a_xml_writer->xmlStartTag("qtimetadatafield");
6240 $a_xml_writer->xmlElement("fieldlabel", null, "kiosk");
6241 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getKiosk()));
6242 $a_xml_writer->xmlEndTag("qtimetadatafield");
6243
6244
6245 //redirection_mode
6246 $a_xml_writer->xmlStartTag('qtimetadatafield');
6247 $a_xml_writer->xmlElement("fieldlabel", null, "redirection_mode");
6248 $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionMode());
6249 $a_xml_writer->xmlEndTag("qtimetadatafield");
6250
6251 //redirection_url
6252 $a_xml_writer->xmlStartTag('qtimetadatafield');
6253 $a_xml_writer->xmlElement("fieldlabel", null, "redirection_url");
6254 $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionUrl());
6255 $a_xml_writer->xmlEndTag("qtimetadatafield");
6256
6257 // use previous answers
6258 $a_xml_writer->xmlStartTag("qtimetadatafield");
6259 $a_xml_writer->xmlElement("fieldlabel", null, "use_previous_answers");
6260 $a_xml_writer->xmlElement("fieldentry", null, $this->getUsePreviousAnswers());
6261 $a_xml_writer->xmlEndTag("qtimetadatafield");
6262
6263 // hide title points
6264 $a_xml_writer->xmlStartTag("qtimetadatafield");
6265 $a_xml_writer->xmlElement("fieldlabel", null, "title_output");
6266 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getTitleOutput()));
6267 $a_xml_writer->xmlEndTag("qtimetadatafield");
6268
6269 // results presentation
6270 $a_xml_writer->xmlStartTag("qtimetadatafield");
6271 $a_xml_writer->xmlElement("fieldlabel", null, "results_presentation");
6272 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getResultsPresentation()));
6273 $a_xml_writer->xmlEndTag("qtimetadatafield");
6274
6275 // examid in test pass
6276 $a_xml_writer->xmlStartTag("qtimetadatafield");
6277 $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_pass");
6278 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestPassEnabled()));
6279 $a_xml_writer->xmlEndTag("qtimetadatafield");
6280
6281 // examid in kiosk
6282 $a_xml_writer->xmlStartTag("qtimetadatafield");
6283 $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_res");
6284 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestResultsEnabled()));
6285 $a_xml_writer->xmlEndTag("qtimetadatafield");
6286
6287 // solution details
6288 $a_xml_writer->xmlStartTag("qtimetadatafield");
6289 $a_xml_writer->xmlElement("fieldlabel", null, "show_summary");
6290 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getListOfQuestionsSettings()));
6291 $a_xml_writer->xmlEndTag("qtimetadatafield");
6292
6293 // solution details
6294 $a_xml_writer->xmlStartTag("qtimetadatafield");
6295 $a_xml_writer->xmlElement("fieldlabel", null, "score_reporting");
6296 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getScoreReporting()));
6297 $a_xml_writer->xmlEndTag("qtimetadatafield");
6298
6299 $a_xml_writer->xmlStartTag("qtimetadatafield");
6300 $a_xml_writer->xmlElement("fieldlabel", null, "solution_details");
6301 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails());
6302 $a_xml_writer->xmlEndTag("qtimetadatafield");
6303 $a_xml_writer->xmlStartTag("qtimetadatafield");
6304 $a_xml_writer->xmlElement("fieldlabel", null, "print_bs_with_res");
6305 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails() ? (int) $this->isBestSolutionPrintedWithResult() : 0);
6306 $a_xml_writer->xmlEndTag("qtimetadatafield");
6307
6308 // solution details
6309 $a_xml_writer->xmlStartTag("qtimetadatafield");
6310 $a_xml_writer->xmlElement("fieldlabel", null, "instant_verification");
6311 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getInstantFeedbackSolution()));
6312 $a_xml_writer->xmlEndTag("qtimetadatafield");
6313
6314 // answer specific feedback
6315 $a_xml_writer->xmlStartTag("qtimetadatafield");
6316 $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback");
6317 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedback()));
6318 $a_xml_writer->xmlEndTag("qtimetadatafield");
6319
6320 // answer specific feedback of reached points
6321 $a_xml_writer->xmlStartTag("qtimetadatafield");
6322 $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback_points");
6323 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedbackPoints()));
6324 $a_xml_writer->xmlEndTag("qtimetadatafield");
6325
6326 // followup question previous answer freezing
6327 $a_xml_writer->xmlStartTag("qtimetadatafield");
6328 $a_xml_writer->xmlElement("fieldlabel", null, "follow_qst_answer_fixation");
6329 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isFollowupQuestionAnswerFixationEnabled());
6330 $a_xml_writer->xmlEndTag("qtimetadatafield");
6331
6332 // instant response answer freezing
6333 $a_xml_writer->xmlStartTag("qtimetadatafield");
6334 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6335 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6336 $a_xml_writer->xmlEndTag("qtimetadatafield");
6337
6338 // instant response forced
6339 $a_xml_writer->xmlStartTag("qtimetadatafield");
6340 $a_xml_writer->xmlElement("fieldlabel", null, "force_instant_feedback");
6341 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isForceInstantFeedbackEnabled());
6342 $a_xml_writer->xmlEndTag("qtimetadatafield");
6343
6344
6345 // highscore
6346 $highscore_metadata = array(
6347 'highscore_enabled' => array('value' => $this->getHighscoreEnabled()),
6348 'highscore_anon' => array('value' => $this->getHighscoreAnon()),
6349 'highscore_achieved_ts' => array('value' => $this->getHighscoreAchievedTS()),
6350 'highscore_score' => array('value' => $this->getHighscoreScore()),
6351 'highscore_percentage' => array('value' => $this->getHighscorePercentage()),
6352 'highscore_hints' => array('value' => $this->getHighscoreHints()),
6353 'highscore_wtime' => array('value' => $this->getHighscoreWTime()),
6354 'highscore_own_table' => array('value' => $this->getHighscoreOwnTable()),
6355 'highscore_top_table' => array('value' => $this->getHighscoreTopTable()),
6356 'highscore_top_num' => array('value' => $this->getHighscoreTopNum()),
6357 );
6358 foreach ($highscore_metadata as $label => $data) {
6359 $a_xml_writer->xmlStartTag("qtimetadatafield");
6360 $a_xml_writer->xmlElement("fieldlabel", null, $label);
6361 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $data['value']));
6362 $a_xml_writer->xmlEndTag("qtimetadatafield");
6363 }
6364
6365 // show cancel
6366 $a_xml_writer->xmlStartTag("qtimetadatafield");
6367 $a_xml_writer->xmlElement("fieldlabel", null, "show_cancel");
6368 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowCancel()));
6369 $a_xml_writer->xmlEndTag("qtimetadatafield");
6370
6371 // show marker
6372 $a_xml_writer->xmlStartTag("qtimetadatafield");
6373 $a_xml_writer->xmlElement("fieldlabel", null, "show_marker");
6374 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowMarker()));
6375 $a_xml_writer->xmlEndTag("qtimetadatafield");
6376
6377 // fixed participants
6378 $a_xml_writer->xmlStartTag("qtimetadatafield");
6379 $a_xml_writer->xmlElement("fieldlabel", null, "fixed_participants");
6380 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getFixedParticipants()));
6381 $a_xml_writer->xmlEndTag("qtimetadatafield");
6382
6383 // show final statement
6384 $a_xml_writer->xmlStartTag("qtimetadatafield");
6385 $a_xml_writer->xmlElement("fieldlabel", null, "showfinalstatement");
6386 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6387 $a_xml_writer->xmlEndTag("qtimetadatafield");
6388
6389 // show introduction only
6390 $a_xml_writer->xmlStartTag("qtimetadatafield");
6391 $a_xml_writer->xmlElement("fieldlabel", null, "showinfo");
6392 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6393 $a_xml_writer->xmlEndTag("qtimetadatafield");
6394
6395 // mail notification
6396 $a_xml_writer->xmlStartTag("qtimetadatafield");
6397 $a_xml_writer->xmlElement("fieldlabel", null, "mailnotification");
6398 $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotification());
6399 $a_xml_writer->xmlEndTag("qtimetadatafield");
6400
6401 // mail notification type
6402 $a_xml_writer->xmlStartTag("qtimetadatafield");
6403 $a_xml_writer->xmlElement("fieldlabel", null, "mailnottype");
6404 $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotificationType());
6405 $a_xml_writer->xmlEndTag("qtimetadatafield");
6406
6407 // export settings
6408 $a_xml_writer->xmlStartTag("qtimetadatafield");
6409 $a_xml_writer->xmlElement("fieldlabel", null, "exportsettings");
6410 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getExportSettings());
6411 $a_xml_writer->xmlEndTag("qtimetadatafield");
6412
6413 // force JavaScript
6414 $a_xml_writer->xmlStartTag("qtimetadatafield");
6415 $a_xml_writer->xmlElement("fieldlabel", null, "forcejs");
6416 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6417 $a_xml_writer->xmlEndTag("qtimetadatafield");
6418
6419 // custom style
6420 $a_xml_writer->xmlStartTag("qtimetadatafield");
6421 $a_xml_writer->xmlElement("fieldlabel", null, "customstyle");
6422 $a_xml_writer->xmlElement("fieldentry", null, $this->getCustomStyle());
6423 $a_xml_writer->xmlEndTag("qtimetadatafield");
6424
6425 // shuffle questions
6426 $a_xml_writer->xmlStartTag("qtimetadatafield");
6427 $a_xml_writer->xmlElement("fieldlabel", null, "shuffle_questions");
6428 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShuffleQuestions()));
6429 $a_xml_writer->xmlEndTag("qtimetadatafield");
6430
6431 // processing time
6432 $a_xml_writer->xmlStartTag("qtimetadatafield");
6433 $a_xml_writer->xmlElement("fieldlabel", null, "processing_time");
6434 $a_xml_writer->xmlElement("fieldentry", null, $this->getProcessingTime());
6435 $a_xml_writer->xmlEndTag("qtimetadatafield");
6436
6437 // enable_examview
6438 $a_xml_writer->xmlStartTag("qtimetadatafield");
6439 $a_xml_writer->xmlElement("fieldlabel", null, "enable_examview");
6440 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableExamview());
6441 $a_xml_writer->xmlEndTag("qtimetadatafield");
6442
6443 // show_examview_html
6444 $a_xml_writer->xmlStartTag("qtimetadatafield");
6445 $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_html");
6446 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewHtml());
6447 $a_xml_writer->xmlEndTag("qtimetadatafield");
6448
6449 // show_examview_pdf
6450 $a_xml_writer->xmlStartTag("qtimetadatafield");
6451 $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_pdf");
6452 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewPdf());
6453 $a_xml_writer->xmlEndTag("qtimetadatafield");
6454
6455 // enable_archiving
6456 $a_xml_writer->xmlStartTag("qtimetadatafield");
6457 $a_xml_writer->xmlElement("fieldlabel", null, "enable_archiving");
6458 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableArchiving());
6459 $a_xml_writer->xmlEndTag("qtimetadatafield");
6460
6461 // sign_submission
6462 $a_xml_writer->xmlStartTag("qtimetadatafield");
6463 $a_xml_writer->xmlElement("fieldlabel", null, "sign_submission");
6464 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSignSubmission());
6465 $a_xml_writer->xmlEndTag("qtimetadatafield");
6466
6467 // char_selector_availability
6468 $a_xml_writer->xmlStartTag("qtimetadatafield");
6469 $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_availability");
6470 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getCharSelectorAvailability()));
6471 $a_xml_writer->xmlEndTag("qtimetadatafield");
6472
6473 // char_selector_definition
6474 $a_xml_writer->xmlStartTag("qtimetadatafield");
6475 $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_definition");
6476 $a_xml_writer->xmlElement("fieldentry", null, $this->getCharSelectorDefinition());
6477 $a_xml_writer->xmlEndTag("qtimetadatafield");
6478
6479 // skill_service
6480 $a_xml_writer->xmlStartTag("qtimetadatafield");
6481 $a_xml_writer->xmlElement("fieldlabel", null, "skill_service");
6482 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isSkillServiceEnabled());
6483 $a_xml_writer->xmlEndTag("qtimetadatafield");
6484
6485 // result_tax_filters
6486 $a_xml_writer->xmlStartTag("qtimetadatafield");
6487 $a_xml_writer->xmlElement("fieldlabel", null, "result_tax_filters");
6488 $a_xml_writer->xmlElement("fieldentry", null, serialize((array) $this->getResultFilterTaxIds()));
6489 $a_xml_writer->xmlEndTag("qtimetadatafield");
6490
6491 // show_grading_status
6492 $a_xml_writer->xmlStartTag("qtimetadatafield");
6493 $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_status");
6494 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingStatusEnabled());
6495 $a_xml_writer->xmlEndTag("qtimetadatafield");
6496
6497 // show_grading_mark
6498 $a_xml_writer->xmlStartTag("qtimetadatafield");
6499 $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_mark");
6500 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingMarkEnabled());
6501 $a_xml_writer->xmlEndTag("qtimetadatafield");
6502
6503
6504 // starting time
6505 if ($this->getStartingTime()) {
6506 $a_xml_writer->xmlStartTag("qtimetadatafield");
6507 $a_xml_writer->xmlElement("fieldlabel", null, "starting_time");
6508 $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->starting_time);
6509 $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6510 $a_xml_writer->xmlEndTag("qtimetadatafield");
6511 }
6512 // ending time
6513 if ($this->getEndingTime()) {
6514 $a_xml_writer->xmlStartTag("qtimetadatafield");
6515 $a_xml_writer->xmlElement("fieldlabel", null, "ending_time");
6516 $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->ending_time);
6517 $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6518 $a_xml_writer->xmlEndTag("qtimetadatafield");
6519 }
6520
6521
6522 //activation_limited
6523 $a_xml_writer->xmlStartTag("qtimetadatafield");
6524 $a_xml_writer->xmlElement("fieldlabel", null, "activation_limited");
6525 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isActivationLimited());
6526 $a_xml_writer->xmlEndTag("qtimetadatafield");
6527
6528 //activation_start_time
6529 $a_xml_writer->xmlStartTag("qtimetadatafield");
6530 $a_xml_writer->xmlElement("fieldlabel", null, "activation_start_time");
6531 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationStartingTime());
6532 $a_xml_writer->xmlEndTag("qtimetadatafield");
6533
6534 //activation_end_time
6535 $a_xml_writer->xmlStartTag("qtimetadatafield");
6536 $a_xml_writer->xmlElement("fieldlabel", null, "activation_end_time");
6537 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationEndingTime());
6538 $a_xml_writer->xmlEndTag("qtimetadatafield");
6539
6540 //activation_visibility
6541 $a_xml_writer->xmlStartTag("qtimetadatafield");
6542 $a_xml_writer->xmlElement("fieldlabel", null, "activation_visibility");
6543 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationVisibility());
6544 $a_xml_writer->xmlEndTag("qtimetadatafield");
6545
6546 // autosave
6547 $a_xml_writer->xmlStartTag("qtimetadatafield");
6548 $a_xml_writer->xmlElement("fieldlabel", null, "autosave");
6549 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosave());
6550 $a_xml_writer->xmlEndTag("qtimetadatafield");
6551
6552 // autosave_ival
6553 $a_xml_writer->xmlStartTag("qtimetadatafield");
6554 $a_xml_writer->xmlElement("fieldlabel", null, "autosave_ival");
6555 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosaveIval());
6556 $a_xml_writer->xmlEndTag("qtimetadatafield");
6557
6558 //offer_question_hints
6559 $a_xml_writer->xmlStartTag("qtimetadatafield");
6560 $a_xml_writer->xmlElement("fieldlabel", null, "offer_question_hints");
6561 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isOfferingQuestionHintsEnabled());
6562 $a_xml_writer->xmlEndTag("qtimetadatafield");
6563
6564 //instant_feedback_specific
6565 $a_xml_writer->xmlStartTag("qtimetadatafield");
6566 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_specific");
6567 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSpecificAnswerFeedback());
6568 $a_xml_writer->xmlEndTag("qtimetadatafield");
6569
6570 //instant_feedback_answer_fixation
6571 $a_xml_writer->xmlStartTag("qtimetadatafield");
6572 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6573 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6574 $a_xml_writer->xmlEndTag("qtimetadatafield");
6575
6576 //obligations_enabled
6577 $a_xml_writer->xmlStartTag("qtimetadatafield");
6578 $a_xml_writer->xmlElement("fieldlabel", null, "obligations_enabled");
6579 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->areObligationsEnabled());
6580 $a_xml_writer->xmlEndTag("qtimetadatafield");
6581
6582 //enable_processing_time
6583 $a_xml_writer->xmlStartTag("qtimetadatafield");
6584 $a_xml_writer->xmlElement("fieldlabel", null, "enable_processing_time");
6585 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableProcessingTime());
6586 $a_xml_writer->xmlEndTag("qtimetadatafield");
6587
6588 foreach ($this->mark_schema->mark_steps as $index => $mark) {
6589 // mark steps
6590 $a_xml_writer->xmlStartTag("qtimetadatafield");
6591 $a_xml_writer->xmlElement("fieldlabel", null, "mark_step_$index");
6592 $a_xml_writer->xmlElement("fieldentry", null, sprintf(
6593 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
6594 $mark->getShortName(),
6595 $mark->getOfficialName(),
6596 $mark->getMinimumLevel(),
6597 $mark->getPassed()
6598 ));
6599 $a_xml_writer->xmlEndTag("qtimetadatafield");
6600 }
6601 $a_xml_writer->xmlEndTag("qtimetadata");
6602
6603 // add qti objectives
6604 $a_xml_writer->xmlStartTag("objectives");
6605 $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6606 $a_xml_writer->xmlEndTag("objectives");
6607
6608 // add qti assessmentcontrol
6609 if ($this->getInstantFeedbackSolution() == 1) {
6610 $attrs = array(
6611 "solutionswitch" => "Yes"
6612 );
6613 } else {
6614 $attrs = null;
6615 }
6616 $a_xml_writer->xmlElement("assessmentcontrol", $attrs, null);
6617
6618 if (strlen($this->getFinalStatement())) {
6619 // add qti presentation_material
6620 $a_xml_writer->xmlStartTag("presentation_material");
6621 $a_xml_writer->xmlStartTag("flow_mat");
6622 $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6623 $a_xml_writer->xmlEndTag("flow_mat");
6624 $a_xml_writer->xmlEndTag("presentation_material");
6625 }
6626
6627 $attrs = array(
6628 "ident" => "1"
6629 );
6630 $a_xml_writer->xmlElement("section", $attrs, null);
6631 $a_xml_writer->xmlEndTag("assessment");
6632 $a_xml_writer->xmlEndTag("questestinterop");
6633
6634 $xml = $a_xml_writer->xmlDumpMem(false);
6635 return $xml;
6636 }
6637
6643 {
6644 $date_time_unix = new ilDateTime($unix_timestamp, IL_CAL_UNIX);
6645 $date_time = $date_time_unix->get(IL_CAL_DATETIME);
6646 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $date_time, $matches);
6647 $iso8601_period = sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]);
6648 return $iso8601_period;
6649 }
6650
6657 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6658 {
6659 global $DIC;
6660 $ilBench = $DIC['ilBench'];
6661
6662 $this->mob_ids = array();
6663 $this->file_ids = array();
6664
6665 // MetaData
6666 $this->exportXMLMetaData($a_xml_writer);
6667
6668 // PageObjects
6669 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Page Objects");
6670 $ilBench->start("ContentObjectExport", "exportPageObjects");
6671 $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6672 $ilBench->stop("ContentObjectExport", "exportPageObjects");
6673 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Page Objects");
6674
6675 // MediaObjects
6676 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Media Objects");
6677 $ilBench->start("ContentObjectExport", "exportMediaObjects");
6678 $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6679 $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6680 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Media Objects");
6681
6682 // FileItems
6683 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export File Items");
6684 $ilBench->start("ContentObjectExport", "exportFileItems");
6685 $this->exportFileItems($a_target_dir, $expLog);
6686 $ilBench->stop("ContentObjectExport", "exportFileItems");
6687 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export File Items");
6688 }
6689
6696 public function exportXMLMetaData(&$a_xml_writer)
6697 {
6698 include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6699 $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6700 $md2xml->setExportMode(true);
6701 $md2xml->startExport();
6702 $a_xml_writer->appendXML($md2xml->getXML());
6703 }
6704
6710 public function modifyExportIdentifier($a_tag, $a_param, $a_value)
6711 {
6712 if ($a_tag == "Identifier" && $a_param == "Entry") {
6713 include_once "./Services/Utilities/classes/class.ilUtil.php";
6714 $a_value = ilUtil::insertInstIntoID($a_value);
6715 }
6716
6717 return $a_value;
6718 }
6719
6720
6727 public function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6728 {
6729 global $DIC;
6730 $ilBench = $DIC['ilBench'];
6731
6732 include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6733
6734 foreach ($this->questions as $question_id) {
6735 $ilBench->start("ContentObjectExport", "exportPageObject");
6736 $expLog->write(date("[y-m-d H:i:s] ") . "Page Object " . $question_id);
6737
6738 $attrs = array();
6739 $a_xml_writer->xmlStartTag("PageObject", $attrs);
6740
6741
6742 // export xml to writer object
6743 $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6744 include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
6745 $page_object = new ilAssQuestionPage($question_id);
6746 $page_object->buildDom();
6747 $page_object->insertInstIntoIDs($a_inst);
6748 $mob_ids = $page_object->collectMediaObjects(false);
6749 require_once 'Services/COPage/classes/class.ilPCFileList.php';
6750 $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
6751 $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6752 $xml = str_replace("&", "&amp;", $xml);
6753 $a_xml_writer->appendXML($xml);
6754 $page_object->freeDom();
6755 unset($page_object);
6756
6757 $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6758
6759 // collect media objects
6760 $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6761 //$mob_ids = $page_obj->getMediaObjectIDs();
6762 foreach ($mob_ids as $mob_id) {
6763 $this->mob_ids[$mob_id] = $mob_id;
6764 }
6765 $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6766
6767 // collect all file items
6768 $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6769 //$file_ids = $page_obj->getFileItemIds();
6770 foreach ($file_ids as $file_id) {
6771 $this->file_ids[$file_id] = $file_id;
6772 }
6773 $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6774
6775 $a_xml_writer->xmlEndTag("PageObject");
6776 //unset($page_obj);
6777
6778 $ilBench->stop("ContentObjectExport", "exportPageObject");
6779 }
6780 }
6781
6788 public function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6789 {
6790 include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6791
6792 foreach ($this->mob_ids as $mob_id) {
6793 $expLog->write(date("[y-m-d H:i:s] ") . "Media Object " . $mob_id);
6794 if (ilObjMediaObject::_exists($mob_id)) {
6795 $media_obj = new ilObjMediaObject($mob_id);
6796 $media_obj->exportXML($a_xml_writer, $a_inst);
6797 $media_obj->exportFiles($a_target_dir);
6798 unset($media_obj);
6799 }
6800 }
6801 }
6802
6807 public function exportFileItems($a_target_dir, &$expLog)
6808 {
6809 include_once "./Modules/File/classes/class.ilObjFile.php";
6810
6811 foreach ($this->file_ids as $file_id) {
6812 $expLog->write(date("[y-m-d H:i:s] ") . "File Item " . $file_id);
6813 $file_obj = new ilObjFile($file_id, false);
6814 $file_obj->export($a_target_dir);
6815 unset($file_obj);
6816 }
6817 }
6818
6823 public function getImportMapping()
6824 {
6825 if (!is_array($this->import_mapping)) {
6826 return array();
6827 } else {
6828 return $this->import_mapping;
6829 }
6830 }
6831
6835 public function canEditEctsGrades()
6836 {
6837 return $this->canShowEctsGrades() && $this->canEditMarks();
6838 }
6839
6843 public function canShowEctsGrades()
6844 {
6845 return $this->getReportingDate();
6846 }
6847
6851 public function getECTSGrade($passed_array, $reached_points, $max_points)
6852 {
6853 return self::_getECTSGrade($passed_array, $reached_points, $max_points, $this->ects_grades["A"], $this->ects_grades["B"], $this->ects_grades["C"], $this->ects_grades["D"], $this->ects_grades["E"], $this->ects_fx);
6854 }
6855
6859 public static function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6860 {
6861 include_once "./Modules/Test/classes/class.ilStatistics.php";
6862 // calculate the median
6863 $passed_statistics = new ilStatistics();
6864 $passed_statistics->setData($points_passed);
6865 $ects_percentiles = array(
6866 "A" => $passed_statistics->quantile($a),
6867 "B" => $passed_statistics->quantile($b),
6868 "C" => $passed_statistics->quantile($c),
6869 "D" => $passed_statistics->quantile($d),
6870 "E" => $passed_statistics->quantile($e)
6871 );
6872 if (count($points_passed) && ($reached_points >= $ects_percentiles["A"])) {
6873 return "A";
6874 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["B"])) {
6875 return "B";
6876 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["C"])) {
6877 return "C";
6878 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["D"])) {
6879 return "D";
6880 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["E"])) {
6881 return "E";
6882 } elseif (strcmp($fx, "") != 0) {
6883 if ($max_points > 0) {
6884 $percentage = ($reached_points / $max_points) * 100.0;
6885 if ($percentage < 0) {
6886 $percentage = 0.0;
6887 }
6888 } else {
6889 $percentage = 0.0;
6890 }
6891 if ($percentage >= $fx) {
6892 return "FX";
6893 } else {
6894 return "F";
6895 }
6896 } else {
6897 return "F";
6898 }
6899 }
6900
6904 public function checkMarks()
6905 {
6906 return $this->mark_schema->checkMarks();
6907 }
6908
6912 public function getMarkSchema()
6913 {
6914 return $this->mark_schema;
6915 }
6916
6920 public function getMarkSchemaForeignId()
6921 {
6922 return $this->getTestId();
6923 }
6924
6927 public function onMarkSchemaSaved()
6928 {
6934 global $DIC;
6935 $ilDB = $DIC['ilDB'];
6936 $ilPluginAdmin = $DIC['ilPluginAdmin'];
6937 $tree = $DIC['tree'];
6938
6939 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
6940 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
6941 $this->saveCompleteStatus($testQuestionSetConfigFactory->getQuestionSetConfig());
6942
6943 if ($this->participantDataExist()) {
6944 $this->recalculateScores(true);
6945 }
6946 }
6947
6951 public function canEditMarks()
6952 {
6953 $total = $this->evalTotalPersons();
6954 if ($total > 0) {
6955 if ($this->getReportingDate()) {
6956 if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches)) {
6957 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
6958 $now = time();
6959 if ($now < $epoch_time) {
6960 return true;
6961 }
6962 }
6963 }
6964 return false;
6965 } else {
6966 return true;
6967 }
6968 }
6969
6977 public function setAuthor($author = "")
6978 {
6979 $this->author = $author;
6980 }
6981
6991 public function saveAuthorToMetadata($a_author = "")
6992 {
6993 $md = new ilMD($this->getId(), 0, $this->getType());
6994 $md_life = &$md->getLifecycle();
6995 if (!$md_life) {
6996 if (strlen($a_author) == 0) {
6997 global $DIC;
6998 $ilUser = $DIC['ilUser'];
6999 $a_author = $ilUser->getFullname();
7000 }
7001
7002 $md_life = &$md->addLifecycle();
7003 $md_life->save();
7004 $con = &$md_life->addContribute();
7005 $con->setRole("Author");
7006 $con->save();
7007 $ent = &$con->addEntity();
7008 $ent->setEntity($a_author);
7009 $ent->save();
7010 }
7011 }
7012
7018 public function createMetaData()
7019 {
7020 parent::createMetaData();
7021 $this->saveAuthorToMetadata();
7022 }
7023
7031 public function getAuthor()
7032 {
7033 $author = array();
7034 include_once "./Services/MetaData/classes/class.ilMD.php";
7035 $md = new ilMD($this->getId(), 0, $this->getType());
7036 $md_life = &$md->getLifecycle();
7037 if ($md_life) {
7038 $ids = &$md_life->getContributeIds();
7039 foreach ($ids as $id) {
7040 $md_cont = &$md_life->getContribute($id);
7041 if (strcmp($md_cont->getRole(), "Author") == 0) {
7042 $entids = &$md_cont->getEntityIds();
7043 foreach ($entids as $entid) {
7044 $md_ent = &$md_cont->getEntity($entid);
7045 array_push($author, $md_ent->getEntity());
7046 }
7047 }
7048 }
7049 }
7050 return join(",", $author);
7051 }
7052
7060 public static function _lookupAuthor($obj_id)
7061 {
7062 $author = array();
7063 include_once "./Services/MetaData/classes/class.ilMD.php";
7064 $md = new ilMD($obj_id, 0, "tst");
7065 $md_life = &$md->getLifecycle();
7066 if ($md_life) {
7067 $ids = &$md_life->getContributeIds();
7068 foreach ($ids as $id) {
7069 $md_cont = &$md_life->getContribute($id);
7070 if (strcmp($md_cont->getRole(), "Author") == 0) {
7071 $entids = &$md_cont->getEntityIds();
7072 foreach ($entids as $entid) {
7073 $md_ent = &$md_cont->getEntity($entid);
7074 array_push($author, $md_ent->getEntity());
7075 }
7076 }
7077 }
7078 }
7079 return join(",", $author);
7080 }
7081
7088 public static function _getAvailableTests($use_object_id = false)
7089 {
7090 global $DIC;
7091 $ilUser = $DIC['ilUser'];
7092 $ilDB = $DIC['ilDB'];
7093
7094 $result_array = array();
7095 $tests = array_slice(
7096 array_reverse(
7097 ilUtil::_getObjectsByOperations("tst", "write", $ilUser->getId(), PHP_INT_MAX)
7098 ),
7099 0,
7100 10000
7101 );
7102
7103 if (count($tests)) {
7104 $titles = ilObject::_prepareCloneSelection($tests, "tst");
7105 foreach ($tests as $ref_id) {
7106 if ($use_object_id) {
7108 $result_array[$obj_id] = $titles[$ref_id];
7109 } else {
7110 $result_array[$ref_id] = $titles[$ref_id];
7111 }
7112 }
7113 }
7114 return $result_array;
7115 }
7116
7125 public function cloneObject($a_target_id, $a_copy_id = 0, $a_omit_tree = false)
7126 {
7127 global $DIC;
7128
7129 $certificateLogger = $DIC->logger()->cert();
7130 $tree = $DIC['tree'];
7131 $ilDB = $DIC->database();
7132 $ilPluginAdmin = $DIC['ilPluginAdmin'];
7133
7134 $this->loadFromDb();
7135
7136 // Copy settings
7138 $newObj = parent::cloneObject($a_target_id, $a_copy_id, $a_omit_tree);
7139 $newObj->setTmpCopyWizardCopyId($a_copy_id);
7140 $this->cloneMetaData($newObj);
7141
7142 // #27082
7143 $newObj->setOfflineStatus(true);
7144 $newObj->update();
7145
7146 $newObj->setAnonymity($this->getAnonymity());
7147 $newObj->setAnswerFeedback($this->getAnswerFeedback());
7148 $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
7149 $newObj->setAuthor($this->getAuthor());
7150 $newObj->setLimitUsersEnabled($this->isLimitUsersEnabled());
7151 $newObj->setAllowedUsers($this->getAllowedUsers());
7152 $newObj->setAllowedUsersTimeGap($this->getAllowedUsersTimeGap());
7153 $newObj->setCountSystem($this->getCountSystem());
7154 $newObj->setECTSFX($this->getECTSFX());
7155 $newObj->setECTSGrades($this->getECTSGrades());
7156 $newObj->setECTSOutput($this->getECTSOutput());
7157 $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
7158 $newObj->setEndingTimeEnabled($this->isEndingTimeEnabled());
7159 $newObj->setEndingTime($this->getEndingTime());
7160 $newObj->setFixedParticipants($this->getFixedParticipants());
7161 $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
7162 $newObj->setIntroductionEnabled($this->isIntroductionEnabled());
7163 $newObj->setIntroduction($this->getIntroduction());
7164 $newObj->setFinalStatement($this->getFinalStatement());
7165 $newObj->setShowInfo($this->getShowInfo());
7166 $newObj->setForceJS($this->getForceJS());
7167 $newObj->setCustomStyle($this->getCustomStyle());
7168 $newObj->setKiosk($this->getKiosk());
7169 $newObj->setShowFinalStatement($this->getShowFinalStatement());
7170 $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
7171 $newObj->setMCScoring($this->getMCScoring());
7172 $newObj->setMailNotification($this->getMailNotification());
7173 $newObj->setMailNotificationType($this->getMailNotificationType());
7174 $newObj->setNrOfTries($this->getNrOfTries());
7175 $newObj->setBlockPassesAfterPassedEnabled($this->isBlockPassesAfterPassedEnabled());
7176 $newObj->setPassScoring($this->getPassScoring());
7177 $newObj->setPasswordEnabled($this->isPasswordEnabled());
7178 $newObj->setPassword($this->getPassword());
7179 $newObj->setProcessingTime($this->getProcessingTime());
7180 $newObj->setQuestionSetType($this->getQuestionSetType());
7181 $newObj->setReportingDate($this->getReportingDate());
7182 $newObj->setResetProcessingTime($this->getResetProcessingTime());
7183 $newObj->setResultsPresentation($this->getResultsPresentation());
7184 $newObj->setScoreCutting($this->getScoreCutting());
7185 $newObj->setScoreReporting($this->getScoreReporting());
7186 $newObj->setSequenceSettings($this->getSequenceSettings());
7187 $newObj->setShowCancel($this->getShowCancel());
7188 $newObj->setShowMarker($this->getShowMarker());
7189 $newObj->setShuffleQuestions($this->getShuffleQuestions());
7190 $newObj->setStartingTimeEnabled($this->isStartingTimeEnabled());
7191 $newObj->setStartingTime($this->getStartingTime());
7192 $newObj->setTitleOutput($this->getTitleOutput());
7193 $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
7194 $newObj->setRedirectionMode($this->getRedirectionMode());
7195 $newObj->setRedirectionUrl($this->getRedirectionUrl());
7196 $newObj->setCertificateVisibility($this->getCertificateVisibility());
7197 $newObj->mark_schema = clone $this->mark_schema;
7198 $newObj->setEnabledViewMode($this->getEnabledViewMode());
7199 $newObj->setTemplate($this->getTemplate());
7200 $newObj->setPoolUsage($this->getPoolUsage());
7201 $newObj->setPrintBestSolutionWithResult($this->isBestSolutionPrintedWithResult());
7202 $newObj->setShowExamIdInTestPassEnabled($this->isShowExamIdInTestPassEnabled());
7203 $newObj->setShowExamIdInTestResultsEnabled($this->isShowExamIdInTestResultsEnabled());
7204 $newObj->setEnableExamView($this->getEnableExamview());
7205 $newObj->setShowExamViewHtml($this->getShowExamviewHtml());
7206 $newObj->setShowExamViewPdf($this->getShowExamviewPdf());
7207 $newObj->setEnableArchiving($this->getEnableArchiving());
7208 $newObj->setSignSubmission($this->getSignSubmission());
7209 $newObj->setCharSelectorAvailability((int) $this->getCharSelectorAvailability());
7210 $newObj->setCharSelectorDefinition($this->getCharSelectorDefinition());
7211 $newObj->setSkillServiceEnabled($this->isSkillServiceEnabled());
7212 $newObj->setResultFilterTaxIds($this->getResultFilterTaxIds());
7213 $newObj->setFollowupQuestionAnswerFixationEnabled($this->isFollowupQuestionAnswerFixationEnabled());
7214 $newObj->setInstantFeedbackAnswerFixationEnabled($this->isInstantFeedbackAnswerFixationEnabled());
7215 $newObj->setForceInstantFeedbackEnabled($this->isForceInstantFeedbackEnabled());
7216 $newObj->setAutosave($this->getAutosave());
7217 $newObj->setAutosaveIval($this->getAutosaveIval());
7218 $newObj->setOfferingQuestionHintsEnabled($this->isOfferingQuestionHintsEnabled());
7219 $newObj->setSpecificAnswerFeedback($this->getSpecificAnswerFeedback());
7220 if ($this->isPassWaitingEnabled()) {
7221 $newObj->setPassWaiting($this->getPassWaiting());
7222 }
7223 $newObj->setObligationsEnabled($this->areObligationsEnabled());
7224 $newObj->saveToDb();
7225
7226 // clone certificate
7227 $pathFactory = new ilCertificatePathFactory();
7228 $templateRepository = new ilCertificateTemplateRepository($ilDB);
7229
7230 $cloneAction = new ilCertificateCloneAction(
7231 $ilDB,
7232 $pathFactory,
7233 $templateRepository,
7234 $DIC->filesystem()->web(),
7235 $certificateLogger,
7237 );
7238
7239 $cloneAction->cloneCertificate($this, $newObj);
7240
7241 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7242 $testQuestionSetConfigFactory->getQuestionSetConfig()->cloneQuestionSetRelatedData($newObj);
7243
7244 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdList.php';
7245 $skillLevelThresholdList = new ilTestSkillLevelThresholdList($ilDB);
7246 $skillLevelThresholdList->setTestId($this->getTestId());
7247 $skillLevelThresholdList->loadFromDb();
7248 $skillLevelThresholdList->cloneListForTest($newObj->getTestId());
7249
7250 $newObj->saveToDb();
7251 $newObj->updateMetaData();// #14467
7252
7253 include_once('./Services/Tracking/classes/class.ilLPObjSettings.php');
7254 $obj_settings = new ilLPObjSettings($this->getId());
7255 $obj_settings->cloneSettings($newObj->getId());
7256
7257 return $newObj;
7258 }
7259
7266 public function getQuestionCount()
7267 {
7268 $num = 0;
7269
7270 if ($this->isRandomTest()) {
7271 global $DIC;
7272 $tree = $DIC['tree'];
7273 $ilDB = $DIC['ilDB'];
7274 $ilPluginAdmin = $DIC['ilPluginAdmin'];
7275
7276 $questionSetConfig = new ilTestRandomQuestionSetConfig(
7277 $tree,
7278 $ilDB,
7279 $ilPluginAdmin,
7280 $this
7281 );
7282
7283 $questionSetConfig->loadFromDb();
7284
7285 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
7286 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php';
7287 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetBuilderWithAmountPerPool.php';
7288 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php';
7289
7290 $sourcePoolDefinitionList = new ilTestRandomQuestionSetSourcePoolDefinitionList(
7291 $ilDB,
7292 $this,
7294 );
7295
7296 $sourcePoolDefinitionList->loadDefinitions();
7297
7298 $num = $sourcePoolDefinitionList->getQuestionAmount();
7299 } else {
7300 $num = $questionSetConfig->getQuestionAmountPerTest();
7301 }
7302 } else {
7303 $num = count($this->questions);
7304 }
7305
7306 return $num;
7307 }
7308
7316 public function logAction($logtext = "", $question_id = "")
7317 {
7318 global $DIC;
7319 $ilUser = $DIC['ilUser'];
7320
7321 $original_id = "";
7322 if (strcmp($question_id, "") != 0) {
7323 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7324 $original_id = assQuestion::_getOriginalId($question_id);
7325 }
7326 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7327 ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, true, $this->getRefId());
7328 }
7329
7337 public static function _getObjectIDFromTestID($test_id)
7338 {
7339 global $DIC;
7340 $ilDB = $DIC['ilDB'];
7341 $object_id = false;
7342 $result = $ilDB->queryF(
7343 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7344 array('integer'),
7345 array($test_id)
7346 );
7347 if ($result->numRows()) {
7348 $row = $ilDB->fetchAssoc($result);
7349 $object_id = $row["obj_fi"];
7350 }
7351 return $object_id;
7352 }
7353
7361 public static function _getObjectIDFromActiveID($active_id)
7362 {
7363 global $DIC;
7364 $ilDB = $DIC['ilDB'];
7365 $object_id = false;
7366 $result = $ilDB->queryF(
7367 "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",
7368 array('integer'),
7369 array($active_id)
7370 );
7371 if ($result->numRows()) {
7372 $row = $ilDB->fetchAssoc($result);
7373 $object_id = $row["obj_fi"];
7374 }
7375 return $object_id;
7376 }
7377
7385 public static function _getTestIDFromObjectID($object_id)
7386 {
7387 global $DIC;
7388 $ilDB = $DIC['ilDB'];
7389 $test_id = false;
7390 $result = $ilDB->queryF(
7391 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7392 array('integer'),
7393 array($object_id)
7394 );
7395 if ($result->numRows()) {
7396 $row = $ilDB->fetchAssoc($result);
7397 $test_id = $row["test_id"];
7398 }
7399 return $test_id;
7400 }
7401
7410 public function getTextAnswer($active_id, $question_id, $pass = null)
7411 {
7412 global $DIC;
7413 $ilDB = $DIC['ilDB'];
7414
7415 $res = "";
7416 if (($active_id) && ($question_id)) {
7417 if (is_null($pass)) {
7418 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7419 $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7420 }
7421 $result = $ilDB->queryF(
7422 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7423 array('integer', 'integer', 'integer'),
7424 array($active_id, $question_id, $pass)
7425 );
7426 if ($result->numRows() == 1) {
7427 $row = $ilDB->fetchAssoc($result);
7428 $res = $row["value1"];
7429 }
7430 }
7431 return $res;
7432 }
7433
7441 public function getQuestiontext($question_id)
7442 {
7443 global $DIC;
7444 $ilDB = $DIC['ilDB'];
7445
7446 $res = "";
7447 if ($question_id) {
7448 $result = $ilDB->queryF(
7449 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
7450 array('integer'),
7451 array($question_id)
7452 );
7453 if ($result->numRows() == 1) {
7454 $row = $ilDB->fetchAssoc($result);
7455 $res = $row["question_text"];
7456 }
7457 }
7458 return $res;
7459 }
7460
7465 {
7466 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
7467 $participantList = new ilTestParticipantList($this);
7468 $participantList->initializeFromDbRows($this->getInvitedUsers());
7469
7470 return $participantList;
7471 }
7472
7477 {
7478 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
7479 $participantList = new ilTestParticipantList($this);
7480 $participantList->initializeFromDbRows($this->getTestParticipants());
7481
7482 return $participantList;
7483 }
7484
7491 public function &getInvitedUsers($user_id = "", $order = "login, lastname, firstname")
7492 {
7493 global $DIC;
7494 $ilDB = $DIC['ilDB'];
7495
7496 $result_array = array();
7497
7498 if ($this->getAnonymity()) {
7499 if (is_numeric($user_id)) {
7500 $result = $ilDB->queryF(
7501 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7502 "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 " .
7503 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7504 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7505 "ORDER BY $order",
7506 array('text', 'text', 'text', 'integer', 'integer'),
7507 array("", $this->lng->txt("anonymous"), "", $this->getTestId(), $user_id)
7508 );
7509 } else {
7510 $result = $ilDB->queryF(
7511 "SELECT tst_active.active_id, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7512 "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 " .
7513 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7514 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7515 "ORDER BY $order",
7516 array('text', 'text', 'text', 'integer'),
7517 array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7518 );
7519 }
7520 } else {
7521 if (is_numeric($user_id)) {
7522 $result = $ilDB->queryF(
7523 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7524 "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 " .
7525 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7526 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7527 "ORDER BY $order",
7528 array('integer', 'integer'),
7529 array($this->getTestId(), $user_id)
7530 );
7531 } else {
7532 $result = $ilDB->queryF(
7533 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7534 "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 " .
7535 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7536 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7537 "ORDER BY $order",
7538 array('integer'),
7539 array($this->getTestId())
7540 );
7541 }
7542 }
7543 $result_array = array();
7544 while ($row = $ilDB->fetchAssoc($result)) {
7545 $result_array[$row['usr_id']] = $row;
7546 }
7547 return $result_array;
7548 }
7549
7556 public function &getTestParticipants()
7557 {
7558 global $DIC;
7559 $ilDB = $DIC['ilDB'];
7560
7561 if ($this->getAnonymity()) {
7562 $query = "
7563 SELECT tst_active.active_id,
7564 tst_active.tries,
7565 tst_active.user_fi usr_id,
7566 %s login,
7567 %s lastname,
7568 %s firstname,
7569 tst_active.submitted test_finished,
7570 usr_data.matriculation,
7571 usr_data.active,
7572 tst_active.lastindex,
7573 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7574 FROM tst_active
7575 LEFT JOIN usr_data
7576 ON tst_active.user_fi = usr_data.usr_id
7577 WHERE tst_active.test_fi = %s
7578 ORDER BY usr_data.lastname
7579 ";
7580 $result = $ilDB->queryF(
7581 $query,
7582 array('text', 'text', 'text', 'integer'),
7583 array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7584 );
7585 } else {
7586 $query = "
7587 SELECT tst_active.active_id,
7588 tst_active.tries,
7589 tst_active.user_fi usr_id,
7590 usr_data.login,
7591 usr_data.lastname,
7592 usr_data.firstname,
7593 tst_active.submitted test_finished,
7594 usr_data.matriculation,
7595 usr_data.active,
7596 tst_active.lastindex,
7597 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7598 FROM tst_active
7599 LEFT JOIN usr_data
7600 ON tst_active.user_fi = usr_data.usr_id
7601 WHERE tst_active.test_fi = %s
7602 ORDER BY usr_data.lastname
7603 ";
7604 $result = $ilDB->queryF(
7605 $query,
7606 array('integer'),
7607 array($this->getTestId())
7608 );
7609 }
7610 $data = array();
7611 while ($row = $ilDB->fetchAssoc($result)) {
7612 $data[$row['active_id']] = $row;
7613 }
7614 foreach ($data as $index => $participant) {
7615 if (strlen(trim($participant["firstname"] . $participant["lastname"])) == 0) {
7616 $data[$index]["lastname"] = $this->lng->txt("deleted_user");
7617 }
7618 }
7619 return $data;
7620 }
7621
7622 public function getTestParticipantsForManualScoring($filter = null)
7623 {
7624 global $DIC;
7625 $ilDB = $DIC['ilDB'];
7626
7627 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7629 if (count($scoring) == 0) {
7630 return array();
7631 }
7632
7633 $participants = &$this->getTestParticipants();
7634 $filtered_participants = array();
7635 foreach ($participants as $active_id => $participant) {
7636 $qstType_IN_manScoreableQstTypes = $ilDB->in('qpl_questions.question_type_fi', $scoring, false, 'integer');
7637
7638 $queryString = "
7639 SELECT tst_test_result.manual
7640
7641 FROM tst_test_result
7642
7643 INNER JOIN qpl_questions
7644 ON tst_test_result.question_fi = qpl_questions.question_id
7645
7646 WHERE tst_test_result.active_fi = %s
7647 AND $qstType_IN_manScoreableQstTypes
7648 ";
7649
7650 $result = $ilDB->queryF(
7651 $queryString,
7652 array("integer"),
7653 array($active_id)
7654 );
7655
7656 $count = $result->numRows();
7657
7658 if ($count > 0) {
7659 switch ($filter) {
7660 case 1: // only active users
7661 if ($participant->active) {
7662 $filtered_participants[$active_id] = $participant;
7663 }
7664 break;
7665 case 2: // only inactive users
7666 if (!$participant->active) {
7667 $filtered_participants[$active_id] = $participant;
7668 }
7669 break;
7670 case 3: // all users
7671 $filtered_participants[$active_id] = $participant;
7672 break;
7673 case 4:
7674 // already scored participants
7675 //$found = 0;
7676 //while ($row = $ilDB->fetchAssoc($result))
7677 //{
7678 // if ($row["manual"]) $found++;
7679 //}
7680 //if ($found == $count)
7681 //{
7682 //$filtered_participants[$active_id] = $participant;
7683 //}
7684 //else
7685 //{
7686 $assessmentSetting = new ilSetting("assessment");
7687 $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7688 if ($manscoring_done) {
7689 $filtered_participants[$active_id] = $participant;
7690 }
7691 //}
7692 break;
7693 case 5:
7694 // unscored participants
7695 //$found = 0;
7696 //while ($row = $ilDB->fetchAssoc($result))
7697 //{
7698 // if ($row["manual"]) $found++;
7699 //}
7700 //if ($found == 0)
7701 //{
7702 $assessmentSetting = new ilSetting("assessment");
7703 $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7704 if (!$manscoring_done) {
7705 $filtered_participants[$active_id] = $participant;
7706 }
7707 //}
7708 break;
7709 case 6:
7710 // partially scored participants
7711 $found = 0;
7712 while ($row = $ilDB->fetchAssoc($result)) {
7713 if ($row["manual"]) {
7714 $found++;
7715 }
7716 }
7717 if (($found > 0) && ($found < $count)) {
7718 $filtered_participants[$active_id] = $participant;
7719 }
7720 break;
7721 default:
7722 $filtered_participants[$active_id] = $participant;
7723 break;
7724 }
7725 }
7726 }
7727 return $filtered_participants;
7728 }
7729
7737 public function &getUserData($ids)
7738 {
7739 global $DIC;
7740 $ilDB = $DIC['ilDB'];
7741
7742 if (!is_array($ids) || count($ids) == 0) {
7743 return array();
7744 }
7745
7746 if ($this->getAnonymity()) {
7747 $result = $ilDB->queryF(
7748 "SELECT usr_id, %s login, %s lastname, %s firstname, client_ip clientip FROM usr_data WHERE " . $ilDB->in('usr_id', $ids, false, 'integer') . " ORDER BY login",
7749 array('text', 'text', 'text'),
7750 array("", $this->lng->txt("anonymous"), "")
7751 );
7752 } else {
7753 $result = $ilDB->query("SELECT usr_id, login, lastname, firstname, client_ip clientip FROM usr_data WHERE " . $ilDB->in('usr_id', $ids, false, 'integer') . " ORDER BY login");
7754 }
7755
7756 $result_array = array();
7757 while ($row = $ilDB->fetchAssoc($result)) {
7758 $result_array[$row["usr_id"]] = $row;
7759 }
7760 return $result_array;
7761 }
7762
7763 public function &getGroupData($ids)
7764 {
7765 if (!is_array($ids) || count($ids) == 0) {
7766 return array();
7767 }
7768 $result = array();
7769 foreach ($ids as $ref_id) {
7771 $result[$ref_id] = array("ref_id" => $ref_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7772 }
7773 return $result;
7774 }
7775
7776 public function &getRoleData($ids)
7777 {
7778 if (!is_array($ids) || count($ids) == 0) {
7779 return array();
7780 }
7781 $result = array();
7782 foreach ($ids as $obj_id) {
7783 $result[$obj_id] = array("obj_id" => $obj_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7784 }
7785 return $result;
7786 }
7787
7788
7795 public function inviteGroup($group_id)
7796 {
7797 include_once "./Modules/Group/classes/class.ilObjGroup.php";
7798 $group = new ilObjGroup($group_id);
7799 $members = $group->getGroupMemberIds();
7800 include_once './Services/User/classes/class.ilObjUser.php';
7801 foreach ($members as $user_id) {
7802 $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7803 }
7804 }
7805
7812 public function inviteRole($role_id)
7813 {
7814 global $DIC;
7815 $rbacreview = $DIC['rbacreview'];
7816 $members = $rbacreview->assignedUsers($role_id);
7817 include_once './Services/User/classes/class.ilObjUser.php';
7818 foreach ($members as $user_id) {
7819 $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7820 }
7821 }
7822
7823
7824
7831 public function disinviteUser($user_id)
7832 {
7833 global $DIC;
7834 $ilDB = $DIC['ilDB'];
7835
7836 $affectedRows = $ilDB->manipulateF(
7837 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7838 array('integer', 'integer'),
7839 array($this->getTestId(), $user_id)
7840 );
7841 }
7842
7849 public function inviteUser($user_id, $client_ip = "")
7850 {
7851 global $DIC;
7852 $ilDB = $DIC['ilDB'];
7853
7854 $affectedRows = $ilDB->manipulateF(
7855 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7856 array('integer', 'integer'),
7857 array($this->getTestId(), $user_id)
7858 );
7859 $affectedRows = $ilDB->manipulateF(
7860 "INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
7861 array('integer', 'integer', 'text', 'integer'),
7862 array($this->getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : null, time())
7863 );
7864 }
7865
7866
7867 public function setClientIP($user_id, $client_ip)
7868 {
7869 global $DIC;
7870 $ilDB = $DIC['ilDB'];
7871
7872 $affectedRows = $ilDB->manipulateF(
7873 "UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
7874 array('text', 'integer', 'integer', 'integer'),
7875 array((strlen($client_ip)) ? $client_ip : null, time(), $this->getTestId(), $user_id)
7876 );
7877 }
7878
7884 public static function _getSolvedQuestions($active_id, $question_fi = null)
7885 {
7886 global $DIC;
7887 $ilDB = $DIC['ilDB'];
7888 if (is_numeric($question_fi)) {
7889 $result = $ilDB->queryF(
7890 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
7891 array('integer', 'integer'),
7892 array($active_id, $question_fi)
7893 );
7894 } else {
7895 $result = $ilDB->queryF(
7896 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
7897 array('integer'),
7898 array($active_id)
7899 );
7900 }
7901 $result_array = array();
7902 while ($row = $ilDB->fetchAssoc($result)) {
7903 $result_array[$row["question_fi"]] = $row;
7904 }
7905 return $result_array;
7906 }
7907
7908
7912 public function setQuestionSetSolved($value, $question_id, $user_id)
7913 {
7914 global $DIC;
7915 $ilDB = $DIC['ilDB'];
7916
7917 $active_id = $this->getActiveIdOfUser($user_id);
7918 $affectedRows = $ilDB->manipulateF(
7919 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
7920 array('integer', 'integer'),
7921 array($active_id, $question_id)
7922 );
7923 $affectedRows = $ilDB->manipulateF(
7924 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
7925 array('integer', 'integer', 'integer'),
7926 array($value, $question_id, $active_id)
7927 );
7928 }
7929
7933 public function isTestFinished($active_id)
7934 {
7935 global $DIC;
7936 $ilDB = $DIC['ilDB'];
7937
7938 $result = $ilDB->queryF(
7939 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
7940 array('integer', 'integer'),
7941 array($active_id, 1)
7942 );
7943 return $result->numRows() == 1;
7944 }
7945
7949 public function isActiveTestSubmitted($user_id = null)
7950 {
7951 global $DIC;
7952 $ilUser = $DIC['ilUser'];
7953 $ilDB = $DIC['ilDB'];
7954
7955 if (!is_numeric($user_id)) {
7956 $user_id = $ilUser->getId();
7957 }
7958
7959 $result = $ilDB->queryF(
7960 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
7961 array('integer', 'integer', 'integer'),
7962 array($this->getTestId(), $user_id, 1)
7963 );
7964 return $result->numRows() == 1;
7965 }
7966
7970 public function hasNrOfTriesRestriction()
7971 {
7972 return $this->getNrOfTries() != 0;
7973 }
7974
7975
7981 public function isNrOfTriesReached($tries)
7982 {
7983 return $tries >= (int) $this->getNrOfTries();
7984 }
7985
7986
7995 public function getAllTestResults($participants, $prepareForCSV = true)
7996 {
7997 $results = array();
7998 $row = array(
7999 "user_id" => $this->lng->txt("user_id"),
8000 "matriculation" => $this->lng->txt("matriculation"),
8001 "lastname" => $this->lng->txt("lastname"),
8002 "firstname" => $this->lng->txt("firstname"),
8003 "login" => $this->lng->txt("login"),
8004 "reached_points" => $this->lng->txt("tst_reached_points"),
8005 "max_points" => $this->lng->txt("tst_maximum_points"),
8006 "percent_value" => $this->lng->txt("tst_percent_solved"),
8007 "mark" => $this->lng->txt("tst_mark"),
8008 "ects" => $this->lng->txt("ects_grade")
8009 );
8010 $results[] = $row;
8011 if (count($participants)) {
8012 if ($this->getECTSOutput()) {
8013 $passed_array = &$this->getTotalPointsPassedArray();
8014 }
8015 foreach ($participants as $active_id => $user_rec) {
8016 $mark = $ects_mark = '';
8017 $row = array();
8018 $reached_points = 0;
8019 $max_points = 0;
8020 foreach ($this->questions as $value) {
8021 $question = &ilObjTest::_instanciateQuestion($value);
8022 if (is_object($question)) {
8023 $max_points += $question->getMaximumPoints();
8024 $reached_points += $question->getReachedPoints($active_id);
8025 }
8026 }
8027 if ($max_points > 0) {
8028 $percentvalue = $reached_points / $max_points;
8029 if ($percentvalue < 0) {
8030 $percentvalue = 0.0;
8031 }
8032 } else {
8033 $percentvalue = 0;
8034 }
8035 $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
8036 $passed = "";
8037 if ($mark_obj) {
8038 $mark = $mark_obj->getOfficialName();
8039 if ($this->getECTSOutput()) {
8040 $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
8041 }
8042 }
8043 if ($this->getAnonymity()) {
8044 $user_rec['firstname'] = "";
8045 $user_rec['lastname'] = $this->lng->txt("anonymous");
8046 }
8047 $row = array(
8048 "user_id" => $user_rec['usr_id'],
8049 "matriculation" => $user_rec['matriculation'],
8050 "lastname" => $user_rec['lastname'],
8051 "firstname" => $user_rec['firstname'],
8052 "login" => $user_rec['login'],
8053 "reached_points" => $reached_points,
8054 "max_points" => $max_points,
8055 "percent_value" => $percentvalue,
8056 "mark" => $mark,
8057 "ects" => $ects_mark
8058 );
8059 $results[] = $prepareForCSV ? $this->processCSVRow($row, true) : $row;
8060 }
8061 }
8062 return $results;
8063 }
8064
8075 public function &processCSVRow($row, $quoteAll = false, $separator = ";")
8076 {
8077 $resultarray = array();
8078 foreach ($row as $rowindex => $entry) {
8079 $surround = false;
8080 if ($quoteAll) {
8081 $surround = true;
8082 }
8083 if (strpos($entry, "\"") !== false) {
8084 $entry = str_replace("\"", "\"\"", $entry);
8085 $surround = true;
8086 }
8087 if (strpos($entry, $separator) !== false) {
8088 $surround = true;
8089 }
8090 // replace all CR LF with LF (for Excel for Windows compatibility
8091 $entry = str_replace(chr(13) . chr(10), chr(10), $entry);
8092
8093 if ($surround) {
8094 $entry = "\"" . $entry . "\"";
8095 }
8096
8097 $resultarray[$rowindex] = $entry;
8098 }
8099 return $resultarray;
8100 }
8101
8110 public static function _getPass($active_id)
8111 {
8112 global $DIC;
8113 $ilDB = $DIC['ilDB'];
8114 $result = $ilDB->queryF(
8115 "SELECT tries FROM tst_active WHERE active_id = %s",
8116 array('integer'),
8117 array($active_id)
8118 );
8119 if ($result->numRows()) {
8120 $row = $ilDB->fetchAssoc($result);
8121 return $row["tries"];
8122 } else {
8123 return 0;
8124 }
8125 }
8126
8136 public static function _getMaxPass($active_id)
8137 {
8138 global $DIC;
8139 $ilDB = $DIC['ilDB'];
8140 $result = $ilDB->queryF(
8141 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
8142 array('integer'),
8143 array($active_id)
8144 );
8145 if ($result->numRows()) {
8146 $row = $ilDB->fetchAssoc($result);
8147 $max = $row["maxpass"];
8148 } else {
8149 $max = null;
8150 }
8151 return $max;
8152 }
8153
8159 public static function _getBestPass($active_id)
8160 {
8161 global $DIC;
8162 $ilDB = $DIC['ilDB'];
8163
8164 $result = $ilDB->queryF(
8165 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
8166 array('integer'),
8167 array($active_id)
8168 );
8169 if ($result->numRows()) {
8170 $bestrow = null;
8171 $bestfactor = 0;
8172 while ($row = $ilDB->fetchAssoc($result)) {
8173 if ($row["maxpoints"] > 0) {
8174 $factor = $row["points"] / $row["maxpoints"];
8175 } else {
8176 $factor = 0;
8177 }
8178
8179 if ($factor > $bestfactor) {
8180 $bestrow = $row;
8181 $bestfactor = $factor;
8182 }
8183 }
8184 if (is_array($bestrow)) {
8185 return $bestrow["pass"];
8186 } else {
8187 return 0;
8188 }
8189 } else {
8190 return 0;
8191 }
8192 }
8193
8202 public static function _getResultPass($active_id)
8203 {
8204 $counted_pass = null;
8205 if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS) {
8206 $counted_pass = ilObjTest::_getBestPass($active_id);
8207 } else {
8208 $counted_pass = ilObjTest::_getMaxPass($active_id);
8209 }
8210 return $counted_pass;
8211 }
8212
8222 public function getAnsweredQuestionCount($active_id, $pass = null)
8223 {
8224 if ($this->isDynamicTest()) {
8225 global $DIC;
8226 $tree = $DIC['tree'];
8227 $ilDB = $DIC['ilDB'];
8228 $lng = $DIC['lng'];
8229 $ilPluginAdmin = $DIC['ilPluginAdmin'];
8230
8231 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
8232 $testSessionFactory = new ilTestSessionFactory($this);
8233 $testSession = $testSessionFactory->getSession($active_id);
8234
8235 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
8236 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
8237 $testSequence = $testSequenceFactory->getSequenceByTestSession($testSession);
8238
8239 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
8240 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
8241 $dynamicQuestionSetConfig->loadFromDb();
8242
8243 $testSequence->loadFromDb($dynamicQuestionSetConfig);
8244 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
8245
8246 return $testSequence->getTrackedQuestionCount();
8247 }
8248
8249 if ($this->isRandomTest()) {
8250 $this->loadQuestions($active_id, $pass);
8251 }
8252 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
8253 $workedthrough = 0;
8254 foreach ($this->questions as $value) {
8255 if (assQuestion::_isWorkedThrough($active_id, $value, $pass)) {
8256 $workedthrough += 1;
8257 }
8258 }
8259 return $workedthrough;
8260 }
8261
8268 public static function lookupPassResultsUpdateTimestamp($active_id, $pass)
8269 {
8270 global $DIC;
8271 $ilDB = $DIC['ilDB'];
8272
8273 if (is_null($pass)) {
8274 $pass = 0;
8275 }
8276
8277 $query = "
8278 SELECT tst_pass_result.tstamp pass_res_tstamp,
8279 tst_test_result.tstamp quest_res_tstamp
8280
8281 FROM tst_pass_result
8282
8283 LEFT JOIN tst_test_result
8284 ON tst_test_result.active_fi = tst_pass_result.active_fi
8285 AND tst_test_result.pass = tst_pass_result.pass
8286
8287 WHERE tst_pass_result.active_fi = %s
8288 AND tst_pass_result.pass = %s
8289
8290 ORDER BY tst_test_result.tstamp DESC
8291 ";
8292
8293 $result = $ilDB->queryF(
8294 $query,
8295 array('integer', 'integer'),
8296 array($active_id, $pass)
8297 );
8298
8299 while ($row = $ilDB->fetchAssoc($result)) {
8300 if ($row['qres_tstamp']) {
8301 return $row['quest_res_tstamp'];
8302 }
8303
8304 return $row['pass_res_tstamp'];
8305 }
8306
8307 return 0;
8308 }
8309
8318 public function isExecutable($testSession, $user_id, $allowPassIncrease = false)
8319 {
8320 $result = array(
8321 "executable" => true,
8322 "errormessage" => ""
8323 );
8324 if (!$this->startingTimeReached()) {
8325 $result["executable"] = false;
8326 $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getStartingTime(), IL_CAL_UNIX)));
8327 return $result;
8328 }
8329 if ($this->endingTimeReached()) {
8330 $result["executable"] = false;
8331 $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getEndingTime(), IL_CAL_UNIX)));
8332 return $result;
8333 }
8334
8335 $active_id = $this->getActiveIdOfUser($user_id);
8336
8337 if ($this->getEnableProcessingTime()) {
8338 if ($active_id > 0) {
8339 $starting_time = $this->getStartingTimeOfUser($active_id);
8340 if ($starting_time !== false) {
8341 if ($this->isMaxProcessingTimeReached($starting_time, $active_id)) {
8342 if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > (self::_getPass($active_id) + 1)))) {
8343 // a test pass was quitted because the maximum processing time was reached, but the time
8344 // will be resetted for future passes, so if there are more passes allowed, the participant may
8345 // start the test again.
8346 // This code block is only called when $allowPassIncrease is TRUE which only happens when
8347 // the test info page is opened. Otherwise this will lead to unexpected results!
8348 $testSession->increasePass();
8349 $testSession->setLastSequence(0);
8350 $testSession->saveToDb();
8351 } else {
8352 $result["executable"] = false;
8353 $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8354 }
8355 return $result;
8356 }
8357 }
8358 }
8359 }
8360 global $DIC;
8361 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8362 $testPassesSelector = new ilTestPassesSelector($DIC['ilDB'], $this);
8363 $testPassesSelector->setActiveId($active_id);
8364 $testPassesSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8365
8366 if ($this->hasNrOfTriesRestriction() && ($active_id > 0)) {
8367 $closedPasses = $testPassesSelector->getClosedPasses();
8368
8369 if (count($closedPasses) >= $this->getNrOfTries()) {
8370 $result["executable"] = false;
8371 $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8372 return $result;
8373 }
8374
8375 if ($this->isBlockPassesAfterPassedEnabled() && !$testPassesSelector->openPassExists()) {
8376 if (ilObjTestAccess::_isPassed($user_id, $this->getId())) {
8377 $result['executable'] = false;
8378 $result['errormessage'] = $this->lng->txt("tst_addit_passes_blocked_after_passed_msg");
8379 return $result;
8380 }
8381 }
8382 }
8383 if ($this->isPassWaitingEnabled() && $testPassesSelector->getLastFinishedPass() !== null) {
8384 $lastPass = $testPassesSelector->getLastFinishedPassTimestamp();
8385 if ($lastPass && strlen($this->getPassWaiting())) {
8386 $pass_waiting_string = $this->getPassWaiting();
8387 $time_values = explode(":", $pass_waiting_string);
8388 $next_pass_allowed = strtotime('+ ' . $time_values[0] . ' Months + ' . $time_values[1] . ' Days + ' . $time_values[2] . ' Hours' . $time_values[3] . ' Minutes', $lastPass);
8389
8390 if (time() < $next_pass_allowed) {
8391 $date = ilDatePresentation::formatDate(new ilDateTime($next_pass_allowed, IL_CAL_UNIX));
8392
8393 $result["executable"] = false;
8394 $result["errormessage"] = sprintf($this->lng->txt('wait_for_next_pass_hint_msg'), $date);
8395 return $result;
8396 }
8397 }
8398 }
8399 return $result;
8400 }
8401
8402
8404 {
8405 global $DIC; /* @var ILIAS\DI\Container $DIC */
8406
8407 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8408 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
8409
8410 $passSelector->setActiveId($testSession->getActiveId());
8411 $passSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8412
8413 return $passSelector->hasReportablePasses();
8414 }
8415
8417 {
8418 global $DIC; /* @var ILIAS\DI\Container $DIC */
8419
8420 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8421 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
8422
8423 $passSelector->setActiveId($testSession->getActiveId());
8424 $passSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8425
8426 return $passSelector->hasExistingPasses();
8427 }
8428
8436 public function getStartingTimeOfUser($active_id, $pass = null)
8437 {
8438 global $DIC;
8439 $ilDB = $DIC['ilDB'];
8440
8441 if ($active_id < 1) {
8442 return false;
8443 }
8444 if ($pass === null) {
8445 $pass = ($this->getResetProcessingTime()) ? self::_getPass($active_id) : 0;
8446 }
8447 $result = $ilDB->queryF(
8448 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
8449 array('integer', 'integer'),
8450 array($active_id, $pass)
8451 );
8452 if ($result->numRows()) {
8453 $row = $ilDB->fetchAssoc($result);
8454 if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches)) {
8455 return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8456 } else {
8457 return time();
8458 }
8459 } else {
8460 return time();
8461 }
8462 }
8463
8472 public function isMaxProcessingTimeReached($starting_time, $active_id)
8473 {
8474 if ($this->getEnableProcessingTime()) {
8475 $processing_time = $this->getProcessingTimeInSeconds($active_id);
8476 $now = time();
8477 if ($now > ($starting_time + $processing_time)) {
8478 return true;
8479 } else {
8480 return false;
8481 }
8482 } else {
8483 return false;
8484 }
8485 }
8486
8487 public function &getTestQuestions()
8488 {
8489 global $DIC;
8490 $ilDB = $DIC['ilDB'];
8491
8492 $query = "
8493 SELECT questions.*,
8494 questtypes.type_tag,
8495 tstquest.sequence,
8496 tstquest.obligatory,
8497 origquest.obj_fi orig_obj_fi
8498
8499 FROM qpl_questions questions
8500
8501 INNER JOIN qpl_qst_type questtypes
8502 ON questtypes.question_type_id = questions.question_type_fi
8503
8504 INNER JOIN tst_test_question tstquest
8505 ON tstquest.question_fi = questions.question_id
8506
8507 LEFT JOIN qpl_questions origquest
8508 ON origquest.question_id = questions.original_id
8509
8510 WHERE tstquest.test_fi = %s
8511
8512 ORDER BY tstquest.sequence
8513 ";
8514
8515 $query_result = $ilDB->queryF(
8516 $query,
8517 array('integer'),
8518 array($this->getTestId())
8519 );
8520
8521 $questions = array();
8522
8523 while ($row = $ilDB->fetchAssoc($query_result)) {
8524 $question = $row;
8525
8526 $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8527
8528 $questions[] = $question;
8529 }
8530
8531 return $questions;
8532 }
8533
8538 public function isTestQuestion($questionId)
8539 {
8540 foreach ($this->getTestQuestions() as $questionData) {
8541 if ($questionData['question_id'] != $questionId) {
8542 continue;
8543 }
8544
8545 return true;
8546 }
8547
8548 return false;
8549 }
8550
8551 public function checkQuestionParent($questionId)
8552 {
8553 global $DIC; /* @var ILIAS\DI\Container $DIC */
8554
8555 $row = $DIC->database()->fetchAssoc($DIC->database()->queryF(
8556 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
8557 array('integer', 'integer'),
8558 array($questionId, $this->getId())
8559 ));
8560
8561 return (bool) $row['cnt'];
8562 }
8563
8568 {
8569 $points = 0;
8570
8571 foreach ($this->getTestQuestions() as $questionData) {
8572 $points += $questionData['points'];
8573 }
8574
8575 return $points;
8576 }
8577
8582 {
8583 $totalWorkingTime = '00:00:00';
8584
8585 foreach ($this->getTestQuestions() as $questionData) {
8587 $totalWorkingTime,
8588 $questionData['working_time']
8589 );
8590 }
8591
8592 return $totalWorkingTime;
8593 }
8594
8598 public function getPotentialRandomTestQuestions()
8599 {
8603 global $DIC;
8604 $ilDB = $DIC['ilDB'];
8605
8606 $query = "
8607 SELECT questions.*,
8608 questtypes.type_tag,
8609 origquest.obj_fi orig_obj_fi
8610
8611 FROM qpl_questions questions
8612
8613 INNER JOIN qpl_qst_type questtypes
8614 ON questtypes.question_type_id = questions.question_type_fi
8615
8616 INNER JOIN tst_rnd_cpy tstquest
8617 ON tstquest.qst_fi = questions.question_id
8618
8619 LEFT JOIN qpl_questions origquest
8620 ON origquest.question_id = questions.original_id
8621
8622 WHERE tstquest.tst_fi = %s
8623 ";
8624
8625 $query_result = $ilDB->queryF(
8626 $query,
8627 array('integer'),
8628 array($this->getTestId())
8629 );
8630
8631 $questions = array();
8632
8633 while ($row = $ilDB->fetchAssoc($query_result)) {
8634 $question = $row;
8635
8636 $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8637
8638 $questions[] = $question;
8639 }
8640
8641 return $questions;
8642 }
8643
8650 public function getShuffleQuestions()
8651 {
8652 return ($this->shuffle_questions) ? 1 : 0;
8653 }
8654
8661 public function setShuffleQuestions($a_shuffle)
8662 {
8663 $this->shuffle_questions = ($a_shuffle) ? 1 : 0;
8664 }
8665
8679 {
8680 return ($this->show_summary) ? $this->show_summary : 0;
8681 }
8682
8695 public function setListOfQuestionsSettings($a_value = 0)
8696 {
8697 $this->show_summary = $a_value;
8698 }
8699
8706 public function getListOfQuestions()
8707 {
8708 if (($this->show_summary & 1) > 0) {
8709 return true;
8710 } else {
8711 return false;
8712 }
8713 }
8714
8721 public function setListOfQuestions($a_value = true)
8722 {
8723 if ($a_value) {
8724 $this->show_summary = 1;
8725 } else {
8726 $this->show_summary = 0;
8727 }
8728 }
8729
8736 public function getListOfQuestionsStart()
8737 {
8738 if (($this->show_summary & 2) > 0) {
8739 return true;
8740 } else {
8741 return false;
8742 }
8743 }
8744
8751 public function setListOfQuestionsStart($a_value = true)
8752 {
8753 if ($a_value && $this->getListOfQuestions()) {
8754 $this->show_summary = $this->show_summary | 2;
8755 }
8756 if (!$a_value && $this->getListOfQuestions()) {
8757 if ($this->getListOfQuestionsStart()) {
8758 $this->show_summary = $this->show_summary ^ 2;
8759 }
8760 }
8761 }
8762
8769 public function getListOfQuestionsEnd()
8770 {
8771 if (($this->show_summary & 4) > 0) {
8772 return true;
8773 } else {
8774 return false;
8775 }
8776 }
8777
8784 public function setListOfQuestionsEnd($a_value = true)
8785 {
8786 if ($a_value && $this->getListOfQuestions()) {
8787 $this->show_summary = $this->show_summary | 4;
8788 }
8789 if (!$a_value && $this->getListOfQuestions()) {
8790 if ($this->getListOfQuestionsEnd()) {
8791 $this->show_summary = $this->show_summary ^ 4;
8792 }
8793 }
8794 }
8795
8803 {
8804 if (($this->show_summary & 8) > 0) {
8805 return true;
8806 } else {
8807 return false;
8808 }
8809 }
8810
8817 public function setListOfQuestionsDescription($a_value = true)
8818 {
8819 if ($a_value && $this->getListOfQuestions()) {
8820 $this->show_summary = $this->show_summary | 8;
8821 }
8822 if (!$a_value && $this->getListOfQuestions()) {
8823 if ($this->getListOfQuestionsDescription()) {
8824 $this->show_summary = $this->show_summary ^ 8;
8825 }
8826 }
8827 }
8828
8835 public function getResultsPresentation()
8836 {
8837 return ($this->results_presentation) ? $this->results_presentation : 0;
8838 }
8839
8846 public function getShowPassDetails()
8847 {
8848 if (($this->results_presentation & 1) > 0) {
8849 return true;
8850 } else {
8851 return false;
8852 }
8853 }
8854
8861 public function getShowSolutionDetails()
8862 {
8863 if (($this->results_presentation & 2) > 0) {
8864 return true;
8865 } else {
8866 return false;
8867 }
8868 }
8869
8877 {
8878 if (($this->results_presentation & 4) > 0) {
8879 return true;
8880 } else {
8881 return false;
8882 }
8883 }
8884
8891 public function getShowSolutionFeedback()
8892 {
8893 if (($this->results_presentation & 8) > 0) {
8894 return true;
8895 } else {
8896 return false;
8897 }
8898 }
8899
8907 {
8908 if (($this->results_presentation & 16) > 0) {
8909 return true;
8910 } else {
8911 return false;
8912 }
8913 }
8914
8922 {
8923 if (($this->results_presentation & 32) > 0) {
8924 return true;
8925 } else {
8926 return false;
8927 }
8928 }
8929
8935 {
8936 if (($this->results_presentation & 64) > 0) {
8937 return true;
8938 } else {
8939 return false;
8940 }
8941 }
8942
8948 {
8949 if (($this->results_presentation & 128) > 0) {
8950 return true;
8951 } else {
8952 return false;
8953 }
8954 }
8955
8962 public function setResultsPresentation($a_results_presentation = 3)
8963 {
8964 $this->results_presentation = $a_results_presentation;
8965 }
8966
8975 public function setShowPassDetails($a_details = 1)
8976 {
8977 if ($a_details) {
8978 $this->results_presentation = $this->results_presentation | 1;
8979 } else {
8980 if ($this->getShowPassDetails()) {
8981 $this->results_presentation = $this->results_presentation ^ 1;
8982 }
8983 }
8984 }
8985
8992 public function setShowSolutionDetails($a_details = 1)
8993 {
8994 if ($a_details) {
8995 $this->results_presentation = $this->results_presentation | 2;
8996 } else {
8997 if ($this->getShowSolutionDetails()) {
8998 $this->results_presentation = $this->results_presentation ^ 2;
8999 }
9000 }
9001 }
9002
9009 public function canShowSolutionPrintview($user_id = null)
9010 {
9011 return $this->getShowSolutionPrintview();
9012 }
9013
9020 public function setShowSolutionPrintview($a_printview = 1)
9021 {
9022 if ($a_printview) {
9023 $this->results_presentation = $this->results_presentation | 4;
9024 } else {
9025 if ($this->getShowSolutionPrintview()) {
9026 $this->results_presentation = $this->results_presentation ^ 4;
9027 }
9028 }
9029 }
9030
9037 public function setShowSolutionFeedback($a_feedback = true)
9038 {
9039 if ($a_feedback) {
9040 $this->results_presentation = $this->results_presentation | 8;
9041 } else {
9042 if ($this->getShowSolutionFeedback()) {
9043 $this->results_presentation = $this->results_presentation ^ 8;
9044 }
9045 }
9046 }
9047
9054 public function setShowSolutionAnswersOnly($a_full = true)
9055 {
9056 if ($a_full) {
9057 $this->results_presentation = $this->results_presentation | 16;
9058 } else {
9059 if ($this->getShowSolutionAnswersOnly()) {
9060 $this->results_presentation = $this->results_presentation ^ 16;
9061 }
9062 }
9063 }
9064
9071 public function setShowSolutionSignature($a_signature = false)
9072 {
9073 if ($a_signature) {
9074 $this->results_presentation = $this->results_presentation | 32;
9075 } else {
9076 if ($this->getShowSolutionSignature()) {
9077 $this->results_presentation = $this->results_presentation ^ 32;
9078 }
9079 }
9080 }
9081
9088 public function setShowSolutionSuggested($a_solution = false)
9089 {
9090 if ($a_solution) {
9091 $this->results_presentation = $this->results_presentation | 64;
9092 } else {
9093 if ($this->getShowSolutionSuggested()) {
9094 $this->results_presentation = $this->results_presentation ^ 64;
9095 }
9096 }
9097 }
9098
9104 public function setShowSolutionListComparison($a_comparison = false)
9105 {
9106 if ($a_comparison) {
9107 $this->results_presentation = $this->results_presentation | 128;
9108 } else {
9109 if ($this->getShowSolutionListComparison()) {
9110 $this->results_presentation = $this->results_presentation ^ 128;
9111 }
9112 }
9113 }
9114
9118 public static function _getUserIdFromActiveId($active_id)
9119 {
9120 global $DIC;
9121 $ilDB = $DIC['ilDB'];
9122 $result = $ilDB->queryF(
9123 "SELECT user_fi FROM tst_active WHERE active_id = %s",
9124 array('integer'),
9125 array($active_id)
9126 );
9127 if ($result->numRows()) {
9128 $row = $ilDB->fetchAssoc($result);
9129 return $row["user_fi"];
9130 } else {
9131 return -1;
9132 }
9133 }
9134
9138 public function isLimitUsersEnabled()
9139 {
9141 }
9142
9147 {
9148 $this->limitUsersEnabled = $limitUsersEnabled;
9149 }
9150
9151 public function getAllowedUsers()
9152 {
9153 return ($this->allowedUsers) ? $this->allowedUsers : 0;
9154 }
9155
9156 public function setAllowedUsers($a_allowed_users)
9157 {
9158 $this->allowedUsers = $a_allowed_users;
9159 }
9160
9161 public function getAllowedUsersTimeGap()
9162 {
9163 return ($this->allowedUsersTimeGap) ? $this->allowedUsersTimeGap : 0;
9164 }
9165
9166 public function setAllowedUsersTimeGap($a_allowed_users_time_gap)
9167 {
9168 $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
9169 }
9170
9172 {
9173 global $DIC;
9174 $ilDB = $DIC['ilDB'];
9175
9176 $nr_of_users = $this->getAllowedUsers();
9177 $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
9178 if (($nr_of_users > 0) && ($time_gap > 0)) {
9179 $now = time();
9180 $time_border = $now - $time_gap;
9181 $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
9182 $query = "
9183 SELECT DISTINCT tst_times.active_fi
9184 FROM tst_times
9185 INNER JOIN tst_active
9186 ON tst_times.active_fi = tst_active.active_id
9187 AND (
9188 tst_times.pass > tst_active.last_finished_pass OR tst_active.last_finished_pass IS NULL
9189 )
9190 WHERE tst_times.tstamp > %s
9191 AND tst_active.test_fi = %s
9192 ";
9193 $result = $ilDB->queryF($query, array('integer', 'integer'), array($time_border, $this->getTestId()));
9194 if ($result->numRows() >= $nr_of_users) {
9195 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
9197 $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
9198 }
9199 return false;
9200 } else {
9201 return true;
9202 }
9203 }
9204 return true;
9205 }
9206
9207 public function _getLastAccess($active_id)
9208 {
9209 global $DIC;
9210 $ilDB = $DIC['ilDB'];
9211
9212 $result = $ilDB->queryF(
9213 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
9214 array('integer'),
9215 array($active_id)
9216 );
9217 if ($result->numRows()) {
9218 $row = $ilDB->fetchAssoc($result);
9219 return $row["finished"];
9220 }
9221 return "";
9222 }
9223
9224 public static function lookupLastTestPassAccess($activeId, $passIndex)
9225 {
9226 global $DIC; /* @var \ILIAS\DI\Container $DIC */
9227
9228 $query = "
9229 SELECT MAX(tst_times.tstamp) as last_pass_access
9230 FROM tst_times
9231 WHERE active_fi = %s
9232 AND pass = %s
9233 ";
9234
9235 $res = $DIC->database()->queryF(
9236 $query,
9237 array('integer', 'integer'),
9238 array($activeId, $passIndex)
9239 );
9240
9241 while ($row = $DIC->database()->fetchAssoc($res)) {
9242 return $row['last_pass_access'];
9243 }
9244
9245 return null;
9246 }
9247
9255 public function isHTML($a_text)
9256 {
9257 if (preg_match("/<[^>]*?>/", $a_text)) {
9258 return true;
9259 } else {
9260 return false;
9261 }
9262 }
9263
9271 public function QTIMaterialToString($a_material)
9272 {
9273 $result = "";
9274 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
9275 $material = $a_material->getMaterial($i);
9276 if (strcmp($material["type"], "mattext") == 0) {
9277 $result .= $material["material"]->getContent();
9278 }
9279 if (strcmp($material["type"], "matimage") == 0) {
9280 $matimage = $material["material"];
9281 if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) {
9282 // import an mediaobject which was inserted using tiny mce
9283 if (!is_array($_SESSION["import_mob_xhtml"])) {
9284 $_SESSION["import_mob_xhtml"] = array();
9285 }
9286 array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
9287 }
9288 }
9289 }
9290 global $DIC;
9291 $ilLog = $DIC['ilLog'];
9292 $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
9293 return $result;
9294 }
9295
9304 public function addQTIMaterial(&$a_xml_writer, $a_material)
9305 {
9306 include_once "./Services/RTE/classes/class.ilRTE.php";
9307 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9308
9309 $a_xml_writer->xmlStartTag("material");
9310 $attrs = array(
9311 "texttype" => "text/plain"
9312 );
9313 if ($this->isHTML($a_material)) {
9314 $attrs["texttype"] = "text/xhtml";
9315 }
9316 $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
9317
9318 $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9319 foreach ($mobs as $mob) {
9320 $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9321 if (strpos($a_material, "mm_$mob") !== false) {
9322 if (ilObjMediaObject::_exists($mob)) {
9323 $mob_obj = new ilObjMediaObject($mob);
9324 $imgattrs = array(
9325 "label" => $moblabel,
9326 "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9327 );
9328 }
9329 $a_xml_writer->xmlElement("matimage", $imgattrs, null);
9330 }
9331 }
9332 $a_xml_writer->xmlEndTag("material");
9333 }
9334
9341 public function prepareTextareaOutput($txt_output, $prepare_for_latex_output = false, $omitNl2BrWhenTextArea = false)
9342 {
9343 include_once "./Services/Utilities/classes/class.ilUtil.php";
9344 return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output, $omitNl2BrWhenTextArea);
9345 }
9346
9353 public function saveCertificateVisibility($a_value)
9354 {
9355 global $DIC;
9356 $ilDB = $DIC['ilDB'];
9357
9358 $affectedRows = $ilDB->manipulateF(
9359 "UPDATE tst_tests SET certificate_visibility = %s, tstamp = %s WHERE test_id = %s",
9360 array('text', 'integer', 'integer'),
9361 array($a_value, time(), $this->getTestId())
9362 );
9363 }
9364
9372 {
9373 return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0;
9374 }
9375
9382 public function setCertificateVisibility($a_value)
9383 {
9384 $this->certificate_visibility = $a_value;
9385 }
9386
9393 public function getAnonymity()
9394 {
9395 return ($this->anonymity) ? 1 : 0;
9396 }
9397
9404 public function setAnonymity($a_value = 0)
9405 {
9406 switch ($a_value) {
9407 case 1:
9408 $this->anonymity = 1;
9409 break;
9410 default:
9411 $this->anonymity = 0;
9412 break;
9413 }
9414 }
9415
9422 public function getShowCancel()
9423 {
9424 return ($this->show_cancel) ? 1 : 0;
9425 }
9426
9433 public function setShowCancel($a_value = 1)
9434 {
9435 switch ($a_value) {
9436 case 1:
9437 $this->show_cancel = 1;
9438 break;
9439 default:
9440 $this->show_cancel = 0;
9441 break;
9442 }
9443 }
9444
9451 public function getShowMarker()
9452 {
9453 return ($this->show_marker) ? 1 : 0;
9454 }
9455
9462 public function setShowMarker($a_value = 1)
9463 {
9464 switch ($a_value) {
9465 case 1:
9466 $this->show_marker = 1;
9467 break;
9468 default:
9469 $this->show_marker = 0;
9470 break;
9471 }
9472 }
9473
9480 public function getFixedParticipants()
9481 {
9482 return ($this->fixed_participants) ? 1 : 0;
9483 }
9484
9491 public function setFixedParticipants($a_value = 1)
9492 {
9493 switch ($a_value) {
9494 case 1:
9495 $this->fixed_participants = 1;
9496 break;
9497 default:
9498 $this->fixed_participants = 0;
9499 break;
9500 }
9501 }
9502
9510 public static function _lookupAnonymity($a_obj_id)
9511 {
9512 global $DIC;
9513 $ilDB = $DIC['ilDB'];
9514
9515 $result = $ilDB->queryF(
9516 "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
9517 array('integer'),
9518 array($a_obj_id)
9519 );
9520 while ($row = $ilDB->fetchAssoc($result)) {
9521 return $row['anonymity'];
9522 }
9523 return 0;
9524 }
9525
9532 public static function lookupQuestionSetTypeByActiveId($active_id)
9533 {
9534 global $DIC;
9535 $ilDB = $DIC['ilDB'];
9536
9537 $query = "
9538 SELECT tst_tests.question_set_type
9539 FROM tst_active
9540 INNER JOIN tst_tests
9541 ON tst_active.test_fi = tst_tests.test_id
9542 WHERE tst_active.active_id = %s
9543 ";
9544
9545 $res = $ilDB->queryF($query, array('integer'), array($active_id));
9546
9547 while ($row = $ilDB->fetchAssoc($res)) {
9548 return $row['question_set_type'];
9549 }
9550
9551 return null;
9552 }
9553
9562 public function _lookupRandomTestFromActiveId($active_id)
9563 {
9564 throw new Exception(__METHOD__ . ' is deprecated ... use ilObjTest::lookupQuestionSetTypeByActiveId() instead!');
9565
9566 global $DIC;
9567 $ilDB = $DIC['ilDB'];
9568
9569 $result = $ilDB->queryF(
9570 "SELECT tst_tests.random_test FROM tst_tests, tst_active WHERE tst_active.active_id = %s AND tst_active.test_fi = tst_tests.test_id",
9571 array('integer'),
9572 array($active_id)
9573 );
9574 while ($row = $ilDB->fetchAssoc($result)) {
9575 return $row['random_test'];
9576 }
9577 return 0;
9578 }
9579
9590 public function userLookupFullName($user_id, $overwrite_anonymity = false, $sorted_order = false, $suffix = "")
9591 {
9592 if ($this->getAnonymity() && !$overwrite_anonymity) {
9593 return $this->lng->txt("anonymous") . $suffix;
9594 } else {
9595 include_once './Services/User/classes/class.ilObjUser.php';
9596 $uname = ilObjUser::_lookupName($user_id);
9597 if (strlen($uname["firstname"] . $uname["lastname"]) == 0) {
9598 $uname["firstname"] = $this->lng->txt("deleted_user");
9599 }
9600 if ($sorted_order) {
9601 return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9602 } else {
9603 return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9604 }
9605 }
9606 }
9607
9615 public function getStartTestLabel($active_id)
9616 {
9617 if ($this->getNrOfTries() == 1) {
9618 return $this->lng->txt("tst_start_test");
9619 }
9620 $active_pass = self::_getPass($active_id);
9621 $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9622 if ($res == 0) {
9623 if ($active_pass == 0) {
9624 return $this->lng->txt("tst_start_test");
9625 } else {
9626 return $this->lng->txt("tst_start_new_test_pass");
9627 }
9628 } else {
9629 return $this->lng->txt("tst_resume_test");
9630 }
9631 }
9632
9638 public function getAvailableDefaults()
9639 {
9644 global $DIC;
9645 $ilDB = $DIC['ilDB'];
9646 $ilUser = $DIC['ilUser'];
9647
9648 $result = $ilDB->queryF(
9649 "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
9650 array('integer'),
9651 array($ilUser->getId())
9652 );
9653 $defaults = array();
9654 while ($row = $ilDB->fetchAssoc($result)) {
9655 $defaults[$row["test_defaults_id"]] = $row;
9656 }
9657 return $defaults;
9658 }
9659
9667 public function &getTestDefaults($test_defaults_id)
9668 {
9669 return self::_getTestDefaults($test_defaults_id);
9670 }
9671
9672 public static function _getTestDefaults($test_defaults_id)
9673 {
9674 global $DIC;
9675 $ilDB = $DIC['ilDB'];
9676
9677 $result = $ilDB->queryF(
9678 "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9679 array('integer'),
9680 array($test_defaults_id)
9681 );
9682 if ($result->numRows() == 1) {
9683 $row = $ilDB->fetchAssoc($result);
9684 return $row;
9685 } else {
9686 return null;
9687 }
9688 }
9689
9696 public function deleteDefaults($test_default_id)
9697 {
9698 global $DIC;
9699 $ilDB = $DIC['ilDB'];
9700 $affectedRows = $ilDB->manipulateF(
9701 "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9702 array('integer'),
9703 array($test_default_id)
9704 );
9705 }
9706
9713 public function addDefaults($a_name)
9714 {
9715 global $DIC;
9716 $ilDB = $DIC['ilDB'];
9717 $ilUser = $DIC['ilUser'];
9718 $testsettings = array(
9719 "TitleOutput" => $this->getTitleOutput(),
9720 "PassScoring" => $this->getPassScoring(),
9721 "IntroEnabled" => $this->isIntroductionEnabled(),
9722 "Introduction" => $this->getIntroduction(),
9723 "FinalStatement" => $this->getFinalStatement(),
9724 "ShowInfo" => $this->getShowInfo(),
9725 "ForceJS" => $this->getForceJS(),
9726 "CustomStyle" => $this->getCustomStyle(),
9727 "ShowFinalStatement" => $this->getShowFinalStatement(),
9728 "SequenceSettings" => $this->getSequenceSettings(),
9729 "ScoreReporting" => $this->getScoreReporting(),
9730 "ScoreCutting" => $this->getScoreCutting(),
9731 'SpecificAnswerFeedback' => $this->getSpecificAnswerFeedback(),
9732 'PrintBsWithRes' => (int) $this->isBestSolutionPrintedWithResult(),
9733 "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9734 "AnswerFeedback" => $this->getAnswerFeedback(),
9735 "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9736 "ResultsPresentation" => $this->getResultsPresentation(),
9737 "Anonymity" => $this->getAnonymity(),
9738 "ShowCancel" => $this->getShowCancel(),
9739 "ShowMarker" => $this->getShowMarker(),
9740 "ReportingDate" => $this->getReportingDate(),
9741 "NrOfTries" => $this->getNrOfTries(),
9742 'BlockAfterPassed' => (int) $this->isBlockPassesAfterPassedEnabled(),
9743 "Shuffle" => $this->getShuffleQuestions(),
9744 "Kiosk" => $this->getKiosk(),
9745 "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9746 "ProcessingTime" => $this->getProcessingTime(),
9747 "EnableProcessingTime" => $this->getEnableProcessingTime(),
9748 "ResetProcessingTime" => $this->getResetProcessingTime(),
9749 "StartingTimeEnabled" => $this->isStartingTimeEnabled(),
9750 "StartingTime" => $this->getStartingTime(),
9751 "EndingTimeEnabled" => $this->isEndingTimeEnabled(),
9752 "EndingTime" => $this->getEndingTime(),
9753 "ECTSOutput" => $this->getECTSOutput(),
9754 "ECTSFX" => $this->getECTSFX(),
9755 "ECTSGrades" => $this->getECTSGrades(),
9756 "questionSetType" => $this->getQuestionSetType(),
9757 "CountSystem" => $this->getCountSystem(),
9758 "MCScoring" => $this->getMCScoring(),
9759 "mailnotification" => $this->getMailNotification(),
9760 "mailnottype" => $this->getMailNotificationType(),
9761 "exportsettings" => $this->getExportSettings(),
9762 "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings(),
9763 'obligations_enabled' => (int) $this->areObligationsEnabled(),
9764 'offer_question_hints' => (int) $this->isOfferingQuestionHintsEnabled(),
9765 'pass_deletion_allowed' => (int) $this->isPassDeletionAllowed(),
9766 'enable_examview' => $this->getEnableExamview(),
9767 'show_examview_html' => $this->getShowExamviewHtml(),
9768 'show_examview_pdf' => $this->getShowExamviewPdf(),
9769 'char_selector_availability' => $this->getCharSelectorAvailability(),
9770 'char_selector_definition' => $this->getCharSelectorDefinition(),
9771 'skill_service' => (int) $this->isSkillServiceEnabled(),
9772 'result_tax_filters' => (array) $this->getResultFilterTaxIds(),
9773 'show_grading_status' => (int) $this->isShowGradingStatusEnabled(),
9774 'show_grading_mark' => (int) $this->isShowGradingMarkEnabled(),
9775
9776 'follow_qst_answer_fixation' => $this->isFollowupQuestionAnswerFixationEnabled(),
9777 'inst_fb_answer_fixation' => $this->isInstantFeedbackAnswerFixationEnabled(),
9778 'force_inst_fb' => $this->isForceInstantFeedbackEnabled(),
9779 'redirection_mode' => $this->getRedirectionMode(),
9780 'redirection_url' => $this->getRedirectionUrl(),
9781 'sign_submission' => $this->getSignSubmission(),
9782 'autosave' => (int) $this->getAutosave(),
9783 'autosave_ival' => (int) $this->getAutosaveIval(),
9784 'examid_in_test_pass' => (int) $this->isShowExamIdInTestPassEnabled(),
9785 'examid_in_test_res' => (int) $this->isShowExamIdInTestResultsEnabled(),
9786
9787 'enable_archiving' => (int) $this->getEnableArchiving(),
9788 'password_enabled' => (int) $this->isPasswordEnabled(),
9789 'password' => (string) $this->getPassword(),
9790 'fixed_participants' => $this->getFixedParticipants(),
9791 'limit_users_enabled' => $this->isLimitUsersEnabled(),
9792 'allowedusers' => $this->getAllowedUsers(),
9793 'alloweduserstimegap' => $this->getAllowedUsersTimeGap(),
9794 'pool_usage' => $this->getPoolUsage(),
9795 'activation_limited' => $this->isActivationLimited(),
9796 'activation_start_time' => $this->getActivationStartingTime(),
9797 'activation_end_time' => $this->getActivationEndingTime(),
9798 'activation_visibility' => $this->getActivationVisibility(),
9799 'highscore_enabled' => $this->getHighscoreEnabled(),
9800 'highscore_anon' => $this->getHighscoreAnon(),
9801 'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
9802 'highscore_score' => $this->getHighscoreScore(),
9803 'highscore_percentage' => $this->getHighscorePercentage(),
9804 'highscore_hints' => $this->getHighscoreHints(),
9805 'highscore_wtime' => $this->getHighscoreWTime(),
9806 'highscore_own_table' => $this->getHighscoreOwnTable(),
9807 'highscore_top_table' => $this->getHighscoreTopTable(),
9808 'highscore_top_num' => $this->getHighscoreTopNum(),
9809 'use_previous_answers' => (string) $this->getUsePreviousAnswers(),
9810 'pass_waiting' => $this->getPassWaiting()
9811 );
9812
9813 $next_id = $ilDB->nextId('tst_test_defaults');
9814 $ilDB->insert(
9815 'tst_test_defaults',
9816 array(
9817 'test_defaults_id' => array('integer', $next_id),
9818 'name' => array('text', $a_name),
9819 'user_fi' => array('integer', $ilUser->getId()),
9820 'defaults' => array('clob', serialize($testsettings)),
9821 'marks' => array('clob', serialize($this->mark_schema)),
9822 'tstamp' => array('integer', time())
9823 )
9824 );
9825 }
9826
9834 public function applyDefaults($test_defaults)
9835 {
9836 $testsettings = unserialize($test_defaults["defaults"]);
9837 include_once "./Modules/Test/classes/class.assMarkSchema.php";
9838 $this->mark_schema = unserialize($test_defaults["marks"]);
9839
9840 $this->setTitleOutput($testsettings["TitleOutput"]);
9841 $this->setPassScoring($testsettings["PassScoring"]);
9842 $this->setIntroductionEnabled($testsettings["IntroEnabled"]);
9843 $this->setIntroduction($testsettings["Introduction"]);
9844 $this->setFinalStatement($testsettings["FinalStatement"]);
9845 $this->setShowInfo($testsettings["ShowInfo"]);
9846 $this->setForceJS($testsettings["ForceJS"]);
9847 $this->setCustomStyle($testsettings["CustomStyle"]);
9848 $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
9849 $this->setSequenceSettings($testsettings["SequenceSettings"]);
9850 $this->setScoreReporting($testsettings["ScoreReporting"]);
9851 $this->setScoreCutting($testsettings['ScoreCutting']);
9852 $this->setSpecificAnswerFeedback($testsettings['SpecificAnswerFeedback']);
9853 $this->setPrintBestSolutionWithResult((bool) $testsettings['PrintBsWithRes']);
9854 $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
9855 $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
9856 $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
9857 $this->setResultsPresentation($testsettings["ResultsPresentation"]);
9858 $this->setAnonymity($testsettings["Anonymity"]);
9859 $this->setShowCancel($testsettings["ShowCancel"]);
9860 $this->setShuffleQuestions($testsettings["Shuffle"]);
9861 $this->setShowMarker($testsettings["ShowMarker"]);
9862 $this->setReportingDate($testsettings["ReportingDate"]);
9863 $this->setNrOfTries($testsettings["NrOfTries"]);
9864 $this->setBlockPassesAfterPassedEnabled((bool) $testsettings['BlockAfterPassed']);
9865 $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
9866 $this->setRedirectionMode($testsettings['redirection_mode']);
9867 $this->setRedirectionUrl($testsettings['redirection_url']);
9868 $this->setProcessingTime($testsettings["ProcessingTime"]);
9869 $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
9870 $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
9871 $this->setStartingTimeEnabled($testsettings["StartingTimeEnabled"]);
9872 $this->setStartingTime($testsettings["StartingTime"]);
9873 $this->setKiosk($testsettings["Kiosk"]);
9874 $this->setEndingTimeEnabled($testsettings["EndingTimeEnabled"]);
9875 $this->setEndingTime($testsettings["EndingTime"]);
9876 $this->setECTSOutput($testsettings["ECTSOutput"]);
9877 $this->setECTSFX($testsettings["ECTSFX"]);
9878 $this->setECTSGrades($testsettings["ECTSGrades"]);
9879 if (isset($testsettings["isRandomTest"])) {
9880 if ($testsettings["isRandomTest"]) {
9881 $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
9882 } else {
9883 $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
9884 }
9885 } elseif (isset($testsettings["questionSetType"])) {
9886 $this->setQuestionSetType($testsettings["questionSetType"]);
9887 }
9888 $this->setCountSystem($testsettings["CountSystem"]);
9889 $this->setMCScoring($testsettings["MCScoring"]);
9890 $this->setMailNotification($testsettings["mailnotification"]);
9891 $this->setMailNotificationType($testsettings["mailnottype"]);
9892 $this->setExportSettings($testsettings['exportsettings']);
9893 $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
9894 $this->setObligationsEnabled($testsettings["obligations_enabled"]);
9895 $this->setOfferingQuestionHintsEnabled($testsettings["offer_question_hints"]);
9896 $this->setHighscoreEnabled($testsettings['highscore_enabled']);
9897 $this->setHighscoreAnon($testsettings['highscore_anon']);
9898 $this->setHighscoreAchievedTS($testsettings['highscore_achieved_ts']);
9899 $this->setHighscoreScore($testsettings['highscore_score']);
9900 $this->setHighscorePercentage($testsettings['highscore_percentage']);
9901 $this->setHighscoreHints($testsettings['highscore_hints']);
9902 $this->setHighscoreWTime($testsettings['highscore_wtime']);
9903 $this->setHighscoreOwnTable($testsettings['highscore_own_table']);
9904 $this->setHighscoreTopTable($testsettings['highscore_top_table']);
9905 $this->setHighscoreTopNum($testsettings['highscore_top_num']);
9906 $this->setPassDeletionAllowed($testsettings['pass_deletion_allowed']);
9907 if (isset($testsettings['examid_in_kiosk'])) {
9908 $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_kiosk']);
9909 } else {
9910 $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_test_pass']);
9911 }
9912 if (isset($testsettings['show_exam_id'])) {
9913 $this->setShowExamIdInTestResultsEnabled($testsettings['show_exam_id']);
9914 } else {
9915 $this->setShowExamIdInTestResultsEnabled($testsettings['examid_in_test_res']);
9916 }
9917 $this->setEnableExamview($testsettings['enable_examview']);
9918 $this->setShowExamviewHtml($testsettings['show_examview_html']);
9919 $this->setShowExamviewPdf($testsettings['show_examview_pdf']);
9920 $this->setEnableArchiving($testsettings['enable_archiving']);
9921 $this->setSignSubmission($testsettings['sign_submission']);
9922 $this->setCharSelectorAvailability($testsettings['char_selector_availability']);
9923 $this->setCharSelectorDefinition($testsettings['char_selector_definition']);
9924 $this->setSkillServiceEnabled((bool) $testsettings['skill_service']);
9925 $this->setResultFilterTaxIds((array) $testsettings['result_tax_filters']);
9926 $this->setShowGradingStatusEnabled((bool) $testsettings['show_grading_status']);
9927 $this->setShowGradingMarkEnabled((bool) $testsettings['show_grading_mark']);
9928
9929 $this->setFollowupQuestionAnswerFixationEnabled($testsettings['follow_qst_answer_fixation']);
9930 $this->setInstantFeedbackAnswerFixationEnabled($testsettings['inst_fb_answer_fixation']);
9931 $this->setForceInstantFeedbackEnabled($testsettings['force_inst_fb']);
9932 $this->setRedirectionMode($testsettings['redirection_mode']);
9933 $this->setRedirectionUrl($testsettings['redirection_url']);
9934
9935 $this->setAutosave($testsettings['autosave']);
9936 $this->setAutosaveIval($testsettings['autosave_ival']);
9937 $this->setShowExamIdInTestResultsEnabled((int) $testsettings['examid_in_test_res']);
9938 $this->setPasswordEnabled($testsettings['password_enabled']);
9939 $this->setPassword($testsettings['password']);
9940 $this->setFixedParticipants($testsettings['fixed_participants']);
9941 $this->setLimitUsersEnabled($testsettings['limit_users_enabled']);
9942 $this->setAllowedUsers($testsettings['allowedusers']);
9943 $this->setAllowedUsersTimeGap($testsettings['alloweduserstimegap']);
9944 $this->setUsePreviousAnswers($testsettings['use_previous_answers']);
9945 $this->setPoolUsage($testsettings['pool_usage']);
9946 $this->setActivationLimited($testsettings['activation_limited']);
9947 $this->setActivationStartingTime($testsettings['activation_start_time']);
9948 $this->setActivationEndingTime($testsettings['activation_end_time']);
9949 $this->setActivationVisibility($testsettings['activation_visibility']);
9950 $this->setPassWaiting($testsettings['pass_waiting']);
9951
9952 $this->saveToDb();
9953
9954 return true;
9955 }
9956
9964 public function processPrintoutput2FO($print_output)
9965 {
9966 if (extension_loaded("tidy")) {
9967 $config = array(
9968 "indent" => false,
9969 "output-xml" => true,
9970 "numeric-entities" => true
9971 );
9972 $tidy = new tidy();
9973 $tidy->parseString($print_output, $config, 'utf8');
9974 $tidy->cleanRepair();
9975 $print_output = tidy_get_output($tidy);
9976 $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
9977 } else {
9978 $print_output = str_replace("&nbsp;", "&#160;", $print_output);
9979 $print_output = str_replace("&otimes;", "X", $print_output);
9980 }
9981 $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
9982
9983 // additional font support
9984 global $DIC;
9985 $xsl = str_replace(
9986 'font-family="Helvetica, unifont"',
9987 'font-family="' . $DIC['ilSetting']->get('rpc_pdf_font', 'Helvetica, unifont') . '"',
9988 $xsl
9989 );
9990
9991 $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
9992 $xh = xslt_create();
9993 $params = array();
9994 $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", null, $args, $params);
9995 xslt_error($xh);
9996 xslt_free($xh);
9997 return $output;
9998 }
9999
10006 public function deliverPDFfromHTML($content, $title = null)
10007 {
10008 $content = preg_replace("/href=\".*?\"/", "", $content);
10009 $printbody = new ilTemplate("tpl.il_as_tst_print_body.html", true, true, "Modules/Test");
10010 $printbody->setVariable("TITLE", ilUtil::prepareFormOutput($this->getTitle()));
10011 $printbody->setVariable("ADM_CONTENT", $content);
10012 $printbody->setCurrentBlock("css_file");
10013 $printbody->setVariable("CSS_FILE", $this->getTestStyleLocation("filesystem"));
10014 $printbody->parseCurrentBlock();
10015 $printbody->setCurrentBlock("css_file");
10016 $printbody->setVariable("CSS_FILE", ilUtil::getStyleSheetLocation("filesystem", "delos.css"));
10017 $printbody->parseCurrentBlock();
10018 $printoutput = $printbody->get();
10019 $html = str_replace("href=\"./", "href=\"" . ILIAS_HTTP_PATH . "/", $printoutput);
10020 $html = preg_replace("/<div id=\"dontprint\">.*?<\\/div>/ims", "", $html);
10021 if (extension_loaded("tidy")) {
10022 $config = array(
10023 "indent" => false,
10024 "output-xml" => true,
10025 "numeric-entities" => true
10026 );
10027 $tidy = new tidy();
10028 $tidy->parseString($html, $config, 'utf8');
10029 $tidy->cleanRepair();
10030 $html = tidy_get_output($tidy);
10031 $html = preg_replace("/^.*?(<html)/", "\\1", $html);
10032 } else {
10033 $html = str_replace("&nbsp;", "&#160;", $html);
10034 $html = str_replace("&otimes;", "X", $html);
10035 }
10036 $html = preg_replace("/src=\".\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
10037 $this->deliverPDFfromFO($this->processPrintoutput2FO($html), $title);
10038 }
10039
10046 public function deliverPDFfromFO($fo, $title = null)
10047 {
10048 global $DIC;
10049 $ilLog = $DIC['ilLog'];
10050
10051 include_once "./Services/Utilities/classes/class.ilUtil.php";
10052 $fo_file = ilUtil::ilTempnam() . ".fo";
10053 $fp = fopen($fo_file, "w");
10054 fwrite($fp, $fo);
10055 fclose($fp);
10056
10057 include_once './Services/WebServices/RPC/classes/class.ilRpcClientFactory.php';
10058 try {
10059 $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo);
10060 $filename = (strlen($title)) ? $title : $this->getTitle();
10061 ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
10062 return true;
10063 } catch (Exception $e) {
10064 $ilLog->write(__METHOD__ . ': ' . $e->getMessage());
10065 return false;
10066 }
10067 }
10068
10078 public static function getManualFeedback($active_id, $question_id, $pass)
10079 {
10080 $feedback = "";
10081 $row = self::getSingleManualFeedback($active_id, $question_id, $pass);
10082
10083 if (count($row) > 0 && ($row['finalized_evaluation'] || \ilTestService::isManScoringDone($active_id))) {
10084 $feedback = $row['feedback'];
10085 }
10086
10087 return $feedback;
10088 }
10089
10099 public static function getSingleManualFeedback($active_id, $question_id, $pass)
10100 {
10101 global $DIC;
10102
10103 $ilDB = $DIC->database();
10104 $row = array();
10105 $result = $ilDB->queryF(
10106 "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10107 array('integer', 'integer', 'integer'),
10108 array($active_id, $question_id, $pass)
10109 );
10110
10111 if ($result->numRows() === 1) {
10112 $row = $ilDB->fetchAssoc($result);
10113 $row['feedback'] = ilRTE::_replaceMediaObjectImageSrc($row['feedback'], 1);
10114 } else {
10115 $DIC->logger()->root()->warning("WARNING: Multiple feedback entries on tst_manual_fb for " .
10116 "active_fi = $active_id , question_fi = $question_id and pass = $pass");
10117 }
10118
10119 return $row;
10120 }
10121
10129 public static function getCompleteManualFeedback(int $question_id)
10130 {
10131 global $DIC;
10132
10133 $ilDB = $DIC->database();
10134 $feedback = array();
10135 $result = $ilDB->queryF(
10136 "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
10137 array('integer'),
10138 array($question_id)
10139 );
10140
10141 while ($row = $ilDB->fetchAssoc($result)) {
10142 $active = $row['active_fi'];
10143 $pass = $row['pass'];
10144 $question = $row['question_fi'];
10145
10146 $row['feedback'] = ilRTE::_replaceMediaObjectImageSrc($row['feedback'], 1);
10147
10148 $feedback[$active][$pass][$question] = $row;
10149 }
10150
10151 return $feedback;
10152 }
10153
10165 public function saveManualFeedback($active_id, $question_id, $pass, $feedback, $finalized = false, $is_single_feedback = false)
10166 {
10167 global $DIC;
10168
10169 $feedback_old = $this->getSingleManualFeedback($active_id, $question_id, $pass);
10170
10171 $finalized_record = (int) $feedback_old['finalized_evaluation'];
10172 if ($finalized_record === 0 || ($is_single_feedback && $finalized_record === 1)) {
10173 $DIC->database()->manipulateF(
10174 "DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10175 array('integer', 'integer', 'integer'),
10176 array($active_id, $question_id, $pass)
10177 );
10178
10179 $this->insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
10180
10182 $this->logManualFeedback($active_id, $question_id, $feedback);
10183 }
10184 }
10185
10186 return true;
10187 }
10188
10199 private function insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old)
10200 {
10201 global $DIC;
10202
10203 $ilDB = $DIC->database();
10204 $ilUser = $DIC->user();
10205 $next_id = $ilDB->nextId('tst_manual_fb');
10206 $user = $ilUser->getId();
10207 $finalized_time = time();
10208
10209 $update_default = [
10210 'manual_feedback_id' => [ 'integer', $next_id],
10211 'active_fi' => [ 'integer', $active_id],
10212 'question_fi' => [ 'integer', $question_id],
10213 'pass' => [ 'integer', $pass],
10214 'feedback' => [ 'clob', ilRTE::_replaceMediaObjectImageSrc($feedback, 0)],
10215 'tstamp' => [ 'integer', time()]
10216 ];
10217
10218 if ($feedback_old['finalized_evaluation'] == 1) {
10219 $user = $feedback_old['finalized_by_usr_id'];
10220 $finalized_time = $feedback_old['finalized_tstamp'];
10221 }
10222
10223 if ($finalized === true || $feedback_old['finalized_evaluation'] == 1) {
10224 if (!array_key_exists('evaluated', $_POST)) {
10225 $update_default['finalized_evaluation'] = ['integer', 0];
10226 $update_default['finalized_by_usr_id'] = ['integer', 0];
10227 $update_default['finalized_tstamp'] = ['integer', 0];
10228 } else {
10229 $update_default['finalized_evaluation'] = ['integer', 1];
10230 $update_default['finalized_by_usr_id'] = ['integer', $user];
10231 $update_default['finalized_tstamp'] = ['integer', $finalized_time];
10232 }
10233 }
10234
10235 $ilDB->insert('tst_manual_fb', $update_default);
10236 }
10237
10245 private function logManualFeedback($active_id, $question_id, $feedback)
10246 {
10247 global $DIC;
10248
10249 $ilUser = $DIC->user();
10250 $lng = $DIC->language();
10251 $username = ilObjTestAccess::_getParticipantData($active_id);
10252
10253 $this->logAction(
10254 sprintf(
10255 $lng->txtlng('assessment', 'log_manual_feedback', ilObjAssessmentFolder::_getLogLanguage()),
10256 $ilUser->getFullname() . ' (' . $ilUser->getLogin() . ')',
10257 $username,
10258 assQuestion::_getQuestionTitle($question_id),
10259 $feedback
10260 )
10261 );
10262 }
10263
10271 public function getJavaScriptOutput()
10272 {
10273 return true;
10274
10275 // global $DIC;
10276// $ilUser = $DIC['ilUser'];
10277// if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
10278// if ($this->getForceJS()) return TRUE;
10279// $assessmentSetting = new ilSetting("assessment");
10280// return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
10281 }
10282
10283 public function &createTestSequence($active_id, $pass, $shuffle)
10284 {
10285 include_once "./Modules/Test/classes/class.ilTestSequence.php";
10286 $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10287 }
10288
10294 public function setTestId($a_id)
10295 {
10296 $this->test_id = $a_id;
10297 }
10298
10307 public function getDetailedTestResults($participants)
10308 {
10309 $results = array();
10310 if (count($participants)) {
10311 foreach ($participants as $active_id => $user_rec) {
10312 $row = array();
10313 $reached_points = 0;
10314 $max_points = 0;
10315 foreach ($this->questions as $value) {
10316 $question = &ilObjTest::_instanciateQuestion($value);
10317 if (is_object($question)) {
10318 $max_points += $question->getMaximumPoints();
10319 $reached_points += $question->getReachedPoints($active_id);
10320 if ($max_points > 0) {
10321 $percentvalue = $reached_points / $max_points;
10322 if ($percentvalue < 0) {
10323 $percentvalue = 0.0;
10324 }
10325 } else {
10326 $percentvalue = 0;
10327 }
10328 if ($this->getAnonymity()) {
10329 $user_rec['firstname'] = "";
10330 $user_rec['lastname'] = $this->lng->txt("anonymous");
10331 }
10332 $row = array(
10333 "user_id" => $user_rec['usr_id'],
10334 "matriculation" => $user_rec['matriculation'],
10335 "lastname" => $user_rec['lastname'],
10336 "firstname" => $user_rec['firstname'],
10337 "login" => $user_rec['login'],
10338 "question_id" => $question->getId(),
10339 "question_title" => $question->getTitle(),
10340 "reached_points" => $reached_points,
10341 "max_points" => $max_points
10342 );
10343 $results[] = $row;
10344 }
10345 }
10346 }
10347 }
10348 return $results;
10349 }
10350
10354 public static function _lookupTestObjIdForQuestionId($a_q_id)
10355 {
10356 global $DIC;
10357 $ilDB = $DIC['ilDB'];
10358
10359 $result = $ilDB->queryF(
10360 "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",
10361 array('integer'),
10362 array($a_q_id)
10363 );
10364 $rec = $ilDB->fetchAssoc($result);
10365 return $rec["obj_id"];
10366 }
10367
10374 public function isPluginActive($a_pname)
10375 {
10376 global $DIC;
10377 $ilPluginAdmin = $DIC['ilPluginAdmin'];
10378 if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname)) {
10379 return true;
10380 } else {
10381 return false;
10382 }
10383 }
10384
10385 public function getPassed($active_id)
10386 {
10387 global $DIC;
10388 $ilDB = $DIC['ilDB'];
10389
10390 $result = $ilDB->queryF(
10391 "SELECT passed FROM tst_result_cache WHERE active_fi = %s",
10392 array('integer'),
10393 array($active_id)
10394 );
10395 if ($result->numRows()) {
10396 $row = $ilDB->fetchAssoc($result);
10397 return $row['passed'];
10398 } else {
10399 $counted_pass = ilObjTest::_getResultPass($active_id);
10400 $result_array = &$this->getTestResult($active_id, $counted_pass);
10401 return $result_array["test"]["passed"];
10402 }
10403 }
10404
10410 public function canShowCertificate($testSession, $user_id, $active_id)
10411 {
10412 if ($this->canShowTestResults($testSession)) {
10413 $isComplete = false;
10414 $userCertificateRepository = new ilUserCertificateRepository($this->db, $this->log);
10415 try {
10416 $userCertificateRepository->fetchActiveCertificate($user_id, $this->getId());
10417 $isComplete = true;
10418 } catch (ilException $e) {
10419 }
10420
10421 if ($isComplete) {
10422 $vis = $this->getCertificateVisibility();
10423 $showcert = false;
10424 switch ($vis) {
10425 case 0:
10426 $showcert = true;
10427 break;
10428 case 1:
10429 if ($this->getPassed($active_id)) {
10430 $showcert = true;
10431 }
10432 break;
10433 case 2:
10434 $showcert = false;
10435 break;
10436 }
10437 if ($showcert) {
10438 return true;
10439 } else {
10440 return false;
10441 }
10442 } else {
10443 return false;
10444 }
10445 } else {
10446 return false;
10447 }
10448 }
10449
10453 public function getParticipantsForTestAndQuestion($test_id, $question_id)
10454 {
10456 global $DIC;
10457 $ilDB = $DIC['ilDB'];
10458
10459 $query = "
10460 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
10461 FROM tst_test_result
10462 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s
10463 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi
10464 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi
10465 WHERE tst_test_result.question_fi = %s
10466 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC
10467 ";
10468
10469 $result = $ilDB->queryF(
10470 $query,
10471 array('integer', 'integer'),
10472 array($test_id, $question_id)
10473 );
10474 $foundusers = array();
10476 while ($row = $ilDB->fetchAssoc($result)) {
10477 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row["active_fi"])) {
10478 continue;
10479 }
10480
10481 if (!array_key_exists($row["active_fi"], $foundusers)) {
10482 $foundusers[$row["active_fi"]] = array();
10483 }
10484 array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10485 }
10486 return $foundusers;
10487 }
10488
10495 {
10496 $data = &$this->getCompleteEvaluationData();
10497 $foundParticipants = &$data->getParticipants();
10498 $results = array("overview" => array(), "questions" => array());
10499 if (count($foundParticipants)) {
10500 $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10501 $total_finished = $data->getTotalFinishedParticipants();
10502 $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10503 $average_time = $this->evalTotalStartedAverageTime($data->getParticipantIds());
10504 $diff_seconds = $average_time;
10505 $diff_hours = floor($diff_seconds / 3600);
10506 $diff_seconds -= $diff_hours * 3600;
10507 $diff_minutes = floor($diff_seconds / 60);
10508 $diff_seconds -= $diff_minutes * 60;
10509 $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10510 $total_passed = 0;
10511 $total_passed_reached = 0;
10512 $total_passed_max = 0;
10513 $total_passed_time = 0;
10514 foreach ($foundParticipants as $userdata) {
10515 if ($userdata->getPassed()) {
10516 $total_passed++;
10517 $total_passed_reached += $userdata->getReached();
10518 $total_passed_max += $userdata->getMaxpoints();
10519 $total_passed_time += $userdata->getTimeOfWork();
10520 }
10521 }
10522 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10523 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10524 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10525 $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10526 $results["overview"][$this->lng->txt("tst_eval_total_passed_average_points")] = sprintf("%2.2f", $average_passed_reached) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%2.2f", $average_passed_max);
10527 $average_time = $average_passed_time;
10528 $diff_seconds = $average_time;
10529 $diff_hours = floor($diff_seconds / 3600);
10530 $diff_seconds -= $diff_hours * 3600;
10531 $diff_minutes = floor($diff_seconds / 60);
10532 $diff_seconds -= $diff_minutes * 60;
10533 $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10534 }
10535
10536 foreach ($data->getQuestionTitles() as $question_id => $question_title) {
10537 $answered = 0;
10538 $reached = 0;
10539 $max = 0;
10540 foreach ($foundParticipants as $userdata) {
10541 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
10542 if (is_object($userdata->getPass($i))) {
10543 $question = &$userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10544 if (is_array($question)) {
10545 $answered++;
10546 $reached += $question["reached"];
10547 $max += $question["points"];
10548 }
10549 }
10550 }
10551 }
10552 $percent = $max ? $reached / $max * 100.0 : 0;
10553 $results["questions"][$question_id] = array(
10554 $question_title,
10555 sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10556 sprintf("%.2f", $percent) . "%",
10557 $answered,
10558 sprintf("%.2f", $answered ? $reached / $answered : 0),
10559 sprintf("%.2f", $answered ? $max / $answered : 0),
10560 $percent / 100.0
10561 );
10562 }
10563 return $results;
10564 }
10565
10569 public function getXMLZip()
10570 {
10571 require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10572 $expFactory = new ilTestExportFactory($this);
10573 $test_exp = $expFactory->getExporter('xml');
10574 return $test_exp->buildExportFile();
10575 }
10576
10580 public function getMailNotification()
10581 {
10583 }
10584
10590 public function setMailNotification($a_notification)
10591 {
10592 $this->mailnotification = $a_notification;
10593 }
10594
10595 public function sendSimpleNotification($active_id)
10596 {
10597 include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10598
10599 $mail = new ilTestMailNotification();
10600 $owner_id = $this->getOwner();
10601 $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10602 $mail->sendSimpleNotification($owner_id, $this->getTitle(), $usr_data);
10603 }
10604
10611 {
10612 include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
10613 include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
10614 $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI($this->getRefId()), 'outEvaluation', $this->getAnonymity());
10615 return $table_gui->getSelectedColumns();
10616 }
10617
10618 public function sendAdvancedNotification($active_id)
10619 {
10620 include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10621
10622 $mail = new ilTestMailNotification();
10623 $owner_id = $this->getOwner();
10624 $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10625
10626 $participantList = new ilTestParticipantList($this);
10627 $participantList->initializeFromDbRows($this->getTestParticipants());
10628
10629 require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10630 $expFactory = new ilTestExportFactory($this);
10631 $exportObj = $expFactory->getExporter('results');
10632 $exportObj->setForcedAccessFilteredParticipantList($participantList);
10633 $file = $exportObj->exportToExcel($deliver = false, 'active_id', $active_id, $passedonly = false);
10634 include_once "./Services/Mail/classes/class.ilFileDataMail.php";
10635 $fd = new ilFileDataMail(ANONYMOUS_USER_ID);
10636 $fd->copyAttachmentFile($file, "result_" . $active_id . ".xls");
10637 $file_names[] = "result_" . $active_id . ".xls";
10638
10639 $mail->sendAdvancedNotification($owner_id, $this->getTitle(), $usr_data, $file_names);
10640
10641 if (count($file_names)) {
10642 $fd->unlinkFiles($file_names);
10643 unset($fd);
10644 @unlink($file);
10645 }
10646 }
10647
10648 public function getResultsForActiveId($active_id)
10649 {
10650 global $DIC;
10651 $ilDB = $DIC['ilDB'];
10652
10653 $query = "
10654 SELECT *
10655 FROM tst_result_cache
10656 WHERE active_fi = %s
10657 ";
10658
10659 $result = $ilDB->queryF(
10660 $query,
10661 array('integer'),
10662 array($active_id)
10663 );
10664
10665 if (!$result->numRows()) {
10666 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10667
10669
10670 $query = "
10671 SELECT *
10672 FROM tst_result_cache
10673 WHERE active_fi = %s
10674 ";
10675
10676 $result = $ilDB->queryF(
10677 $query,
10678 array('integer'),
10679 array($active_id)
10680 );
10681 }
10682
10683 $row = $ilDB->fetchAssoc($result);
10684
10685 return $row;
10686 }
10687
10688 public function getMailNotificationType()
10689 {
10690 if ($this->mailnottype == 1) {
10691 return $this->mailnottype;
10692 } else {
10693 return 0;
10694 }
10695 }
10696
10698 {
10699 if ($a_type == 1) {
10700 $this->mailnottype = 1;
10701 } else {
10702 $this->mailnottype = 0;
10703 }
10704 }
10705
10706 public function getExportSettings()
10707 {
10708 if ($this->exportsettings) {
10709 return $this->exportsettings;
10710 } else {
10711 return 0;
10712 }
10713 }
10714
10715 public function setExportSettings($a_settings)
10716 {
10717 if ($a_settings) {
10718 $this->exportsettings = $a_settings;
10719 } else {
10720 $this->exportsettings = 0;
10721 }
10722 }
10723
10725 {
10726 if (($this->exportsettings & 1) > 0) {
10727 return true;
10728 } else {
10729 return false;
10730 }
10731 }
10732
10733 public function setExportSettingsSingleChoiceShort($a_settings)
10734 {
10735 if ($a_settings) {
10736 $this->exportsettings = $this->exportsettings | 1;
10737 } else {
10739 $this->exportsettings = $this->exportsettings ^ 1;
10740 }
10741 }
10742 }
10743
10744 public function getEnabledViewMode()
10745 {
10746 return $this->enabled_view_mode;
10747 }
10748
10749 public function setEnabledViewMode($mode)
10750 {
10751 $this->enabled_view_mode = $mode;
10752 }
10753
10754 public function setTemplate($template_id)
10755 {
10756 $this->template_id = (int) $template_id;
10757 }
10758
10759 public function getTemplate()
10760 {
10761 return $this->template_id;
10762 }
10763
10764 public function moveQuestionAfterOLD($previous_question_id, $new_question_id)
10765 {
10766 $new_array = array();
10767 $position = 1;
10768
10769 $query = 'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
10770 $types = array('integer');
10771 $values = array($this->getTestId());
10772
10773 $new_question_id += 1;
10774
10775 global $DIC;
10776 $ilDB = $DIC['ilDB'];
10777 $inserted = false;
10778 $res = $ilDB->queryF($query, $types, $values);
10779 while ($row = $ilDB->fetchAssoc($res)) {
10780 $qid = $row['question_fi'];
10781
10782 if ($qid == $new_question_id) {
10783 continue;
10784 } elseif ($qid == $previous_question_id) {
10785 $new_array[$position++] = $qid;
10786 $new_array[$position++] = $new_question_id;
10787 $inserted = true;
10788 } else {
10789 $new_array[$position++] = $qid;
10790 }
10791 }
10792
10793 $update_query = 'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
10794 $update_types = array('integer', 'integer', 'integer');
10795
10796 foreach ($new_array as $position => $qid) {
10797 $ilDB->manipulateF(
10798 $update_query,
10799 $update_types,
10800 $vals = array(
10801 $position,
10802 $this->getTestId(),
10803 $qid
10804 )
10805 );
10806 }
10807 }
10808
10810 {
10811 return (
10814 );
10815 }
10816
10818 {
10819 $values = array();
10820
10821 if ($this->getSpecificAnswerFeedback()) {
10822 $values[] = 'instant_feedback_specific';
10823 }
10824 if ($this->getGenericAnswerFeedback()) {
10825 $values[] = 'instant_feedback_generic';
10826 }
10827 if ($this->getAnswerFeedbackPoints()) {
10828 $values[] = 'instant_feedback_points';
10829 }
10830 if ($this->getInstantFeedbackSolution()) {
10831 $values[] = 'instant_feedback_solution';
10832 }
10833
10834 return $values;
10835 }
10836
10837 public function setInstantFeedbackOptionsByArray($options)
10838 {
10839 if (is_array($options)) {
10840 $this->setGenericAnswerFeedback(in_array('instant_feedback_generic', $options) ? 1 : 0);
10841 $this->setSpecificAnswerFeedback(in_array('instant_feedback_specific', $options) ? 1 : 0);
10842 $this->setAnswerFeedbackPoints(in_array('instant_feedback_points', $options) ? 1 : 0);
10843 $this->setInstantFeedbackSolution(in_array('instant_feedback_solution', $options) ? 1 : 0);
10844 } else {
10845 $this->setGenericAnswerFeedback(0);
10846 $this->setSpecificAnswerFeedback(0);
10847 $this->setAnswerFeedbackPoints(0);
10849 }
10850 }
10851
10853 {
10854 $setter = array(
10855 'pass_details' => 'setShowPassDetails',
10856 'solution_details' => 'setShowSolutionDetails',
10857 'solution_printview' => 'setShowSolutionPrintview',
10858 'solution_feedback' => 'setShowSolutionFeedback',
10859 'solution_answers_only' => 'setShowSolutionAnswersOnly',
10860 'solution_signature' => 'setShowSolutionSignature',
10861 'solution_suggested' => 'setShowSolutionSuggested',
10862 );
10863 foreach ($setter as $key => $setter) {
10864 if (in_array($key, $options)) {
10865 $this->$setter(1);
10866 } else {
10867 $this->$setter(0);
10868 }
10869 }
10870 }
10871
10872 public function getPoolUsage()
10873 {
10874 return (boolean) $this->poolUsage;
10875 }
10876
10877 public function setPoolUsage($usage)
10878 {
10879 $this->poolUsage = (boolean) $usage;
10880 }
10881
10886 {
10887 global $DIC;
10888 $tree = $DIC['tree'];
10889 $db = $DIC['ilDB'];
10890 $pluginAdmin = $DIC['ilPluginAdmin'];
10891
10892 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
10893 $qscFactory = new ilTestQuestionSetConfigFactory($tree, $db, $pluginAdmin, $this);
10894 $questionSetConfig = $qscFactory->getQuestionSetConfig();
10895
10896 /* @var ilTestFixedQuestionSetConfig $questionSetConfig */
10897 $reindexedSequencePositionMap = $questionSetConfig->reindexQuestionOrdering();
10898
10899 $this->loadQuestions();
10900
10901 return $reindexedSequencePositionMap;
10902 }
10903
10904 public function setQuestionOrderAndObligations($orders, $obligations)
10905 {
10906 global $DIC;
10907 $ilDB = $DIC['ilDB'];
10908
10909 asort($orders);
10910
10911 $i = 0;
10912
10913 foreach ($orders as $id => $position) {
10914 $i++;
10915
10916 $obligatory = (
10917 isset($obligations[$id]) && $obligations[$id] ? 1 : 0
10918 );
10919
10920 $query = "
10921 UPDATE tst_test_question
10922 SET sequence = %s,
10923 obligatory = %s
10924 WHERE question_fi = %s
10925 ";
10926
10927 $ilDB->manipulateF(
10928 $query,
10929 array('integer', 'integer', 'integer'),
10930 array($i, $obligatory, $id)
10931 );
10932 }
10933
10934 $this->loadQuestions();
10935 }
10936
10937 public function moveQuestionAfter($question_to_move, $question_before)
10938 {
10939 global $DIC;
10940 $ilDB = $DIC['ilDB'];
10941 //var_dump(func_get_args());
10942 if ($question_before) {
10943 $query = 'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
10944 $types = array('integer');
10945 $values = array($question_before);
10946 $rset = $ilDB->queryF($query, $types, $values);
10947 }
10948
10949 if (!$question_before || ($rset && !($row = $ilDB->fetchAssoc($rset)))) {
10950 $row = array(
10951 'sequence' => 0,
10952 'test_fi' => $this->getTestId(),
10953 );
10954 }
10955
10956 $update = 'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
10957 $types = array('integer', 'integer');
10958 $values = array($row['sequence'], $row['test_fi']);
10959 $ilDB->manipulateF($update, $types, $values);
10960
10961 $update = 'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
10962 $types = array('integer', 'integer');
10963 $values = array($row['sequence'] + 1, $question_to_move);
10964 $ilDB->manipulateF($update, $types, $values);
10965
10967 }
10968
10970 {
10971 global $DIC;
10972 $ilDB = $DIC['ilDB'];
10973
10975
10976 $IN_questions = $ilDB->in('q1.question_id', array_keys($questions), false, 'integer');
10977
10978 $query = "
10979 SELECT count(q1.question_id) cnt
10980
10981 FROM qpl_questions q1
10982
10983 INNER JOIN qpl_questions q2
10984 ON q2.question_id = q1.original_id
10985
10986 WHERE $IN_questions
10987 AND q1.obj_fi = q2.obj_fi
10988 ";
10989
10990 $rset = $ilDB->query($query);
10991
10992 $row = $ilDB->fetchAssoc($rset);
10993
10994 return $row['cnt'] > 0;
10995 }
10996
11003 public static function _lookupFinishedUserTests($a_user_id)
11004 {
11005 global $DIC;
11006 $ilDB = $DIC['ilDB'];
11007
11008 $result = $ilDB->queryF(
11009 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
11010 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
11011 " WHERE user_fi=%s" .
11012 " GROUP BY test_fi",
11013 array('integer', 'integer'),
11014 array($a_user_id, 1)
11015 );
11016 $all = array();
11017 while ($row = $ilDB->fetchAssoc($result)) {
11018 $obj_id = self::_getObjectIDFromTestID($row["test_fi"]);
11019 $all[$obj_id] = (bool) $row["pass"];
11020 }
11021 return $all;
11022 }
11023 public function getQuestions()
11024 {
11025 return $this->questions;
11026 }
11027
11028 public function isOnline()
11029 {
11030 return $this->online;
11031 }
11032
11033 public function setOnline($a_online = true)
11034 {
11035 $this->online = (bool) $a_online;
11036 }
11037
11041 public function getOldOnlineStatus()
11042 {
11044 }
11045
11050 {
11051 $this->oldOnlineStatus = $oldOnlineStatus;
11052 }
11053
11054 public function setPrintBestSolutionWithResult($status)
11055 {
11056 $this->print_best_solution_with_result = (bool) $status;
11057 }
11058
11060 {
11062 }
11063
11070 {
11072 }
11073
11080 {
11081 $this->offeringQuestionHintsEnabled = (bool) $offeringQuestionHintsEnabled;
11082 }
11083
11084 public function setActivationVisibility($a_value)
11085 {
11086 $this->activation_visibility = (bool) $a_value;
11087 }
11088
11089 public function getActivationVisibility()
11090 {
11092 }
11093
11094 public function isActivationLimited()
11095 {
11096 return (bool) $this->activation_limited;
11097 }
11098
11099 public function setActivationLimited($a_value)
11100 {
11101 $this->activation_limited = (bool) $a_value;
11102 }
11103
11104 /* GET/SET for highscore feature */
11105
11111 public function setHighscoreEnabled($a_enabled)
11112 {
11113 $this->_highscore_enabled = (bool) $a_enabled;
11114 }
11115
11121 public function getHighscoreEnabled()
11122 {
11123 return (bool) $this->_highscore_enabled;
11124 }
11125
11133 public function setHighscoreAnon($a_anon)
11134 {
11135 $this->_highscore_anon = (bool) $a_anon;
11136 }
11137
11147 public function getHighscoreAnon()
11148 {
11149 return (bool) $this->_highscore_anon;
11150 }
11151
11160 public function isHighscoreAnon()
11161 {
11162 if ($this->getAnonymity() == 1) {
11163 return true;
11164 } else {
11165 return (bool) $this->getHighscoreAnon();
11166 }
11167 }
11168
11174 public function setHighscoreAchievedTS($a_achieved_ts)
11175 {
11176 $this->_highscore_achieved_ts = (bool) $a_achieved_ts;
11177 }
11178
11184 public function getHighscoreAchievedTS()
11185 {
11186 return (bool) $this->_highscore_achieved_ts;
11187 }
11188
11194 public function setHighscoreScore($a_score)
11195 {
11196 $this->_highscore_score = (bool) $a_score;
11197 }
11198
11204 public function getHighscoreScore()
11205 {
11206 return (bool) $this->_highscore_score;
11207 }
11208
11214 public function setHighscorePercentage($a_percentage)
11215 {
11216 $this->_highscore_percentage = (bool) $a_percentage;
11217 }
11218
11224 public function getHighscorePercentage()
11225 {
11226 return (bool) $this->_highscore_percentage;
11227 }
11228
11234 public function setHighscoreHints($a_hints)
11235 {
11236 $this->_highscore_hints = (bool) $a_hints;
11237 }
11238
11244 public function getHighscoreHints()
11245 {
11246 return (bool) $this->_highscore_hints;
11247 }
11248
11254 public function setHighscoreWTime($a_wtime)
11255 {
11256 $this->_highscore_wtime = (bool) $a_wtime;
11257 }
11258
11264 public function getHighscoreWTime()
11265 {
11266 return (bool) $this->_highscore_wtime;
11267 }
11268
11274 public function setHighscoreOwnTable($a_own_table)
11275 {
11276 $this->_highscore_own_table = (bool) $a_own_table;
11277 }
11278
11284 public function getHighscoreOwnTable()
11285 {
11286 return (bool) $this->_highscore_own_table;
11287 }
11288
11294 public function setHighscoreTopTable($a_top_table)
11295 {
11296 $this->_highscore_top_table = (bool) $a_top_table;
11297 }
11298
11304 public function getHighscoreTopTable()
11305 {
11306 return (bool) $this->_highscore_top_table;
11307 }
11308
11315 public function setHighscoreTopNum($a_top_num)
11316 {
11317 $this->_highscore_top_num = (int) $a_top_num;
11318 }
11319
11328 public function getHighscoreTopNum($a_retval = 10)
11329 {
11330 $retval = $a_retval;
11331 if ((int) $this->_highscore_top_num != 0) {
11332 $retval = $this->_highscore_top_num;
11333 }
11334
11335 return $retval;
11336 }
11337
11341 public function getHighscoreMode()
11342 {
11343 switch (true) {
11344 case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
11346 break;
11347
11348 case $this->getHighscoreTopTable():
11350 break;
11351
11352 case $this->getHighscoreOwnTable():
11353 default:
11355 break;
11356 }
11357 }
11358
11362 public function setHighscoreMode($mode)
11363 {
11364 switch ($mode) {
11366 $this->setHighscoreTopTable(1);
11367 $this->setHighscoreOwnTable(1);
11368 break;
11369
11371 $this->setHighscoreTopTable(1);
11372 $this->setHighscoreOwnTable(0);
11373 break;
11374
11376 default:
11377 $this->setHighscoreTopTable(0);
11378 $this->setHighscoreOwnTable(1);
11379 break;
11380 }
11381 }
11382 /* End GET/SET for highscore feature*/
11383
11384 public function setSpecificAnswerFeedback($specific_answer_feedback)
11385 {
11386 switch ($specific_answer_feedback) {
11387 case 1:
11388 $this->specific_answer_feedback = 1;
11389 break;
11390 default:
11391 $this->specific_answer_feedback = 0;
11392 break;
11393 }
11394 }
11395
11397 {
11398 switch ($this->specific_answer_feedback) {
11399 case 1:
11400 return 1;
11401 default:
11402 return 0;
11403 }
11404 }
11405
11412 {
11413 $this->obligationsEnabled = (bool) $obligationsEnabled;
11414 }
11415
11421 public function areObligationsEnabled()
11422 {
11423 return (bool) $this->obligationsEnabled;
11424 }
11425
11432 public static function isQuestionObligationPossible($questionId)
11433 {
11434 require_once('Modules/TestQuestionPool/classes/class.assQuestion.php');
11435
11436 $classConcreteQuestion = assQuestion::_getQuestionType($questionId);
11437
11438 assQuestion::_includeClass($classConcreteQuestion, 0);
11439
11440 // static binder is not at work yet (in PHP < 5.3)
11441 //$obligationPossible = $classConcreteQuestion::isObligationPossible();
11442 $obligationPossible = call_user_func(array($classConcreteQuestion, 'isObligationPossible'), $questionId);
11443
11444 return $obligationPossible;
11445 }
11446
11453 public static function isQuestionObligatory($question_id)
11454 {
11455 global $DIC;
11456 $ilDB = $DIC['ilDB'];
11457
11458 $rset = $ilDB->queryF('SELECT obligatory FROM tst_test_question WHERE question_fi = %s', array('integer'), array($question_id));
11459
11460 if ($row = $ilDB->fetchAssoc($rset)) {
11461 return (bool) $row['obligatory'];
11462 }
11463
11464 return false;
11465 }
11466
11479 public static function allObligationsAnswered($test_id, $active_id, $pass)
11480 {
11481 global $DIC;
11482 $ilDB = $DIC['ilDB'];
11483
11484 $rset = $ilDB->queryF(
11485 'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
11486 array('integer', 'integer'),
11487 array($active_id, $pass)
11488 );
11489
11490 if ($row = $ilDB->fetchAssoc($rset)) {
11491 return (bool) $row['obligations_answered'];
11492 }
11493
11495 }
11496
11505 public static function hasObligations($test_id)
11506 {
11507 global $DIC;
11508 $ilDB = $DIC['ilDB'];
11509
11510 $rset = $ilDB->queryF(
11511 'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
11512 array('integer'),
11513 array($test_id)
11514 );
11515
11516 $row = $ilDB->fetchAssoc($rset);
11517
11518 return (bool) $row['cnt'] > 0;
11519 }
11520
11521 public function setAutosave($autosave)
11522 {
11523 $this->autosave = $autosave;
11524 }
11525
11526 public function getAutosave()
11527 {
11528 return $this->autosave;
11529 }
11530
11532 {
11533 $this->autosave_ival = $autosave_ival;
11534 }
11535
11536 public function getAutosaveIval()
11537 {
11538 return $this->autosave_ival;
11539 }
11540
11546 public function isPassDeletionAllowed()
11547 {
11549 }
11550
11557 {
11558 $this->passDeletionAllowed = (bool) $passDeletionAllowed;
11559 }
11560
11561 #region Examview / PDF Examview
11566 {
11567 $this->show_examview_html = $show_examview_html;
11568 }
11569
11573 public function getShowExamviewHtml()
11574 {
11576 }
11577
11582 {
11583 $this->show_examview_pdf = $show_examview_pdf;
11584 }
11585
11589 public function getShowExamviewPdf()
11590 {
11592 }
11593
11598 {
11599 $this->enable_examview = $enable_examview;
11600 }
11601
11605 public function getEnableExamview()
11606 {
11608 }
11609
11610 #endregion
11611
11613 {
11614 $this->activation_starting_time = $starting_time;
11615 }
11616
11618 {
11619 $this->activation_ending_time = $ending_time;
11620 }
11621
11623 {
11624 return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : null;
11625 }
11626
11627 public function getActivationEndingTime()
11628 {
11629 return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : null;
11630 }
11631
11639 {
11640 global $DIC;
11641 $ilDB = $DIC['ilDB'];
11642
11643 $times = array();
11644 $result = $ilDB->queryF("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",
11645 array('integer'),
11646 array($this->getTestId())
11647 );
11648 while ($row = $ilDB->fetchAssoc($result)) {
11649 $times[$row['active_fi']] = $row['started'];
11650 }
11651 return $times;
11652 }
11653
11655 {
11656 global $DIC;
11657 $ilDB = $DIC['ilDB'];
11658
11659 $times = array();
11660 $result = $ilDB->queryF(
11661 "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",
11662 array('integer'),
11663 array($this->getTestId())
11664 );
11665 while ($row = $ilDB->fetchAssoc($result)) {
11666 $times[$row['active_fi']] = $row['additionaltime'];
11667 }
11668 return $times;
11669 }
11670
11671 public function getExtraTime($active_id)
11672 {
11673 global $DIC;
11674 $ilDB = $DIC['ilDB'];
11675
11676 $result = $ilDB->queryF(
11677 "SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
11678 array('integer'),
11679 array($active_id)
11680 );
11681 if ($result->numRows() > 0) {
11682 $row = $ilDB->fetchAssoc($result);
11683 return $row['additionaltime'];
11684 }
11685 return 0;
11686 }
11687
11688 public function addExtraTime($active_id, $minutes)
11689 {
11690 global $DIC; /* @var ILIAS\DI\Container $DIC */
11691
11692 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
11693 $participantData = new ilTestParticipantData($DIC->database(), $DIC->language());
11694
11695 $participantData->setParticipantAccessFilter(
11697 );
11698
11699 if ($active_id) {
11700 $participantData->setActiveIdsFilter(array($active_id));
11701 }
11702
11703 $participantData->load($this->getTestId());
11704
11705 foreach ($participantData->getActiveIds() as $active_id) {
11706 $result = $DIC->database()->queryF(
11707 "SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
11708 array('integer'),
11709 array($active_id)
11710 );
11711
11712 if ($result->numRows() > 0) {
11713 $DIC->database()->manipulateF(
11714 "DELETE FROM tst_addtime WHERE active_fi = %s",
11715 array('integer'),
11716 array($active_id)
11717 );
11718 }
11719
11720 $DIC->database()->manipulateF(
11721 "UPDATE tst_active SET tries = %s, submitted = %s, submittimestamp = %s WHERE active_id = %s",
11722 array('integer','integer','timestamp','integer'),
11723 array(0, 0, null, $active_id)
11724 );
11725
11726 $DIC->database()->manipulateF(
11727 "INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
11728 array('integer','integer','integer'),
11729 array($active_id, $minutes, time())
11730 );
11731
11732 require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
11734 $this->logAction(sprintf($this->lng->txtlng("assessment", "log_added_extratime", ilObjAssessmentFolder::_getLogLanguage()), $minutes, $active_id));
11735 }
11736 }
11737 }
11738
11745 {
11746 $this->enable_archiving = $enable_archiving;
11747 return $this;
11748 }
11749
11753 public function getEnableArchiving()
11754 {
11756 }
11757
11758 public function getMaxPassOfTest()
11759 {
11763 global $DIC;
11764 $ilDB = $DIC['ilDB'];
11765
11766 $query = '
11767 SELECT MAX(tst_pass_result.pass) + 1 max_res
11768 FROM tst_pass_result
11769 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
11770 WHERE test_fi = ' . $ilDB->quote($this->getTestId(), 'integer') . '
11771 ';
11772 $res = $ilDB->query($query);
11773 $data = $ilDB->fetchAssoc($res);
11774 return (int) $data['max_res'];
11775 }
11776
11782 public static function lookupExamId($active_id, $pass)
11783 {
11784 global $DIC;
11785 $ilDB = $DIC['ilDB'];
11786
11787 $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
11788 $exam_id_result = $ilDB->queryF($exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ));
11789 if ($ilDB->numRows($exam_id_result) == 1) {
11790 $exam_id_row = $ilDB->fetchAssoc($exam_id_result);
11791
11792 if ($exam_id_row['exam_id'] != null) {
11793 return $exam_id_row['exam_id'];
11794 }
11795 }
11796
11797 return null;
11798 }
11799
11806 public static function buildExamId($active_id, $pass, $test_obj_id = null)
11807 {
11808 global $DIC;
11809 $ilSetting = $DIC['ilSetting'];
11810
11811 $inst_id = $ilSetting->get('inst_id', null);
11812
11813 if ($test_obj_id === null) {
11814 $obj_id = self::_getObjectIDFromActiveID($active_id);
11815 } else {
11816 $obj_id = $test_obj_id;
11817 }
11818
11819 $examId = 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
11820
11821 return $examId;
11822 }
11823
11825 {
11826 $this->show_exam_id_in_test_pass_enabled = $show_exam_id_in_test_pass_enabled;
11827 }
11828
11830 {
11832 }
11833
11838 {
11839 $this->show_exam_id_in_test_results_enabled = $show_exam_id_in_test_results_enabled;
11840 }
11841
11846 {
11848 }
11849
11854 {
11855 $this->sign_submission = $sign_submission;
11856 }
11857
11861 public function getSignSubmission()
11862 {
11864 }
11865
11869 public function setCharSelectorAvailability($availability)
11870 {
11871 $this->char_selector_availability = (int) $availability;
11872 }
11873
11878 {
11880 }
11881
11885 public function setCharSelectorDefinition($definition = '')
11886 {
11887 $this->char_selector_definition = $definition;
11888 }
11889
11894 {
11896 }
11897
11898
11905 {
11906 $this->questionSetType = $questionSetType;
11907 }
11908
11914 public function getQuestionSetType()
11915 {
11917 }
11918
11926 public static function lookupQuestionSetType($objId)
11927 {
11928 global $DIC;
11929 $ilDB = $DIC['ilDB'];
11930
11931 $query = "SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
11932
11933 $res = $ilDB->queryF($query, array('integer'), array($objId));
11934
11935 $questionSetType = null;
11936
11937 while ($row = $ilDB->fetchAssoc($res)) {
11938 $questionSetType = $row['question_set_type'];
11939 }
11940
11941 return $questionSetType;
11942 }
11943
11949 public function isFixedTest()
11950 {
11952 }
11953
11959 public function isRandomTest()
11960 {
11962 }
11963
11969 public function isDynamicTest()
11970 {
11972 }
11973
11981 public static function _lookupRandomTest($a_obj_id)
11982 {
11984 }
11985
11987 {
11988 switch ($questionSetType) {
11990 return $lng->txt('tst_question_set_type_fixed');
11991
11993 return $lng->txt('tst_question_set_type_random');
11994
11996 return $lng->txt('tst_question_set_type_dynamic');
11997 }
11998
11999 throw new ilTestException('invalid question set type value given: ' . $questionSetType);
12000 }
12001
12002 public function participantDataExist()
12003 {
12004 if ($this->participantDataExist === null) {
12005 $this->participantDataExist = (bool) $this->evalTotalPersons();
12006 }
12007
12009 }
12010
12011 public function recalculateScores($preserve_manscoring = false)
12012 {
12013 require_once 'class.ilTestScoring.php';
12014 $scoring = new ilTestScoring($this);
12015 $scoring->setPreserveManualScores($preserve_manscoring);
12016 $scoring->recalculateSolutions();
12017 }
12018
12019 public static function getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
12020 {
12021 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
12022
12023 $questionChangeListeners = array(
12025 );
12026
12027 return $questionChangeListeners;
12028 }
12029
12030 public static function getTestObjIdsWithActiveForUserId($userId)
12031 {
12032 global $DIC;
12033 $ilDB = $DIC['ilDB'];
12034
12035 $query = "
12036 SELECT obj_fi
12037 FROM tst_active
12038 INNER JOIN tst_tests
12039 ON test_id = test_fi
12040 WHERE user_fi = %s
12041 ";
12042
12043 $res = $ilDB->queryF($query, array('integer'), array($userId));
12044
12045 $objIds = array();
12046
12047 while ($row = $ilDB->fetchAssoc($res)) {
12048 $objIds[] = (int) $row['obj_fi'];
12049 }
12050
12051 return $objIds;
12052 }
12053
12055 {
12056 $this->skillServiceEnabled = $skillServiceEnabled;
12057 }
12058
12059 public function isSkillServiceEnabled()
12060 {
12062 }
12063
12065 {
12066 $this->resultFilterTaxIds = $resultFilterTaxIds;
12067 }
12068
12069 public function getResultFilterTaxIds()
12070 {
12072 }
12073
12075 {
12076 if (!$this->isSkillServiceEnabled()) {
12077 return false;
12078 }
12079
12080 if (!self::isSkillManagementGloballyActivated()) {
12081 return false;
12082 }
12083
12084 return true;
12085 }
12086
12088
12089 public static function isSkillManagementGloballyActivated()
12090 {
12091 if (self::$isSkillManagementGloballyActivated === null) {
12092 include_once 'Services/Skill/classes/class.ilSkillManagementSettings.php';
12093 $skmgSet = new ilSkillManagementSettings();
12094
12095 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
12096 }
12097
12099 }
12100
12102 {
12103 $this->showGradingStatusEnabled = $showGradingStatusEnabled;
12104 }
12105
12107 {
12109 }
12110
12112 {
12113 $this->showGradingMarkEnabled = $showGradingMarkEnabled;
12114 }
12115
12116
12118 {
12120 }
12121
12123 {
12124 $this->followupQuestionAnswerFixationEnabled = $followupQuestionAnswerFixationEnabled;
12125 }
12126
12128 {
12130 }
12131
12133 {
12134 $this->instantFeedbackAnswerFixationEnabled = $instantFeedbackAnswerFixationEnabled;
12135 }
12136
12138 {
12140 }
12141
12146 {
12148 }
12149
12154 {
12155 $this->forceInstantFeedbackEnabled = $forceInstantFeedbackEnabled;
12156 }
12157
12158 public static function ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run = false)
12159 {
12160 global $DIC;
12161 $ilDB = $DIC['ilDB'];
12162 $lng = $DIC['lng'];
12163 $ilPluginAdmin = $DIC['ilPluginAdmin'];
12164
12165 /* @var ilObjTest $testOBJ */
12166
12167 $testOBJ = ilObjectFactory::getInstanceByRefId($testObjId, false);
12168
12169 $activeId = $testOBJ->getActiveIdOfUser($userId);
12170
12171 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12172 $testSessionFactory = new ilTestSessionFactory($testOBJ);
12173
12174 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12175 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12176
12177 $testSession = $testSessionFactory->getSession($activeId);
12178 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12179 $testSequence->loadFromDb();
12180
12181 // begin-patch lok changed smeyer
12182 if ($a_force_new_run) {
12183 if ($testSequence->hasSequence()) {
12184 $testSession->increasePass();
12185 }
12186 $testSession->setLastSequence(0);
12187 $testSession->saveToDb();
12188 }
12189 // end-patch lok
12190 }
12191
12192 public static function isParticipantsLastPassActive($testRefId, $userId)
12193 {
12194 global $DIC;
12195 $ilDB = $DIC['ilDB'];
12196 $lng = $DIC['lng'];
12197 $ilPluginAdmin = $DIC['ilPluginAdmin'];
12198
12199 /* @var ilObjTest $testOBJ */
12200
12201 $testOBJ = ilObjectFactory::getInstanceByRefId($testRefId, false);
12202
12203
12204 $activeId = $testOBJ->getActiveIdOfUser($userId);
12205
12206 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12207 $testSessionFactory = new ilTestSessionFactory($testOBJ);
12208 // Added temporarily bugfix smeyer
12209 $testSessionFactory->reset();
12210
12211 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12212 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12213
12214 $testSession = $testSessionFactory->getSession($activeId);
12215 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12216 $testSequence->loadFromDb();
12217
12218 return $testSequence->hasSequence();
12219 }
12220
12224 public function isTestFinalBroken()
12225 {
12227 }
12228
12233 {
12234 $this->testFinalBroken = $testFinalBroken;
12235 }
12236
12237 public function adjustTestSequence()
12238 {
12242 global $DIC;
12243 $ilDB = $DIC['ilDB'];
12244
12245 $query = "
12246 SELECT COUNT(test_question_id) cnt
12247 FROM tst_test_question
12248 WHERE test_fi = %s
12249 ORDER BY sequence
12250 ";
12251
12252 $questRes = $ilDB->queryF($query, array('integer'), array($this->getTestId()));
12253
12254 $row = $ilDB->fetchAssoc($questRes);
12255 $questCount = $row['cnt'];
12256
12257 if ($this->getShuffleQuestions()) {
12258 $query = "
12259 SELECT tseq.*
12260 FROM tst_active tac
12261 INNER JOIN tst_sequence tseq
12262 ON tseq.active_fi = tac.active_id
12263 WHERE tac.test_fi = %s
12264 ";
12265
12266 $partRes = $ilDB->queryF(
12267 $query,
12268 array('integer'),
12269 array($this->getTestId())
12270 );
12271
12272 while ($row = $ilDB->fetchAssoc($partRes)) {
12273 $sequence = @unserialize($row['sequence']);
12274
12275 if (!$sequence) {
12276 $sequence = array();
12277 }
12278
12279 $sequence = array_filter($sequence, function ($value) use ($questCount) {
12280 return $value <= $questCount;
12281 });
12282
12283 $num_seq = count($sequence);
12284 if ($questCount > $num_seq) {
12285 $diff = $questCount - $num_seq;
12286 for ($i = 1; $i <= $diff; $i++) {
12287 $sequence[$num_seq + $i - 1] = $num_seq + $i;
12288 }
12289 }
12290
12291 $new_sequence = serialize($sequence);
12292
12293 $ilDB->update('tst_sequence', array(
12294 'sequence' => array('clob', $new_sequence)
12295 ), array(
12296 'active_fi' => array('integer', $row['active_fi']),
12297 'pass' => array('integer', $row['pass'])
12298 ));
12299 }
12300 } else {
12301 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : array());
12302
12303 $query = "
12304 SELECT tseq.*
12305 FROM tst_active tac
12306 INNER JOIN tst_sequence tseq
12307 ON tseq.active_fi = tac.active_id
12308 WHERE tac.test_fi = %s
12309 ";
12310
12311 $part_rest = $ilDB->queryF(
12312 $query,
12313 array('integer'),
12314 array($this->getTestId())
12315 );
12316
12317 while ($row = $ilDB->fetchAssoc($part_rest)) {
12318 $ilDB->update('tst_sequence', array(
12319 'sequence' => array('clob', $new_sequence)
12320 ), array(
12321 'active_fi' => array('integer', $row['active_fi']),
12322 'pass' => array('integer', $row['pass'])
12323 ));
12324 }
12325 }
12326 }
12327
12329 {
12330 return ilHtmlPurifierFactory::_getInstanceByType('qpl_usersolution');
12331 }
12332}
$result
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
Definition: PEAR.php:64
$total
Definition: Utf8Test.php:87
$test
Definition: Utf8Test.php:84
$filename
Definition: buildRTE.php:89
$_POST["username"]
$_SESSION["AccountId"]
A class defining mark schemas for assessment test objects.
An exception for terminatinating execution or to throw for unit testing.
const IL_COMP_MODULE
const IL_CAL_UNIX
const IL_CAL_DATETIME
const NEWS_USERS
const NEWS_NOTICE
static getFeedbackClassNameByQuestionType($questionType)
static _getOriginalId($question_id)
Returns the original id of a question.
static sumTimesInISO8601FormatH_i_s_Extended($time1, $time2)
static _getSolutionMaxPass($question_id, $active_id)
Returns the maximum pass a users question solution.
static _updateTestResultCache($active_id, ilAssQuestionProcessLocker $processLocker=null)
@TODO Move this to a proper place.
static _getSuggestedSolutionOutput($question_id)
Returns the output of the suggested solution.
static getGuiClassNameByQuestionType($questionType)
static _isWorkedThrough($active_id, $question_id, $pass=null)
Returns true if the question was worked through in the given pass Worked through means that the user ...
static _includeClass($question_type, $gui=0)
Include the php class file for a given question type.
static _getQuestionTitle($question_id)
Returns the question title of a question with a given id.
static _getQuestionType($question_id)
Returns the question type of a question with a given id.
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
static deleteRequestsByActiveIds($activeIds)
Deletes all hint requests relating to a testactive included in given active ids.
Question page object.
static completeMissingPluginName($questionTypeData)
static formatDate(ilDateTime $date, $a_skip_day=false, $a_include_wd=false, $include_seconds=false)
Format a date @access public.
@classDescription Date and time handling
TableGUI class for evaluation of all users.
Base class for ILIAS Exception handling.
Class ilFileDataMail.
static recursive_dirscan($dir, &$arr)
Recursively scans a given directory and writes path and filename into referenced array.
static _getInstanceByType(string $type)
Factory method for creating purifier instances.
language handling
static deleteNewsOfContext( $a_context_obj_id, $a_context_obj_type, $a_context_sub_obj_id=0, $a_context_sub_obj_type="")
Delete all news of a context.
static getFirstNewsIdForContext( $a_context_obj_id, $a_context_obj_type, $a_context_sub_obj_id="", $a_context_sub_obj_type="")
Get first new id of news set related to a certain context.
static _addLog($user_id, $object_id, $logtext, $question_id="", $original_id="", $test_only=false, $test_ref_id=null)
Add an assessment log entry.
static _getLogLanguage()
retrieve the log language for assessment logging
static _getManualScoring()
Retrieve the manual scoring settings.
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
Class ilObjFile.
Class ilObjGroup.
Class ilObjMediaObject.
static _saveUsage($a_mob_id, $a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
Save usage of mob within another container (e.g.
static _getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
static _removeUsage($a_mob_id, $a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
Remove usage of mob in another container.
static _exists($a_id, $a_reference=false, $a_type=null)
checks wether a lm content object with specified id exists or not
static _saveTempFileAsMediaObject($name, $tmp_name, $upload=true)
Create new media object and update page in db and return new media object.
static _getAvailableQuestionpools($use_object_id=false, $equal_points=false, $could_be_offline=false, $showPath=false, $with_questioncount=false, $permission="read", $usr_id="")
Returns the available question pools for the active user.
static _getParticipantData($active_id)
Retrieves a participant name from active id.
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.
static getPoolQuestionChangeListener(ilDBInterface $db, $poolObjId)
Class ilObjTestGUI.
static _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
{Returns the ECTS grade for a number of reached points.string The ECTS grade short description}
setHighscorePercentage($a_percentage)
Sets if the percentages of the scores pass should be shown.
getResetProcessingTime()
Returns wheather the processing time should be reset or not.
_buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
Builds a user name for the output depending on test type and existence of the user.
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
setPrintBestSolutionWithResult($status)
setAnswerFeedback($answer_feedback=0)
Sets the generic feedback for the test @deprecate Use setGenericAnswerFeedback instead.
__construct($a_id=0, $a_call_by_reference=true)
Constructor.
getPassed($active_id)
setIntroduction($introduction="")
Sets the introduction text of the ilObjTest object.
exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
export page objects to xml (see ilias_co.dtd)
setECTSFX($a_ects_fx)
{}
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
getProcessingTimeAsMinutes()
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
getEstimatedWorkingTime()
Returns the estimated working time for the test calculated from the working time of the contained que...
setShowInfo($a_info=1)
Set whether the complete information page is shown or the required data only.
const QUESTION_SET_TYPE_DYNAMIC
type setting value for dynamic question set (continues testing mode)
getTestId()
Gets the database id of the additional test data.
getECTSOutput()
{int|bool}
& createQuestionGUI($question_type, $question_id=-1)
Creates a question GUI instance of a given question type.
$followupQuestionAnswerFixationEnabled
endingTimeReached()
Returns true if the ending time of a test is reached An ending time is not available for self assessm...
setClientIP($user_id, $client_ip)
setAllowedUsersTimeGap($a_allowed_users_time_gap)
getQuestionSetType()
getter for question set type
insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old)
Inserts a manual feedback into the DB.
setTestId($a_id)
Sets the test ID.
getShowKioskModeParticipant()
Returns the status of the kiosk mode participant.
setKiosk($kiosk=0)
Sets the kiosk mode for the test.
getQuestionTitle($title, $nr=null)
Returns the title of a test question and checks if the title output is allowed.
canShowEctsGrades()
{boolean}
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
getAnsweredQuestionCount($active_id, $pass=null)
Retrieves the number of answered questions for a given user in a given test.
getShowKioskModeTitle()
Returns the status of the kiosk mode title.
hasRandomQuestionsForPass($active_id, $pass)
Checkes wheather a random test has already created questions for a given pass or not.
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
getCountSystem()
Gets the count system for the calculation of points.
isShowExamIdInTestPassEnabled()
setPostponingEnabled($postponingEnabled)
setInstantFeedbackSolution($instant_feedback=0)
Sets the instant feedback for the solution.
canShowSolutionPrintview($user_id=null)
Calculates if a user may see the solution printview of his/her test results.
getEnableProcessingTime()
Returns the state of the processing time (enabled/disabled)
setShowKioskModeParticipant($a_participant=false)
Set to true, if the participant's name should be shown in kiosk mode.
getListOfQuestionsStart()
Returns if the list of questions should be presented as the first page of the test.
& getExistingQuestions($pass=null)
Get the id's of the questions which are already part of the test.
static _getTestIDFromObjectID($object_id)
Returns the ILIAS test id for a given object id.
loadFromDb()
Loads a ilObjTest object from a database.
pcArrayShuffle($array)
Shuffles the values of a given array.
_getTitleOutput($active_id)
Returns the value of the title_output status.
isAnyInstantFeedbackOptionEnabled()
isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
Returns true, if a test is complete for use and can be set online.
canShowTestResults(ilTestSession $testSession)
getInstantFeedbackSolution()
Returns 1 if the correct solution will be shown after answering a question.
setFinalStatement($a_statement="")
Sets the final statement text of the ilObjTest object.
setFixedParticipants($a_value=1)
Sets the fixed participants status.
getStartingTimeOfUser($active_id, $pass=null)
Returns the unix timestamp of the time a user started a test.
_getLastAccess($active_id)
getStartTestLabel($active_id)
Returns the "Start the Test" label for the Info page.
static _getTestDefaults($test_defaults_id)
setOnline($a_online=true)
& getParticipants()
Returns all persons who started the test.
setProcessingTime($processing_time="00:00:00")
Sets the processing time for the test.
setHighscoreAnon($a_anon)
Sets if the highscores should be anonymized.
getDetailedTestResults($participants)
returns all test results for all participants
setAllowedUsers($a_allowed_users)
isNrOfTriesReached($tries)
returns if number of tries are reached
reindexFixedQuestionOrdering()
static getTestObjIdsWithActiveForUserId($userId)
setKioskMode($a_kiosk=false)
Sets the kiosk mode for the test.
setTemplate($template_id)
setShowExamviewPdf($show_examview_pdf)
setShowSolutionSignature($a_signature=false)
Set to TRUE, if the signature field should be shown in the solution.
setShowExamIdInTestPassEnabled($show_exam_id_in_test_pass_enabled)
inviteUser($user_id, $client_ip="")
Invites a user to a test.
setScoreCutting($a_score_cutting=SCORE_CUT_QUESTION)
Sets the type of score cutting.
static _getCountSystem($active_id)
Gets the count system for the calculation of points.
evalTotalStartedAverageTime($activeIdsFilter=null)
Returns the average processing time for all started tests.
setFollowupQuestionAnswerFixationEnabled($followupQuestionAnswerFixationEnabled)
getQuestionCount()
Returns the number of questions in the test.
getQuestiontext($question_id)
Returns the question text for a given question.
setResultsPresentationOptionsByArray($options)
QTIMaterialToString($a_material)
Reads an QTI material tag an creates a text string.
& getTestDefaults($test_defaults_id)
Returns the test defaults for a given id.
const QUESTION_SET_TYPE_RANDOM
type setting value for random question set
saveAuthorToMetadata($a_author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
setOldOnlineStatus($oldOnlineStatus)
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
setPassDeletionAllowed($passDeletionAllowed)
setter for the test setting passDeletionAllowed
setHighscoreScore($a_score)
Sets if the actual score should be displayed.
const HIGHSCORE_SHOW_ALL_TABLES
sendSimpleNotification($active_id)
getXMLZip()
Get zipped xml file for test.
getShowSolutionListComparison()
static lookupExamId($active_id, $pass)
createExportDirectory()
creates data directory for export files (data_dir/tst_data/tst_<id>/export, depending on data directo...
setShowGradingStatusEnabled($showGradingStatusEnabled)
static _getActiveIdOfUser($user_id="", $test_id="")
Gets the active id of the tst_active table for the active user.
getExtraTime($active_id)
isPreviousSolutionReuseEnabled($activeId)
getFixedParticipants()
Returns the fixed participants status.
isBestSolutionPrintedWithResult()
_lookupRandomTestFromActiveId($active_id)
Returns the random status of a test with a given object id.
setPassword($a_password=null)
Sets the password for test access.
setShowSolutionDetails($a_details=1)
Sets if the the solution details should be presented to the user or not.
& createTestSequence($active_id, $pass, $shuffle)
$show_exam_id_in_test_results_enabled
getFinalStatement()
Gets the final statement.
getProcessingTimeAsArray()
Returns the processing time for the test.
questionMoveDown($question_id)
Moves a question down in order.
setShowFinalStatement($show=0)
Sets whether the final statement should be shown or not.
logAction($logtext="", $question_id="")
Logs an action into the Test&Assessment log.
createMetaData()
Create meta data entry.
getEvaluationAdditionalFields()
Gets additional user fields that should be shown in the user evaluation.
setEndingTimeEnabled($ending_time_enabled)
loadQuestions($active_id="", $pass=null)
Load the test question id's from the database.
& getCompleteEvaluationData($withStatistics=true, $filterby="", $filtertext="")
setShowPassDetails($a_details=1)
Sets if the pass details should be shown when a test is not finished.
insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly=false)
Insert a question in the list of questions.
buildName($user_id, $firstname, $lastname, $title)
Builds a user name for the output depending on test type and existence of the user.
setRedirectionUrl($redirection_url=null)
hasQuestionsWithoutQuestionpool()
$print_best_solution_with_result
setCountSystem($a_count_system=COUNT_PARTIAL_SOLUTIONS)
Sets the count system for the calculation of points.
buildIso8601PeriodFromUnixtimeForExportCompatibility($unix_timestamp)
$instantFeedbackAnswerFixationEnabled
static _getUsePreviousAnswers($active_id, $user_active_user_setting=false)
Returns if the previous results should be hidden for a learner.
removeQuestionFromSequences($questionId, $activeIds, ilTestReindexedSequencePositionMap $reindexedSequencePositionMap)
getImagePath()
Returns the image path for web accessable images of a test The image path is under the CLIENT_WEB_DIR...
getShowSolutionSignature()
Returns if the signature field should be shown in the test results.
getHighscoreAnon()
Gets if the highscores should be anonymized per setting.
exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export media objects to xml (see ilias_co.dtd)
getPassScoring()
Gets the pass scoring type.
setInstantFeedbackAnswerFixationEnabled($instantFeedbackAnswerFixationEnabled)
setHighscoreHints($a_hints)
Sets if the number of requested hints should be shown.
getPassword()
Returns the password for test access.
setPasswordEnabled($passwordEnabled)
setPassScoring($a_pass_scoring=SCORE_LAST_PASS)
Sets the pass scoring.
isHighscoreAnon()
Gets if the highscores should be displayed anonymized.
setOfferingQuestionHintsEnabled($offeringQuestionHintsEnabled)
sets offering question hints enabled/disabled
getFixedQuestionSetTotalWorkingTime()
getShowSolutionAnswersOnly()
Returns if the full solution (including ILIAS content) should be presented to the solution or not.
setShowSolutionPrintview($a_printview=1)
Sets if the the solution printview should be presented to the user or not.
& evalTotalPersonsArray($name_sort_order="asc")
Returns all persons who started the test.
& evalStatistical($active_id)
Returns the statistical evaluation of the test for a specified user.
isExecutable($testSession, $user_id, $allowPassIncrease=false)
Checks if the test is executable by the given user.
const SCORE_REPORTING_IMMIDIATLY
& getTestParticipants()
Returns a list of all participants in a test.
getStartingTime()
Returns the starting time of the test.
canEditEctsGrades()
{boolean}
startingTimeReached()
Returns true if the starting time of a test is reached A starting time is not available for self asse...
setAutosave($autosave)
saveManualFeedback($active_id, $question_id, $pass, $feedback, $finalized=false, $is_single_feedback=false)
Saves the manual feedback for a question in a test.
setListOfQuestions($a_value=true)
Sets if the the list of questions should be presented to the user or not.
& getTotalPointsPassedArray()
Returns an array with the total points of all users who passed the test This array could be used for ...
getShowPassDetails()
Returns if the pass details should be shown when a test is not finished.
getQuestionSetTypeTranslation(ilLanguage $lng, $questionSetType)
& evalResultsOverview()
Creates an associated array with the results of all participants of a test.
getResultsPresentation()
Returns the combined results presentation value.
$show_exam_id_in_test_pass_enabled
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
Checks if the test is complete and saves the status in the database.
getKioskMode()
Returns the kiosk mode.
getSequenceSettings()
SEQUENCE SETTING = POSTPONING ENABLED !!
static allObligationsAnswered($test_id, $active_id, $pass)
checks wether all questions marked as obligatory were answered within the test pass with given testId...
getShowSolutionFeedback()
Returns if the feedback should be presented to the solution or not.
static _getPassScoring($active_id)
Gets the pass scoring type.
setHighscoreTopNum($a_top_num)
Sets the number of entries which are to be shown in the top-rankings table.
getTimeExtensionsOfParticipants()
static getSingleManualFeedback($active_id, $question_id, $pass)
Retrieves the manual feedback for a question in a test.
static _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
const QUESTION_SET_TYPE_FIXED
type setting value for fixed question set
setHighscoreEnabled($a_enabled)
Sets if the highscore feature should be enabled.
duplicateQuestionForTest($question_id)
Takes a question and creates a copy of the question for use in the test.
setRedirectionMode($redirection_mode=0)
hasSingleChoiceQuestions()
Returns TRUE if the test contains single choice results.
setMailNotification($a_notification)
Set mail notification settings.
isActiveTestSubmitted($user_id=null)
returns if the active for user_id has been submitted
setQuestionSetType($questionSetType)
setter for question set type
setReportingDate($reporting_date)
Sets the reporting date of the ilObjTest object.
static lookupQuestionSetType($objId)
lookup-er for question set type
moveQuestionAfterOLD($previous_question_id, $new_question_id)
setCharSelectorDefinition($definition='')
getKiosk()
Returns the kiosk mode.
getResultsForActiveId($active_id)
getShowSolutionDetails()
Returns if the solution details should be presented to the user or not.
setAuthor($author="")
Sets the authors name of the ilObjTest object.
setQuestionOrderAndObligations($orders, $obligations)
isTestQuestion($questionId)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
getAuthor()
Gets the authors name of the ilObjTest object.
getAnswerFeedbackPoints()
Returns 1 if answer specific feedback as reached points is activated.
randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id=0, $qpls="", $pass=null)
Returns a random selection of questions.
setIntroductionEnabled($introductionEnabled)
getProcessingTimeInSeconds($active_id="")
Returns the processing time for the test in seconds.
getFixedQuestionSetTotalPoints()
static lookupLastTestPassAccess($activeId, $passIndex)
inviteGroup($group_id)
Invites all users of a group to a test.
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test.
read()
read object data from db into object
getHighscorePercentage()
Gets if the percentage column should be shown.
const SCORE_REPORTING_FINISHED
addDefaults($a_name)
Adds the defaults of this test to the test defaults.
getCustomStyles()
Return the available custom styles.
setCertificateVisibility($a_value)
Sets the visibility settings of the certificate.
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
setListOfQuestionsEnd($a_value=true)
Sets if the the list of questions as the end page of the test.
getTestParticipantsForManualScoring($filter=null)
static _getMCScoring($active_id)
Gets the scoring type for multiple choice questions.
getHtmlQuestionContentPurifier()
setResetProcessingTime($reset=0)
Sets wheather the processing time should be reset or not.
const SCORE_REPORTING_AFTER_PASSED
moveQuestions($move_questions, $target_index, $insert_mode)
Move questions to another position.
static _getObjectIDFromTestID($test_id)
Returns the ILIAS test object id for a given test id.
setListOfQuestionsSettings($a_value=0)
Sets the settings for the list of questions options in the test properties This could contain one of ...
isSkillServiceToBeConsidered()
sendAdvancedNotification($active_id)
modifyExportIdentifier($a_tag, $a_param, $a_value)
Returns the installation id for a given identifier.
updateWorkingTime($times_id)
Update the working time of a test when a question is answered.
setActivationStartingTime($starting_time=null)
static isSkillManagementGloballyActivated()
getHighscoreHints()
Gets, if the column with the number of requested hints should be shown.
buildStatisticsAccessFilteredParticipantList()
getMCScoring()
Gets the scoring type for multiple choice questions.
getGenericAnswerFeedback()
Returns 1 if generic answer feedback is to be shown.
setObligationsEnabled($obligationsEnabled=true)
sets obligations enabled/disabled
setSkillServiceEnabled($skillServiceEnabled)
fromXML(ilQTIAssessment $assessment)
Receives parameters from a QTI parser and creates a valid ILIAS test object.
setHighscoreTopTable($a_top_table)
Sets if the top-rankings table should be shown.
static _setImportDirectory($a_import_dir=null)
set import directory
static _getMaxPass($active_id)
Retrieves the maximum pass of a given user for a given test in which the user answered at least one q...
isRandomTest()
Returns the fact wether this test is a random questions test or not.
getQuestionType($question_id)
Returns the question type of a question with a given id.
getShowSolutionPrintview()
Returns if the solution printview should be presented to the user or not.
exportXMLMetaData(&$a_xml_writer)
export content objects meta data to xml (see ilias_co.dtd)
static _getImportDirectory()
Get the import directory location of the test.
getShowInfo()
Gets whether the complete information page is shown or the required data only.
setActivationVisibility($a_value)
setQuestionSetSolved($value, $question_id, $user_id)
sets question solved state to value for given user_id
isFixedTest()
Returns the fact wether this test is a fixed question set test or not.
getMarkSchema()
{ASS_MarkSchema}
& _getCompleteWorkingTimeOfParticipants($test_id)
Returns the complete working time in seconds for all test participants.
deleteTest()
Deletes the test and all related objects, files and database entries.
setHighscoreMode($mode)
deleteDefaults($test_default_id)
Deletes the defaults for a test.
getListOfQuestionsEnd()
Returns if the list of questions should be presented as the last page of the test.
getHighscoreEnabled()
Gets the setting which determines if the highscore feature is enabled.
getReportingDate()
Gets the reporting date of the ilObjTest object.
setForceJS($a_js=1)
Set whether JavaScript should be forced for tests.
isTestFinished($active_id)
returns if the active for user_id has been submitted
static _getBestPass($active_id)
Retrieves the best pass of a given user for a given test.
static _lookupRandomTest($a_obj_id)
Returns the fact wether the test with passed obj id is a random questions test or not.
const HIGHSCORE_SHOW_OWN_TABLE
setShowSolutionListComparison($a_comparison=false)
Set to TRUE, if the list of answers should be shown prior to finish the test.
getQuestionDataset($question_id)
Returns the dataset for a given question id.
& getTestResult($active_id, $pass=null, $ordered_sequence=false, $considerHiddenQuestions=true, $considerOptionalQuestions=true)
Calculates the results of a test for a given user and returns an array with all test results.
getTitleOutput()
Returns the value of the title_output status.
getAggregatedResultsData()
Returns the aggregated test results.
isDynamicTest()
Returns the fact wether this test is a dynamic question set test or not.
setShowExamIdInTestResultsEnabled($show_exam_id_in_test_results_enabled)
checkQuestionParent($questionId)
setInstantFeedbackOptionsByArray($options)
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
setActivationEndingTime($ending_time=null)
static getCompleteManualFeedback(int $question_id)
Retrieves the manual feedback for a question in a test.
& getQuestionTitlesAndIndexes()
Returns the titles of the test questions in question sequence.
getAllTestResults($participants, $prepareForCSV=true)
returns all test results for all participants
getListOfQuestions()
Returns if the list of questions should be presented to the user or not.
saveToDb($properties_only=false)
Saves a ilObjTest object to a database.
isMaxProcessingTimeReached($starting_time, $active_id)
Returns whether the maximum processing time for a test is reached or not.
isHTML($a_text)
Checks if a given string contains HTML or not.
moveQuestionAfter($question_to_move, $question_before)
logManualFeedback($active_id, $question_id, $feedback)
Creates a log for the manual feedback.
saveQuestionsToDb()
Saves the test questions to the database.
setShuffleQuestions($a_shuffle)
Sets the status of the shuffle_questions variable.
getUsePreviousAnswers()
Returns if the previous answers should be shown for a learner.
& getWorkedQuestions($active_id, $pass=null)
Gets the id's of all questions a user already worked through.
setForceInstantFeedbackEnabled($forceInstantFeedbackEnabled)
getAvailableQuestions($arrFilter, $completeonly=0)
Calculates the available questions for a test.
getListOfQuestionsSettings()
Returns the settings for the list of questions options in the test properties This could contain one ...
removeTestResultsByActiveIds($activeIds)
startWorkingTime($active_id, $pass)
Write the initial entry for the tests working time to the database.
isFollowupQuestionAnswerFixationEnabled()
getHighscoreTopNum($a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
setBlockPassesAfterPassedEnabled($blockPassesAfterPassedEnabled)
setSpecificAnswerFeedback($specific_answer_feedback)
& processCSVRow($row, $quoteAll=false, $separator=";")
Processes an array as a CSV row and converts the array values to correct CSV values.
setMailNotificationType($a_type)
setTitleOutput($title_output=0)
Sets the status of the title output.
isOfferingQuestionHintsEnabled()
returns the fact wether offering hints is enabled or not
& getGroupData($ids)
getCompleteWorkingTime($user_id)
Returns the complete working time in seconds a user worked on the test.
static buildExamId($active_id, $pass, $test_obj_id=null)
& getQuestionsOfTest($active_id)
Retrieves all the assigned questions for all test passes of a test participant.
setPassWaiting($pass_waiting)
removeQuestions($removeQuestionIds)
getForceJS()
Gets whether JavaScript should be forced for tests.
removeTestResults(ilTestParticipantData $participantData)
applyDefaults($test_defaults)
Applies given test defaults to this test.
disinviteUser($user_id)
Disinvites a user from a test.
setAnswerFeedbackPoints($answer_feedback_points=0)
Sets the answer specific feedback of reached points for the test.
getExportDirectory()
Get the location of the export directory for the test.
getInstantFeedbackOptionsAsArray()
setStartingTimeEnabled($starting_time_enabled)
setECTSGrades(array $a_ects_grades)
{}
static lookupQuestionSetTypeByActiveId($active_id)
returns the question set type of test relating to passed active id
& getQuestionsOfPass($active_id, $pass)
Retrieves all the assigned questions for a test participant in a given test pass.
deliverPDFfromHTML($content, $title=null)
Delivers a PDF file from XHTML.
getImagePathWeb()
Returns the web image path for web accessable images of a test The image path is under the web access...
static _getWorkingTimeOfParticipantForPass($active_id, $pass)
Returns the complete working time in seconds for a test participant.
static isQuestionObligationPossible($questionId)
checks wether the obligation for question with given id is possible or not
setActivationLimited($a_value)
_isComplete($obj_id)
Returns true, if a test is complete for use.
isShowExamIdInTestResultsEnabled()
setPoolUsage($usage)
areObligationsEnabled()
returns the fact wether obligations are enabled or not
const DEFAULT_PROCESSING_TIME_MINUTES
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
create()
create test object
setShowSolutionSuggested($a_solution=false)
Set to TRUE, if the suggested solution should be shown in the solution.
getEndingTime()
Returns the ending time of the test.
static _getAvailableTests($use_object_id=false)
Returns the available tests for the active user.
setShowKioskModeTitle($a_title=false)
Set to true, if the full test title should be shown in kiosk mode.
setHighscoreOwnTable($a_own_table)
Sets if the table with the own ranking should be shown.
saveCertificateVisibility($a_value)
Saves the visibility settings of the certificate.
setShowGradingMarkEnabled($showGradingMarkEnabled)
getCompleteWorkingTimeOfParticipant($active_id)
Returns the complete working time in seconds for a test participant.
setStartingTime($starting_time=null)
Sets the starting time in database timestamp format for the test.
evalTotalPersons()
Returns the number of persons who started the test.
setEnableExamview($enable_examview)
static $isSkillManagementGloballyActivated
getScoreReporting()
Gets the score reporting of the ilObjTest object.
getMailNotification()
Get mail notification settings.
setSignSubmission($sign_submission)
setEnableArchiving($enable_archiving)
& _evalResultsOverview($test_id)
Creates an associated array with the results of all participants of a test.
setResultFilterTaxIds($resultFilterTaxIds)
$blockPassesAfterPassedEnabled
isInstantFeedbackAnswerFixationEnabled()
& getQuestionTitles()
Returns the titles of the test questions in question sequence.
getAllRTEContent()
Returns the content of all RTE enabled text areas in the test.
_getVisitTimeOfParticipant($test_id, $active_id)
Returns the first and last visit of a participant.
getExportSettingsSingleChoiceShort()
setShowCancel($a_value=1)
Sets the cancel test button status.
getECTSGrades()
{array}
getMarkSchemaForeignId()
{int}
addQTIMaterial(&$a_xml_writer, $a_material)
Creates a QTI material tag from a plain text or xhtml text.
& getAllQuestions($pass=null)
Returns all questions of a test in test order.
static _getUserIdFromActiveId($active_id)
isPluginActive($a_pname)
Checks wheather or not a question plugin with a given name is active.
& evalTotalParticipantsArray($name_sort_order="asc")
Returns all participants who started the test.
setShowSolutionAnswersOnly($a_full=true)
Set to true, if the full solution (including the ILIAS content pages) should be shown in the solution...
setAutosaveIval($autosave_ival)
getAnonymity()
Returns the anonymity status of the test.
deliverPDFfromFO($fo, $title=null)
Delivers a PDF file from a XSL-FO string.
static hasObligations($test_id)
returns the fact wether the test with given test id contains questions markes as obligatory or not
setTestFinalBroken($testFinalBroken)
setResultsPresentation($a_results_presentation=3)
Sets the combined results presentation value.
removeQuestion($question_id)
Removes a question from the test object.
setLimitUsersEnabled($limitUsersEnabled)
toXML()
Returns a QTI xml representation of the test.
& getRoleData($ids)
static lookupPassResultsUpdateTimestamp($active_id, $pass)
hasAnyTestResult(ilTestSession $testSession)
isSingleChoiceTest()
Returns TRUE if the test contains single choice results only.
& evalResultsOverviewOfParticipant($active_id)
Creates an associated array with the results for a given participant of a test.
getShowCancel()
Returns wheather the cancel test button is shown or not.
getCertificateVisibility()
Returns the visibility settings of the certificate.
setHighscoreWTime($a_wtime)
Sets if the workingtime of the scores should be shown.
setNrOfTries($nr_of_tries=0)
Sets the nr of tries for the test.
getTestStyleLocation($mode="output")
get full style sheet file name (path inclusive) of current user
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
getHighscoreScore()
Gets if the score column should be shown.
isBlockPassesAfterPassedEnabled()
setECTSOutput($a_ects_output)
{}
& getInvitedUsers($user_id="", $order="login, lastname, firstname")
Returns a list of all invited users in a test.
setProcessingTimeByMinutes($minutes)
removeTestResultsFromSoapLpAdministration($userIds)
static _lookupFinishedUserTests($a_user_id)
Gather all finished tests for user.
static _getScoreCutting($active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test.
setListOfQuestionsStart($a_value=true)
Sets if the the list of questions as the start page of the test.
setHighscoreAchievedTS($a_achieved_ts)
Sets if the date and time of the scores achievement should be displayed.
removeTestActives($activeIds)
getShowMarker()
Returns wheather the marker button is shown or not.
getImportMapping()
get array of (two) new created questions for import id
isSingleChoiceTestWithoutShuffle()
Returns TRUE if the test contains single choice results and no shuffle only.
setCharSelectorAvailability($availability)
setAnonymity($a_value=0)
Sets the anonymity status of the test.
getShuffleQuestions()
Returns the status of the shuffle_questions variable.
setExportSettingsSingleChoiceShort($a_settings)
removeTestResultsByUserIds($userIds)
& getUserData($ids)
Returns a data of all users specified by id list.
isNewRandomTest()
Checks wheather the test is a new random test (using tst_rnd_cpy) or an old one.
getListOfQuestionsDescription()
Returns TRUE if the list of questions should be presented with the question descriptions.
getECTSGrade($passed_array, $reached_points, $max_points)
{Returns the ECTS grade for a number of reached points.string The ECTS grade short description}
getActiveIdOfUser($user_id="", $anonymous_id="")
Gets the active id of a given user.
getCustomStyle()
Get the custom style.
checkMarks()
{boolean|string True or an error string which can be used for display purposes}
setShowSolutionFeedback($a_feedback=true)
Sets if the the feedback should be presented to the user in the solution or not.
recalculateScores($preserve_manscoring=false)
setEnabledViewMode($mode)
static isParticipantsLastPassActive($testRefId, $userId)
getSecondsUntilEndingTime()
Returns the seconds left from the actual time until the ending time.
isPassDeletionAllowed()
getter for the test setting passDeletionAllowed
getNrOfTries()
Returns the nr of tries for the test.
setShowExamviewHtml($show_examview_html)
const SCORE_REPORTING_DATE
setMCScoring($a_mc_scoring=SCORE_ZERO_POINTS_WHEN_UNANSWERED)
Sets the multiple choice scoring.
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
static _lookupAnonymity($a_obj_id)
Returns the anonymity status of a test with a given object id.
setEnableProcessingTime($enable=0)
Sets the processing time enabled or disabled.
setUsePreviousAnswers($use_previous_answers=1)
Sets the status of the visibility of previous learner answers.
& getAvailableQuestionpools($use_object_id=false, $equal_points=false, $could_be_offline=false, $show_path=false, $with_questioncount=false, $permission="read")
Returns the available question pools for the active user.
setGenericAnswerFeedback($generic_answer_feedback=0)
Sets if the generic feedback is to be shown in the test.
static getManualFeedback($active_id, $question_id, $pass)
Retrieves the feedback comment for a question in a test if it is finalized.
inviteRole($role_id)
Invites all users of a role to a test.
getJavaScriptOutput()
Returns if Javascript should be chosen for drag & drop actions for the active user.
setListOfQuestionsDescription($a_value=true)
Sets the show_summary attribute to TRUE if the list of questions should be presented with the questio...
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
update()
update object data
canShowCertificate($testSession, $user_id, $active_id)
Checks whether the certificate button could be shown on the info page or not.
getTextAnswer($active_id, $question_id, $pass=null)
Returns the text answer of a given user for a given question.
userLookupFullName($user_id, $overwrite_anonymity=false, $sorted_order=false, $suffix="")
Returns the full name of a test user according to the anonymity status.
getNrOfResultsForPass($active_id, $pass)
Calculates the number of user results for a specific test pass.
getECTSFX()
{float|null}
setExportSettings($a_settings)
setEndingTime($ending_time=null)
Sets the ending time in database timestamp format for the test.
getStartingTimeOfParticipants()
Note, this function should only be used if absolutely necessary, since it perform joins on tables tha...
addExtraTime($active_id, $minutes)
getAccessFilteredParticipantList()
static getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
cleanupMediaobjectUsage()
Cleans up the media objects for all text fields in a test which are using an RTE field.
setScoreReporting($score_reporting=0)
Sets the score reporting of the ilObjTest object.
isTestFinishedToViewResults($active_id, $currentpass)
Returns true if an active user completed a test pass and did not start a new pass.
static ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run=false)
exportFileItems($a_target_dir, &$expLog)
export files of file itmes
hasNrOfTriesRestriction()
returns if the numbers of tries have to be checked
static _lookupTestObjIdForQuestionId($a_q_id)
Get test Object ID for question ID.
setCustomStyle($a_customStyle=null)
Set the custom style.
const SCORE_REPORTING_DISABLED
setTmpCopyWizardCopyId($tmpCopyWizardCopyId)
getVisitTimeOfParticipant($active_id)
Returns the first and last visit of a participant.
setAccessFilteredParticipantList($accessFilteredParticipantList)
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename
getShowFinalStatement()
Returns whether the final statement should be shown or not.
questionMoveUp($question_id)
Moves a question up in order.
getProcessingTime()
Returns the processing time for the test.
setSequenceSettings($sequence_settings=0)
SEQUENCE SETTING = POSTPONING ENABLED !!
isForceInstantFeedbackEnabled()
& getCompleteWorkingTimeOfParticipants()
Returns the complete working time in seconds for all test participants.
getIntroduction()
Gets the introduction text of the ilObjTest object.
getAnswerFeedback()
Returns 1 if generic answer feedback is activated.
const HIGHSCORE_SHOW_TOP_TABLE
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd)
setShowMarker($a_value=1)
Sets the marker button status.
static _lookupName($a_user_id)
lookup user name
static _lookupClientIP($a_user_id)
Lookup client ip.
Class ilObjectActivation.
setTimingType($a_type)
Set timing type.
static getItem($a_ref_id)
Get item data.
static getInstanceByRefId($a_ref_id, $stop_on_error=true)
get an instance of an Ilias object by reference id
static getInstance($a_obj_id)
Class ilObject Basic functions for all objects.
getType()
get object type @access public
getOwner()
get object owner
static _lookupObjId($a_id)
setOfflineStatus($a_status)
Set offline status.
static _lookupTitle($a_id)
lookup object title
setTitle($a_title)
set object title
deleteMetaData()
delete meta data entry
static _lookupDescription($a_id)
lookup object description
updateMetaData()
update meta data entry
setDescription($a_desc)
set object description
getOfflineStatus()
Get offline status.
getRefId()
get reference id @access public
getDescription()
get object description
cloneMetaData($target_obj)
Copy meta data.
getId()
get object id @access public
static _prepareCloneSelection($a_ref_ids, $new_type, $show_path=true)
Prepare copy wizard object selection.
static _lookupOwner($a_id)
lookup object owner
getTitle()
get object title @access public
static collectFileItems($a_page, $a_domdoc)
Get all file items that are used within the page.
static getPluginObject(string $a_ctype, string $a_cname, string $a_slot_id, string $a_pname)
getPresentationMaterial()
{ilQTIPresentationMaterial|null}
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
static _cleanupMediaObjectUsage($a_text, $a_usage_type, $a_usage_id)
Synchronises appearances of media objects in $a_text with media object usage table.
static factory($a_package, $a_timeout=0)
Creates an ilRpcClient instance to our ilServer.
ILIAS Setting Class.
special template class to simplify handling of ITX/PEAR
Base Exception for all Exceptions relating to Modules/Test.
Class ilTestMailNotification.
Class ilTestScoring.
Test sequence handler.
static isManScoringDone($activeId)
reads the flag wether manscoring is done for the given test active or not from the global settings (s...
Test session handler.
static getDataDir()
get data directory (outside webspace)
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static insertInstIntoID($a_value)
inserts installation id into ILIAS id
static prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free,...
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
static deliverData($a_data, $a_filename, $mime="application/octet-stream", $charset="")
deliver data for download via browser.
static _getObjectsByOperations($a_obj_type, $a_operation, $a_usr_id=0, $limit=0)
Get all objects of a specific type and check access This function is not recursive,...
static ilTempnam($a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
static removeTrailingPathSeparators($path)
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms @access public
static makeDir($a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
XML writer class.
xmlHeader()
Writes xml header @access public.
$login
Definition: cron.php:13
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
global $ilBench
Definition: ilias.php:18
global $ilCtrl
Definition: ilias.php:18
const SCORE_BEST_PASS
const SCORE_ZERO_POINTS_WHEN_UNANSWERED
const COUNT_PARTIAL_SOLUTIONS
const TEST_FIXED_SEQUENCE
Test constants.
const SCORE_CUT_QUESTION
const SCORE_LAST_PASS
const INVITATION_OFF
xslt_error(&$proc)
xslt_free(&$proc)
xslt_create()
Interface ilDBInterface.
if($format !==null) $name
Definition: metadata.php:230
$index
Definition: metadata.php:128
if(!array_key_exists('PATH_INFO', $_SERVER)) $config
Definition: metadata.php:68
$i
Definition: metadata.php:24
$keys
Definition: metadata.php:187
$xml
Definition: metadata.php:332
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
redirection script todo: (a better solution should control the processing via a xml file)
global $ilSetting
Definition: privfeed.php:17
$query
$results
foreach($_POST as $key=> $value) $res
global $ilDB
$data
Definition: storeScorm.php:23
$mobs
$ilUser
Definition: imgupload.php:18
$a_type
Definition: workflow.php:92
$DIC
Definition: xapitoken.php:46
$objId
Definition: xapitoken.php:41
$rows
Definition: xhr_table.php:10