ILIAS  release_7 Revision v7.30-3-g800a261c036
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
10use ILIAS\Refinery\Factory as Refinery;
11
23{
25
26 #region Properties
27
31 const QUESTION_SET_TYPE_FIXED = 'FIXED_QUEST_SET';
32
36 const QUESTION_SET_TYPE_RANDOM = 'RANDOM_QUEST_SET';
37
41 const QUESTION_SET_TYPE_DYNAMIC = 'DYNAMIC_QUEST_SET';
42
47
52
57
64
68 private $skillServiceEnabled = false;
69
73 private $resultFilterTaxIds = array();
74
82 protected $_kiosk;
83
89 public $test_id;
90
97
104 public $author;
105
111 public $metadata;
112
119
124
131 protected $introduction;
132
139
148
159
168
175
185
192
200
202
210
220
227
234
241
246
252 protected $starting_time;
253
258
264 protected $ending_time;
265
270 protected $ects_output = false;
271
276 protected $ects_fx = null;
277
282 protected $ects_grades = array();
283
284
292
299
306
314
321
328
335
340
346 protected $password;
347
352
358 protected $allowedUsers;
359
366
373
380
387
394
401
408
415
422
429
436
442 private $_showinfo;
443
449 private $_forcejs = true;
450
457
459
460 protected $mailnottype;
461
463
464 protected $poolUsage;
465
467
468 protected $oldOnlineStatus = null;
469
474
481
487 private $obligationsEnabled = null;
488
490
492
494
495 protected $autosave;
496
497 protected $autosave_ival;
498
505 private $passDeletionAllowed = null;
506
512 private $participantDataExist = null;
513
516
519
522
525
529 private $redirection_mode = 0;
530
534 private $redirection_url = null;
535
538
541
544
547
550
555
560
565
570
575
580
585
589 protected $pass_waiting = "00:000:00:00:00";
590 #endregion
591
600 public function __construct($a_id = 0, $a_call_by_reference = true)
601 {
602 global $DIC;
603 $ilUser = $DIC['ilUser'];
604 $lng = $DIC['lng'];
605 $this->refinery = $DIC['refinery'];
606 $this->type = "tst";
607
608 $lng->loadLanguageModule("assessment");
609 // Defaults:
610 include_once "./Modules/Test/classes/class.assMarkSchema.php";
611 $this->mark_schema = new ASS_MarkSchema();
612 $this->mark_schema->createSimpleSchema(
613 $lng->txt("failed_short"),
614 $lng->txt("failed_official"),
615 0,
616 0,
617 $lng->txt("passed_short"),
618 $lng->txt("passed_official"),
619 50,
620 1
621 );
622
623 $this->test_id = -1;
624 $this->author = $ilUser->fullname;
625 $this->introductionEnabled = false;
626 $this->introduction = "";
627 $this->questions = array();
628 $this->sequence_settings = TEST_FIXED_SEQUENCE;
629 $this->score_reporting = self::SCORE_REPORTING_FINISHED;
630 $this->instant_verification = 0;
631 $this->answer_feedback_points = 0;
632 $this->reporting_date = "";
633 $this->nr_of_tries = 0;
634 $this->_kiosk = 0;
635 $this->use_previous_answers = 1;
636 $this->title_output = 0;
637 $this->starting_time = "";
638 $this->ending_time = "";
639 $this->processing_time = "";
640 $this->enable_processing_time = "0";
641 $this->reset_processing_time = 0;
642 $this->ects_output = false;
643 $this->ects_fx = null;
644 $this->shuffle_questions = false;
645 $this->mailnottype = 0;
646 $this->exportsettings = 0;
647 $this->show_summary = 8;
648 $this->count_system = COUNT_PARTIAL_SOLUTIONS;
649 $this->mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED;
650 $this->score_cutting = SCORE_CUT_QUESTION;
651 $this->pass_scoring = SCORE_LAST_PASS;
652 $this->answer_feedback = 0;
653 $this->password = "";
654 $this->certificate_visibility = 0;
655 $this->allowedUsers = "";
656 $this->_showfinalstatement = false;
657 $this->_finalstatement = "";
658 $this->_showinfo = true;
659 $this->_forcejs = true;
660 $this->_customStyle = "";
661 $this->allowedUsersTimeGap = "";
662 $this->anonymity = 0;
663 $this->show_cancel = 0;
664 $this->show_marker = 0;
665 $this->fixed_participants = 0;
666 $this->setShowPassDetails(true);
667 $this->setShowSolutionDetails(true);
668 $this->setShowSolutionAnswersOnly(false);
669 $this->setShowSolutionSignature(false);
670 $this->testSession = false;
671 $this->testSequence = false;
672 $this->mailnotification = 0;
673 $this->poolUsage = 1;
674
675 $this->ects_grades = array(
676 'A' => 90,
677 'B' => 65,
678 'C' => 35,
679 'D' => 10,
680 'E' => 0
681 );
682
683 $this->autosave = false;
684 $this->autosave_ival = 30000;
685
686 $this->enable_examview = false;
687 $this->show_examview_html = false;
688 $this->show_examview_pdf = false;
689 $this->enable_archiving = false;
690
691 $this->express_mode = false;
692 $this->template_id = '';
693 $this->redirection_mode = 0;
694 $this->redirection_url = null;
695 $this->show_exam_id_in_test_pass_enabled = false;
696 $this->show_exam_id_in_test_results_enabled = false;
697 $this->sign_submission = false;
698 $this->char_selector_availability = 0;
699 $this->char_selector_definition = null;
700
701 $this->showGradingStatusEnabled = true;
702 $this->showGradingMarkEnabled = true;
703
704 $this->followupQuestionAnswerFixationEnabled = false;
705 $this->instantFeedbackAnswerFixationEnabled = false;
706
707 $this->testFinalBroken = false;
708
709 $this->tmpCopyWizardCopyId = null;
710
711 parent::__construct($a_id, $a_call_by_reference);
712 }
713
720 {
721 require_once 'Services/Utilities/classes/class.ilUtil.php';
722 return ilUtil::getASCIIFilename($this->getTitle());
723 }
724
728 public function getTmpCopyWizardCopyId()
729 {
731 }
732
737 {
738 $this->tmpCopyWizardCopyId = $tmpCopyWizardCopyId;
739 }
740
744 public function create()
745 {
746 $this->setOfflineStatus(true);
747 parent::create();
748
749 // meta data will be created by
750 // import parser
751 if (!$a_upload) {
752 $this->createMetaData();
753 }
754 }
755
762 public function update()
763 {
764 if (!parent::update()) {
765 return false;
766 }
767
768 // put here object specific stuff
769 $this->updateMetaData();
770 return true;
771 }
772
778 public function read()
779 {
780 parent::read();
781 $this->loadFromDb();
782 }
783
784
791 public function delete()
792 {
793 // always call parent delete function first!!
794 if (!parent::delete()) {
795 return false;
796 }
797
798 // delet meta data
799 $this->deleteMetaData();
800
801 //put here your module specific stuff
802 $this->deleteTest();
803
804 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentImportFails.php';
805 $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($this->getId());
806 $qsaImportFails->deleteRegisteredImportFails();
807 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdImportFails.php';
808 $sltImportFails = new ilTestSkillLevelThresholdImportFails($this->getId());
809 $sltImportFails->deleteRegisteredImportFails();
810
811 return true;
812 }
813
819 public function deleteTest()
820 {
821 global $DIC;
822 $tree = $DIC['tree'];
823 $ilDB = $DIC['ilDB'];
824 $ilPluginAdmin = $DIC['ilPluginAdmin'];
825 $lng = $DIC['lng'];
826
827 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
828 $participantData = new ilTestParticipantData($ilDB, $lng);
829 $participantData->load($this->getTestId());
830 $this->removeTestResults($participantData);
831
832 $affectedRows = $ilDB->manipulateF(
833 "DELETE FROM tst_mark WHERE test_fi = %s",
834 array('integer'),
835 array($this->getTestId())
836 );
837
838 $affectedRows = $ilDB->manipulateF(
839 "DELETE FROM tst_tests WHERE test_id = %s",
840 array('integer'),
841 array($this->getTestId())
842 );
843
844 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
845 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
846 $testQuestionSetConfigFactory->getQuestionSetConfig()->removeQuestionSetRelatedData();
847
848 // delete export files
849 include_once "./Services/Utilities/classes/class.ilUtil.php";
850 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
851 $directory = $tst_data_dir . "/tst_" . $this->getId();
852 if (is_dir($directory)) {
853 include_once "./Services/Utilities/classes/class.ilUtil.php";
854 ilUtil::delDir($directory);
855 }
856 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
857 $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
858 // remaining usages are not in text anymore -> delete them
859 // and media objects (note: delete method of ilObjMediaObject
860 // checks whether object is used in another context; if yes,
861 // the object is not deleted!)
862 foreach ($mobs as $mob) {
863 ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
864 if (ilObjMediaObject::_exists($mob)) {
865 $mob_obj = new ilObjMediaObject($mob);
866 $mob_obj->delete();
867 }
868 }
869 }
870
876 public function createExportDirectory()
877 {
878 include_once "./Services/Utilities/classes/class.ilUtil.php";
879 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
880 ilUtil::makeDir($tst_data_dir);
881 if (!is_writable($tst_data_dir)) {
882 $this->ilias->raiseError("Test Data Directory (" . $tst_data_dir
883 . ") not writeable.", $this->ilias->error_obj->MESSAGE);
884 }
885
886 // create learning module directory (data_dir/lm_data/lm_<id>)
887 $tst_dir = $tst_data_dir . "/tst_" . $this->getId();
888 ilUtil::makeDir($tst_dir);
889 if (!@is_dir($tst_dir)) {
890 $this->ilias->raiseError("Creation of Test Directory failed.", $this->ilias->error_obj->MESSAGE);
891 }
892 // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
893 $export_dir = $tst_dir . "/export";
894 ilUtil::makeDir($export_dir);
895 if (!@is_dir($export_dir)) {
896 $this->ilias->raiseError("Creation of Export Directory failed.", $this->ilias->error_obj->MESSAGE);
897 }
898 }
899
905 public function getExportDirectory()
906 {
907 include_once "./Services/Utilities/classes/class.ilUtil.php";
908 $export_dir = ilUtil::getDataDir() . "/tst_data" . "/tst_" . $this->getId() . "/export";
909 return $export_dir;
910 }
911
918 public function getExportFiles($dir)
919 {
920 // quit if import dir not available
921 if (!@is_dir($dir) || !is_writeable($dir)) {
922 return array();
923 }
924
925 $files = array();
926 foreach (new DirectoryIterator($dir) as $file) {
930 if ($file->isDir()) {
931 continue;
932 }
933
934 $files[] = $file->getBasename();
935 }
936
937 sort($files);
938
939 return $files;
940 }
941
945 public static function _setImportDirectory($a_import_dir = null)
946 {
947 if (strlen($a_import_dir)) {
948 $_SESSION["tst_import_dir"] = $a_import_dir;
949 } else {
950 unset($_SESSION["tst_import_dir"]);
951 }
952 }
953
960 public static function _getImportDirectory()
961 {
962 if (strlen($_SESSION["tst_import_dir"])) {
963 return $_SESSION["tst_import_dir"];
964 }
965 return null;
966 }
967
968 public function getImportDirectory()
969 {
971 }
972
978 public static function _createImportDirectory()
979 {
980 global $DIC;
981 $ilias = $DIC['ilias'];
982 include_once "./Services/Utilities/classes/class.ilUtil.php";
983 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
984 ilUtil::makeDir($tst_data_dir);
985
986 if (!is_writable($tst_data_dir)) {
987 $ilias->raiseError("Test Data Directory (" . $tst_data_dir
988 . ") not writeable.", $ilias->error_obj->FATAL);
989 }
990
991 // create test directory (data_dir/tst_data/tst_import)
992 $tst_dir = $tst_data_dir . "/tst_import";
993 ilUtil::makeDir($tst_dir);
994 if (!@is_dir($tst_dir)) {
995 $ilias->raiseError("Creation of test import directory failed.", $ilias->error_obj->FATAL);
996 }
997
998 // assert that this is empty and does not contain old data
999 ilUtil::delDir($tst_dir, true);
1000
1001 return $tst_dir;
1002 }
1003
1011 {
1012 global $DIC;
1013 $ilDB = $DIC['ilDB'];
1014
1015 $result = $ilDB->queryF(
1016 "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",
1017 array('integer'),
1018 array($this->getTestId())
1019 );
1020 $hasSC = false;
1021 while ($row = $ilDB->fetchAssoc($result)) {
1022 if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1023 $hasSC = true;
1024 }
1025 }
1026 return $hasSC;
1027 }
1028
1035 public function isSingleChoiceTest()
1036 {
1037 global $DIC;
1038 $ilDB = $DIC['ilDB'];
1039
1040 $result = $ilDB->queryF(
1041 "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",
1042 array('integer'),
1043 array($this->getTestId())
1044 );
1045 if ($result->numRows() == 1) {
1046 $row = $ilDB->fetchAssoc($result);
1047 if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1048 return true;
1049 } else {
1050 return false;
1051 }
1052 }
1053 return false;
1054 }
1055
1063 {
1064 global $DIC;
1065 $ilDB = $DIC['ilDB'];
1066
1067 if (!$this->hasSingleChoiceQuestions()) {
1068 return false;
1069 }
1070
1071 $result = $ilDB->queryF(
1072 "
1073 SELECT DISTINCT(qpl_qst_sc.shuffle) foundshuffles
1074 FROM qpl_questions,
1075 qpl_qst_sc,
1076 tst_test_result,
1077 qpl_qst_type,
1078 tst_active
1079 WHERE tst_test_result.question_fi = qpl_questions.question_id
1080 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
1081 AND tst_test_result.active_fi = tst_active.active_id
1082 AND qpl_questions.question_id = qpl_qst_sc.question_fi
1083 AND tst_active.test_fi = %s
1084 AND qpl_qst_type.type_tag = %s
1085 ",
1086 array('integer', 'text'),
1087 array($this->getTestId(), 'assSingleChoice')
1088 );
1089 if ($result->numRows() == 1) {
1090 $row = $ilDB->fetchAssoc($result);
1091 return ($row['foundshuffles'] == 0);
1092 }
1093 return false;
1094 }
1095
1102 final public function isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
1103 {
1104 if (!count($this->mark_schema->mark_steps)) {
1105 return false;
1106 }
1107
1108 if (!$testQuestionSetConfig->isQuestionSetConfigured()) {
1109 return false;
1110 }
1111
1112 return true;
1113 }
1114
1121 public function _isComplete($obj_id)
1122 {
1123 global $DIC;
1124 $tree = $DIC['tree'];
1125 $ilDB = $DIC['ilDB'];
1126 $ilPluginAdmin = $DIC['ilPluginAdmin'];
1127
1128 $test = new ilObjTest($obj_id, false);
1129 $test->loadFromDb();
1130
1131 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1132 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
1133
1134 return $test->isComplete($testQuestionSetConfigFactory->getQuestionSetConfig());
1135 }
1136
1140 public function saveECTSStatus()
1141 {
1145 global $DIC;
1146 $ilDB = $DIC['ilDB'];
1147
1148 if ($this->getTestId() > 0) {
1149 $this->setECTSFX(preg_replace('/,/', '.', $this->getECTSFX()));
1150 if (!preg_match('/\d+/', $this->getECTSFX())) {
1151 $this->setECTSFX(null);
1152 }
1153
1154 $grades = $this->getECTSGrades();
1155 $ilDB->manipulateF(
1156 "UPDATE tst_tests
1157 SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s
1158 WHERE test_id = %s",
1159 array('text', 'float', 'float', 'float', 'float', 'float', 'float', 'integer'),
1160 array(
1161 (int) $this->getECTSOutput(),
1162 $grades['A'], $grades['B'], $grades['C'], $grades['D'], $grades['E'],
1163 $this->getECTSFX(),
1164 $this->getTestId()
1165 )
1166 );
1167 }
1168 }
1169
1174 public function saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
1175 {
1176 global $DIC;
1177 $ilDB = $DIC['ilDB'];
1178
1179 $complete = 0;
1180 if ($this->isComplete($testQuestionSetConfig)) {
1181 $complete = 1;
1182 }
1183 if ($this->getTestId() > 0) {
1184 $ilDB->manipulateF(
1185 "UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1186 array('text', 'integer'),
1187 array($complete, $this->test_id)
1188 );
1189 }
1190 }
1191
1197 public function getAllRTEContent()
1198 {
1199 $result = array();
1200 array_push($result, $this->getIntroduction());
1201 array_push($result, $this->getFinalStatement());
1202 return $result;
1203 }
1204
1210 public function cleanupMediaobjectUsage()
1211 {
1212 include_once("./Services/RTE/classes/class.ilRTE.php");
1213 $completecontent = "";
1214 foreach ($this->getAllRTEContent() as $content) {
1215 $completecontent .= $content;
1216 }
1218 $completecontent,
1219 $this->getType() . ":html",
1220 $this->getId()
1221 );
1222 }
1223
1229 public function saveToDb($properties_only = false)
1230 {
1231 global $DIC;
1232 $tree = $DIC['tree'];
1233 $ilDB = $DIC['ilDB'];
1234 $ilPluginAdmin = $DIC['ilPluginAdmin'];
1235
1236 // moved online_status to ilObjectActivation (see below)
1237
1238 // cleanup RTE images
1239 $this->cleanupMediaobjectUsage();
1240
1241 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1242 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
1243 $testQuestionSetConfig = $testQuestionSetConfigFactory->getQuestionSetConfig();
1244
1245 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1246 if ($this->test_id == -1) {
1247 // Create new dataset
1248 $next_id = $ilDB->nextId('tst_tests');
1249
1250 $ilDB->insert('tst_tests', array(
1251 'test_id' => array('integer', $next_id),
1252 'obj_fi' => array('integer', $this->getId()),
1253 'author' => array('text', $this->getAuthor()),
1254 'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1255 'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1256 'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1257 'showinfo' => array('integer', $this->getShowInfo()),
1258 'forcejs' => array('integer', $this->getForceJS()),
1259 'customstyle' => array('text', $this->getCustomStyle()),
1260 'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1261 'sequence_settings' => array('integer', $this->getSequenceSettings()),
1262 'score_reporting' => array('integer', $this->getScoreReporting()),
1263 'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1264 'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1265 'answer_feedback' => array('text', $this->getAnswerFeedback()),
1266 'anonymity' => array('text', $this->getAnonymity()),
1267 'show_cancel' => array('text', $this->getShowCancel()),
1268 'show_marker' => array('integer', $this->getShowMarker()),
1269 'fixed_participants' => array('text', $this->getFixedParticipants()),
1270 'nr_of_tries' => array('integer', $this->getNrOfTries()),
1271 'block_after_passed' => array('integer', (int) $this->isBlockPassesAfterPassedEnabled()),
1272 'kiosk' => array('integer', $this->getKiosk()),
1273 'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1274 'title_output' => array('text', $this->getTitleOutput()),
1275 'processing_time' => array('text', $this->getProcessingTime()),
1276 'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1277 'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1278 'reporting_date' => array('text', $this->getReportingDate()),
1279 'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1280 'starting_time' => array('integer', $this->getStartingTime()),
1281 'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1282 'ending_time' => array('integer', $this->getEndingTime()),
1283 'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1284 'ects_output' => array('text', $this->getECTSOutput()),
1285 'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1286 'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1287 'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1288 'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1289 'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1290 'ects_fx' => array('float', $this->getECTSFX()),
1291 'count_system' => array('text', $this->getCountSystem()),
1292 'mc_scoring' => array('text', $this->getMCScoring()),
1293 'score_cutting' => array('text', $this->getScoreCutting()),
1294 'pass_scoring' => array('text', $this->getPassScoring()),
1295 'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1296 'results_presentation' => array('integer', $this->getResultsPresentation()),
1297 'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1298 'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1299 'password' => array('text', $this->getPassword()),
1300 'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1301 'allowedusers' => array('integer', $this->getAllowedUsers()),
1302 'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1303 'mailnottype' => array('integer', $this->getMailNotificationType()),
1304 'exportsettings' => array('integer', $this->getExportSettings()),
1305 'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1306 'mailnotification' => array('integer', $this->getMailNotification()),
1307 'created' => array('integer', time()),
1308 'tstamp' => array('integer', time()),
1309 'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1310 'template_id' => array('integer', $this->getTemplate()),
1311 'pool_usage' => array('integer', $this->getPoolUsage()),
1312 'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1313 'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1314 'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1315 'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1316 'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1317 'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1318 'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1319 'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1320 'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1321 'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1322 'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1323 'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1324 'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1325 'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1326 'autosave' => array('integer', (int) $this->getAutosave()),
1327 'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1328 'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1329 'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1330 'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1331 'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1332 'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1333 'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1334 'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1335 'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1336 'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1337 'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1338 'question_set_type' => array('text', $this->getQuestionSetType()),
1339 'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1340 'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1341 'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1342 'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1343 'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1344 'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1345 'follow_qst_answer_fixation' => array('integer', (int) $this->isFollowupQuestionAnswerFixationEnabled()),
1346 'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1347 'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1348 'broken' => array('integer', (int) $this->isTestFinalBroken()),
1349 'pass_waiting' => array('text', (string) $this->getPassWaiting())
1350 ));
1351
1352 $this->test_id = $next_id;
1353
1355 $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1356 }
1357 } else {
1358 // Modify existing dataset
1359 $oldrow = array();
1361 $result = $ilDB->queryF(
1362 "SELECT * FROM tst_tests WHERE test_id = %s",
1363 array('integer'),
1364 array($this->test_id)
1365 );
1366 if ($result->numRows() == 1) {
1367 $oldrow = $ilDB->fetchAssoc($result);
1368 }
1369 }
1370
1371 $ilDB->update(
1372 'tst_tests',
1373 array(
1374 'author' => array('text', $this->getAuthor()),
1375 'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1376 'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1377 'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1378 'showinfo' => array('integer', $this->getShowInfo()),
1379 'forcejs' => array('integer', $this->getForceJS()),
1380 'customstyle' => array('text', $this->getCustomStyle()),
1381 'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1382 'sequence_settings' => array('integer', $this->getSequenceSettings()),
1383 'score_reporting' => array('integer', $this->getScoreReporting()),
1384 'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1385 'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1386 'answer_feedback' => array('text', $this->getGenericAnswerFeedback()),
1387 'anonymity' => array('text', $this->getAnonymity()),
1388 'show_cancel' => array('text', $this->getShowCancel()),
1389 'show_marker' => array('integer', $this->getShowMarker()),
1390 'fixed_participants' => array('text', $this->getFixedParticipants()),
1391 'nr_of_tries' => array('integer', $this->getNrOfTries()),
1392 'block_after_passed' => array('integer', (int) $this->isBlockPassesAfterPassedEnabled()),
1393 'kiosk' => array('integer', $this->getKiosk()),
1394 'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1395 'title_output' => array('text', $this->getTitleOutput()),
1396 'processing_time' => array('text', $this->getProcessingTime()),
1397 'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1398 'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1399 'reporting_date' => array('text', $this->getReportingDate()),
1400 'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1401 'starting_time' => array('integer', $this->getStartingTime()),
1402 'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1403 'ending_time' => array('integer', $this->getEndingTime()),
1404 'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1405 'ects_output' => array('text', $this->getECTSOutput()),
1406 'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1407 'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1408 'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1409 'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1410 'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1411 'ects_fx' => array('float', $this->getECTSFX()),
1412 'count_system' => array('text', $this->getCountSystem()),
1413 'mc_scoring' => array('text', $this->getMCScoring()),
1414 'score_cutting' => array('text', $this->getScoreCutting()),
1415 'pass_scoring' => array('text', $this->getPassScoring()),
1416 'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1417 'results_presentation' => array('integer', $this->getResultsPresentation()),
1418 'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1419 'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1420 'password' => array('text', $this->getPassword()),
1421 'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1422 'allowedusers' => array('integer', $this->getAllowedUsers()),
1423 'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1424 'mailnottype' => array('integer', $this->getMailNotificationType()),
1425 'exportsettings' => array('integer', $this->getExportSettings()),
1426 'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1427 'mailnotification' => array('integer', $this->getMailNotification()),
1428 'tstamp' => array('integer', time()),
1429 'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1430 'template_id' => array('integer', $this->getTemplate()),
1431 'pool_usage' => array('integer', $this->getPoolUsage()),
1432 'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1433 'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1434 'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1435 'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1436 'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1437 'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1438 'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1439 'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1440 'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1441 'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1442 'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1443 'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1444 'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1445 'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1446 'autosave' => array('integer', (int) $this->getAutosave()),
1447 'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1448 'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1449 'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1450 'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1451 'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1452 'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1453 'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1454 'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1455 'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1456 'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1457 'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1458 'question_set_type' => array('text', $this->getQuestionSetType()),
1459 'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1460 'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1461 'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1462 'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1463 'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1464 'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1465 'follow_qst_answer_fixation' => array('integer', (int) $this->isFollowupQuestionAnswerFixationEnabled()),
1466 'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1467 'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1468 'broken' => array('integer', (int) $this->isTestFinalBroken()),
1469 'pass_waiting' => array('text', (string) $this->getPassWaiting())
1470 ),
1471 array(
1472 'test_id' => array('integer', (int) $this->getTestId())
1473 )
1474 );
1475
1476 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1478 $logresult = $ilDB->queryF(
1479 "SELECT * FROM tst_tests WHERE test_id = %s",
1480 array('integer'),
1481 array($this->getTestId())
1482 );
1483 $newrow = array();
1484 if ($logresult->numRows() == 1) {
1485 $newrow = $ilDB->fetchAssoc($logresult);
1486 }
1487 $changed_fields = array();
1488 foreach ($oldrow as $key => $value) {
1489 if (strcmp($oldrow[$key], $newrow[$key]) != 0) {
1490 array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1491 }
1492 }
1493 $changes = join(", ", $changed_fields);
1494 if (count($changed_fields) > 0) {
1495 $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [" . $changes . "]");
1496 }
1497 }
1498 if ($this->evalTotalPersons() > 0) {
1499 // reset the finished status of participants if the nr of test passes did change
1500 if ($this->getNrOfTries() > 0) {
1501 // set all unfinished tests with nr of passes >= allowed passes finished
1502 $aresult = $ilDB->queryF(
1503 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
1504 array('integer', 'integer', 'integer'),
1505 array($this->getTestId(), $this->getNrOfTries(), 0)
1506 );
1507 while ($row = $ilDB->fetchAssoc($aresult)) {
1508 $ilDB->manipulateF(
1509 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1510 array('integer', 'timestamp', 'integer'),
1511 array(1, date('Y-m-d H:i:s'), $row["active_id"])
1512 );
1513 }
1514
1515 // set all finished tests with nr of passes < allowed passes not finished
1516 $aresult = $ilDB->queryF(
1517 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
1518 array('integer', 'integer', 'integer'),
1519 array($this->getTestId(), $this->getNrOfTries() - 1, 1)
1520 );
1521 while ($row = $ilDB->fetchAssoc($aresult)) {
1522 $ilDB->manipulateF(
1523 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1524 array('integer', 'timestamp', 'integer'),
1525 array(0, null, $row["active_id"])
1526 );
1527 }
1528 } else {
1529 // set all finished tests with nr of passes >= allowed passes not finished
1530 $aresult = $ilDB->queryF(
1531 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
1532 array('integer', 'integer'),
1533 array($this->getTestId(), 1)
1534 );
1535 while ($row = $ilDB->fetchAssoc($aresult)) {
1536 $ilDB->manipulateF(
1537 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1538 array('integer', 'timestamp', 'integer'),
1539 array(0, null, $row["active_id"])
1540 );
1541 }
1542 }
1543 }
1544 }
1545
1546 // news item creation/update/deletion
1547 include_once 'Services/News/classes/class.ilNewsItem.php';
1548 if (!$this->getOldOnlineStatus() && !$this->getOfflineStatus()) {
1549 global $DIC;
1550 $ilUser = $DIC['ilUser'];
1551 $newsItem = new ilNewsItem();
1552 $newsItem->setContext($this->getId(), 'tst');
1553 $newsItem->setPriority(NEWS_NOTICE);
1554 $newsItem->setTitle('new_test_online');
1555 $newsItem->setContentIsLangVar(true);
1556 $newsItem->setContent('');
1557 $newsItem->setUserId($ilUser->getId());
1558 $newsItem->setVisibility(NEWS_USERS);
1559 $newsItem->create();
1560 } elseif ($this->getOldOnlineStatus() && !$this->getOfflineStatus()) {
1561 ilNewsItem::deleteNewsOfContext($this->getId(), 'tst');
1562 } elseif (!$this->getOfflineStatus()) {
1563 $newsId = ilNewsItem::getFirstNewsIdForContext($this->getId(), 'tst');
1564 if ($newsId > 0) {
1565 $newsItem = new ilNewsItem($newsId);
1566 $newsItem->setTitle('new_test_online');
1567 $newsItem->setContentIsLangVar(true);
1568 $newsItem->setContent('');
1569 $newsItem->update();
1570 }
1571 }
1572
1573 // moved activation to ilObjectActivation
1574 if ($this->ref_id) {
1575 include_once "./Services/Object/classes/class.ilObjectActivation.php";
1576 ilObjectActivation::getItem($this->ref_id);
1577
1578 $item = new ilObjectActivation;
1579 if (!$this->isActivationLimited()) {
1581 } else {
1582 $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
1583 $item->setTimingStart($this->getActivationStartingTime());
1584 $item->setTimingEnd($this->getActivationEndingTime());
1585 $item->toggleVisible($this->getActivationVisibility());
1586 }
1587
1588 $item->update($this->ref_id);
1589 }
1590
1591 if (!$properties_only) {
1592 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
1593 $this->saveQuestionsToDb();
1594 }
1595
1596 $this->mark_schema->saveToDb($this->test_id);
1597 }
1598 }
1599
1606 public function saveQuestionsToDb()
1607 {
1608 global $DIC;
1609 $ilDB = $DIC['ilDB'];
1610
1611 $oldquestions = array();
1612 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1614 $result = $ilDB->queryF(
1615 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1616 array('integer'),
1617 array($this->getTestId())
1618 );
1619 if ($result->numRows() > 0) {
1620 while ($row = $ilDB->fetchAssoc($result)) {
1621 array_push($oldquestions, $row["question_fi"]);
1622 }
1623 }
1624 }
1625 // workaround for lost obligations
1626 // this method is called if a question is removed
1627 $currentQuestionsObligationsQuery = 'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
1628 $rset = $ilDB->queryF($currentQuestionsObligationsQuery, array('integer'), array($this->getTestId()));
1629 while ($row = $ilDB->fetchAssoc($rset)) {
1630 $obligatoryQuestionState[$row['question_fi']] = $row['obligatory'];
1631 }
1632 // delete existing category relations
1633 $affectedRows = $ilDB->manipulateF(
1634 "DELETE FROM tst_test_question WHERE test_fi = %s",
1635 array('integer'),
1636 array($this->getTestId())
1637 );
1638 // create new category relations
1639 foreach ($this->questions as $key => $value) {
1640 // workaround for import witout obligations information
1641 if (!isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value])) {
1642 $obligatoryQuestionState[$value] = 0;
1643 }
1644
1645 // insert question
1646 $next_id = $ilDB->nextId('tst_test_question');
1647 $ilDB->insert('tst_test_question', array(
1648 'test_question_id' => array('integer', $next_id),
1649 'test_fi' => array('integer', $this->getTestId()),
1650 'question_fi' => array('integer', $value),
1651 'sequence' => array('integer', $key),
1652 'obligatory' => array('integer', $obligatoryQuestionState[$value]),
1653 'tstamp' => array('integer', time())
1654 ));
1655 }
1656 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1658 $result = $ilDB->queryF(
1659 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1660 array('integer'),
1661 array($this->getTestId())
1662 );
1663 $newquestions = array();
1664 if ($result->numRows() > 0) {
1665 while ($row = $ilDB->fetchAssoc($result)) {
1666 array_push($newquestions, $row["question_fi"]);
1667 }
1668 }
1669 foreach ($oldquestions as $index => $question_id) {
1670 if (strcmp($newquestions[$index], $question_id) != 0) {
1671 $pos = array_search($question_id, $newquestions);
1672 if ($pos === false) {
1673 $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1674 } else {
1675 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index + 1) . " => " . ($pos + 1), $question_id);
1676 }
1677 }
1678 }
1679 foreach ($newquestions as $index => $question_id) {
1680 if (array_search($question_id, $oldquestions) === false) {
1681 $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index + 1), $question_id);
1682 }
1683 }
1684 }
1685 }
1686
1692 protected function isNewRandomTest()
1693 {
1694 global $DIC;
1695 $ilDB = $DIC['ilDB'];
1696 $result = $ilDB->queryF(
1697 'SELECT copy_id FROM tst_rnd_cpy WHERE tst_fi = %s',
1698 array('integer'),
1699 array($this->getTestId())
1700 );
1701 return $result->numRows() > 0;
1702 }
1703
1716 public function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = null)
1717 {
1718 global $DIC;
1719 $rbacsystem = $DIC['rbacsystem'];
1720 $ilDB = $DIC['ilDB'];
1721
1722 // retrieve object id instead of ref id if necessary
1723 if (($questionpool != 0) && (!$use_obj_id)) {
1724 $questionpool = ilObject::_lookupObjId($questionpool);
1725 }
1726
1727 // get original ids of all existing questions in the test
1728 $result = $ilDB->queryF(
1729 "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",
1730 array("integer"),
1731 array($this->getTestId())
1732 );
1733 $original_ids = array();
1734 $paramtypes = array();
1735 $paramvalues = array();
1736 while ($row = $ilDB->fetchAssoc($result)) {
1737 array_push($original_ids, $row['original_id']);
1738 }
1739
1740 $available = "";
1741 // get a list of all available questionpools
1742 if (($questionpool == 0) && (!is_array($qpls))) {
1743 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1744 $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())));
1745 if (count($available_pools)) {
1746 $available = " AND " . $ilDB->in('obj_fi', $available_pools, false, 'integer');
1747 } else {
1748 return array();
1749 }
1750 }
1751
1752 $constraint_qpls = "";
1753 $result_array = array();
1754 if ($questionpool == 0) {
1755 if (is_array($qpls)) {
1756 if (count($qpls) > 0) {
1757 $constraint_qpls = " AND " . $ilDB->in('obj_fi', $qpls, false, 'integer');
1758 }
1759 }
1760 }
1761
1762 $original_clause = "";
1763 if (count($original_ids)) {
1764 $original_clause = " AND " . $ilDB->in('question_id', $original_ids, true, 'integer');
1765 }
1766
1767 if ($questionpool == 0) {
1768 $result = $ilDB->queryF(
1769 "SELECT question_id FROM qpl_questions WHERE original_id IS NULL $available $constraint_qpls AND owner > %s AND complete = %s $original_clause",
1770 array('integer', 'text'),
1771 array(0, "1")
1772 );
1773 } else {
1774 $result = $ilDB->queryF(
1775 "SELECT question_id FROM qpl_questions WHERE original_id IS NULL AND obj_fi = %s AND owner > %s AND complete = %s $original_clause",
1776 array('integer','integer', 'text'),
1777 array($questionpool, 0, "1")
1778 );
1779 }
1780 $found_ids = array();
1781 while ($row = $ilDB->fetchAssoc($result)) {
1782 array_push($found_ids, $row['question_id']);
1783 }
1784 $nr_of_questions = ($nr_of_questions > count($found_ids)) ? count($found_ids) : $nr_of_questions;
1785 if ($nr_of_questions == 0) {
1786 return array();
1787 }
1788 $rand_keys = array_rand($found_ids, $nr_of_questions);
1789 $result = array();
1790 if (is_array($rand_keys)) {
1791 foreach ($rand_keys as $key) {
1792 $result[$found_ids[$key]] = $found_ids[$key];
1793 }
1794 } else {
1795 $result[$found_ids[$rand_keys]] = $found_ids[$rand_keys];
1796 }
1797 return $result;
1798 }
1799
1807 public function getNrOfResultsForPass($active_id, $pass)
1808 {
1809 global $DIC;
1810 $ilDB = $DIC['ilDB'];
1811
1812 $result = $ilDB->queryF(
1813 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1814 array('integer','integer'),
1815 array($active_id, $pass)
1816 );
1817 return $result->numRows();
1818 }
1819
1830 public function hasRandomQuestionsForPass($active_id, $pass)
1831 {
1832 global $DIC;
1833 $ilDB = $DIC['ilDB'];
1834 $result = $ilDB->queryF(
1835 "SELECT test_random_question_id FROM tst_test_rnd_qst WHERE active_fi = %s AND pass = %s",
1836 array('integer','integer'),
1837 array($active_id, $pass)
1838 );
1839 return ($result->numRows() > 0) ? true : false;
1840 }
1841
1845 public function loadFromDb()
1846 {
1847 global $DIC;
1848 $ilDB = $DIC['ilDB'];
1849
1850 $result = $ilDB->queryF(
1851 "SELECT * FROM tst_tests WHERE obj_fi = %s",
1852 array('integer'),
1853 array($this->getId())
1854 );
1855 if ($result->numRows() == 1) {
1856 $data = $ilDB->fetchObject($result);
1857 $this->setTestId($data->test_id);
1858 if (strlen($this->getAuthor()) == 0) {
1859 $this->saveAuthorToMetadata($data->author);
1860 }
1861 $this->setAuthor($data->author);
1862 include_once("./Services/RTE/classes/class.ilRTE.php");
1863 $this->setIntroductionEnabled($data->intro_enabled);
1865 $this->setShowInfo($data->showinfo);
1867 $this->setForceJS($data->forcejs);
1868 $this->setCustomStyle($data->customstyle);
1869 $this->setShowFinalStatement($data->showfinalstatement);
1870 $this->setSequenceSettings($data->sequence_settings);
1871 $this->setScoreReporting($data->score_reporting);
1872 $this->setInstantFeedbackSolution($data->instant_verification);
1873 $this->setAnswerFeedbackPoints($data->answer_feedback_points);
1874 $this->setAnswerFeedback($data->answer_feedback);
1875 $this->setAnonymity($data->anonymity);
1876 $this->setShowCancel($data->show_cancel);
1877 $this->setShowMarker($data->show_marker);
1878 $this->setFixedParticipants($data->fixed_participants);
1879 $this->setNrOfTries($data->nr_of_tries);
1880 $this->setBlockPassesAfterPassedEnabled((bool) $data->block_after_passed);
1881 $this->setKiosk($data->kiosk);
1882 $this->setUsePreviousAnswers($data->use_previous_answers);
1883 $this->setRedirectionMode($data->redirection_mode);
1884 $this->setRedirectionUrl($data->redirection_url);
1885 $this->setTitleOutput($data->title_output);
1886 $this->setProcessingTime($data->processing_time);
1887 $this->setEnableProcessingTime($data->enable_processing_time);
1888 $this->setResetProcessingTime($data->reset_processing_time);
1889 $this->setReportingDate($data->reporting_date);
1890 $this->setShuffleQuestions($data->shuffle_questions);
1891 $this->setResultsPresentation($data->results_presentation);
1892 $this->setStartingTimeEnabled($data->starting_time_enabled);
1893 $this->setStartingTime($data->starting_time);
1894 $this->setEndingTimeEnabled($data->ending_time_enabled);
1895 $this->setEndingTime($data->ending_time);
1896 $this->setListOfQuestionsSettings($data->show_summary);
1897 $this->setECTSOutput($data->ects_output);
1898 $this->setECTSGrades(
1899 array(
1900 "A" => $data->ects_a,
1901 "B" => $data->ects_b,
1902 "C" => $data->ects_c,
1903 "D" => $data->ects_d,
1904 "E" => $data->ects_e
1905 )
1906 );
1907 $this->setECTSFX($data->ects_fx);
1908 $this->mark_schema->flush();
1909 $this->mark_schema->loadFromDb($this->getTestId());
1910 $this->setCountSystem($data->count_system);
1911 $this->setMCScoring($data->mc_scoring);
1912 $this->setMailNotification($data->mailnotification);
1913 $this->setMailNotificationType($data->mailnottype);
1914 $this->setExportSettings($data->exportsettings);
1915 $this->setScoreCutting($data->score_cutting);
1916 $this->setPasswordEnabled($data->password_enabled);
1917 $this->setPassword($data->password);
1918 $this->setLimitUsersEnabled($data->limit_users_enabled);
1919 $this->setAllowedUsers($data->allowedusers);
1920 $this->setAllowedUsersTimeGap($data->alloweduserstimegap);
1921 $this->setPassScoring($data->pass_scoring);
1922 $this->setObligationsEnabled($data->obligations_enabled);
1923 $this->setOfferingQuestionHintsEnabled($data->offer_question_hints);
1924 $this->setCertificateVisibility($data->certificate_visibility);
1925 $this->setEnabledViewMode($data->enabled_view_mode);
1926 $this->setTemplate($data->template_id);
1927 $this->setPoolUsage($data->pool_usage);
1928 $this->setPrintBestSolutionWithResult((bool) $data->print_bs_with_res);
1929 $this->setHighscoreEnabled((bool) $data->highscore_enabled);
1930 $this->setHighscoreAnon((bool) $data->highscore_anon);
1931 $this->setHighscoreAchievedTS((bool) $data->highscore_achieved_ts);
1932 $this->setHighscoreScore((bool) $data->highscore_score);
1933 $this->setHighscorePercentage((bool) $data->highscore_percentage);
1934 $this->setHighscoreHints((bool) $data->highscore_hints);
1935 $this->setHighscoreWTime((bool) $data->highscore_wtime);
1936 $this->setHighscoreOwnTable((bool) $data->highscore_own_table);
1937 $this->setHighscoreTopTable((bool) $data->highscore_top_table);
1938 $this->setHighscoreTopNum((int) $data->highscore_top_num);
1939 $this->setOldOnlineStatus((bool) !$this->getOfflineStatus());
1940 $this->setSpecificAnswerFeedback((int) $data->specific_feedback);
1941 $this->setAutosave((bool) $data->autosave);
1942 $this->setAutosaveIval((int) $data->autosave_ival);
1943 $this->setPassDeletionAllowed($data->pass_deletion_allowed);
1944 $this->setEnableExamview((bool) $data->enable_examview);
1945 $this->setShowExamviewHtml((bool) $data->show_examview_html);
1946 $this->setShowExamviewPdf((bool) $data->show_examview_pdf);
1947 $this->setEnableArchiving((bool) $data->enable_archiving);
1948 $this->setShowExamIdInTestPassEnabled((bool) $data->examid_in_test_pass);
1949 $this->setShowExamIdInTestResultsEnabled((bool) $data->examid_in_test_res);
1950 $this->setSignSubmission((bool) $data->sign_submission);
1951 $this->setQuestionSetType($data->question_set_type);
1952 $this->setCharSelectorAvailability((int) $data->char_selector_availability);
1953 $this->setCharSelectorDefinition($data->char_selector_definition);
1954 $this->setSkillServiceEnabled((bool) $data->skill_service);
1955 $this->setResultFilterTaxIds(strlen($data->result_tax_filters) ? unserialize($data->result_tax_filters) : array());
1956 $this->setShowGradingStatusEnabled((bool) $data->show_grading_status);
1957 $this->setShowGradingMarkEnabled((bool) $data->show_grading_mark);
1958 $this->setFollowupQuestionAnswerFixationEnabled((bool) $data->follow_qst_answer_fixation);
1959 $this->setInstantFeedbackAnswerFixationEnabled((bool) $data->inst_fb_answer_fixation);
1960 $this->setForceInstantFeedbackEnabled((bool) $data->force_inst_fb);
1961 $this->setTestFinalBroken((bool) $data->broken);
1962 $this->setPassWaiting($data->pass_waiting);
1963 $this->loadQuestions();
1964 }
1965
1966 // moved activation to ilObjectActivation
1967 if ($this->ref_id) {
1968 include_once "./Services/Object/classes/class.ilObjectActivation.php";
1969 $activation = ilObjectActivation::getItem($this->ref_id);
1970 switch ($activation["timing_type"]) {
1972 $this->setActivationLimited(true);
1973 $this->setActivationStartingTime($activation["timing_start"]);
1974 $this->setActivationEndingTime($activation["timing_end"]);
1975 $this->setActivationVisibility($activation["visible"]);
1976 break;
1977
1978 default:
1979 $this->setActivationLimited(false);
1980 break;
1981 }
1982 }
1983 }
1984
1991 public function loadQuestions($active_id = "", $pass = null)
1992 {
1993 global $DIC;
1994 $ilUser = $DIC['ilUser'];
1995 $ilDB = $DIC['ilDB'];
1996
1997 $tags_trafo = $this->refinery->string()->stripTags();
1998
1999 $this->questions = array();
2000 if ($this->isRandomTest()) {
2001 if (strcmp($active_id, "") == 0) {
2002 $active_id = $this->getActiveIdOfUser($ilUser->getId());
2003 }
2004 if (is_null($pass)) {
2005 $pass = self::_getPass($active_id);
2006 }
2007 $result = $ilDB->queryF(
2008 "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",
2009 array('integer', 'integer'),
2010 array($active_id, $pass)
2011 );
2012 // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
2013 // is only one test pass (pass = 0) in tst_test_rnd_qst while with ILIAS 3.8 there are questions for every test pass.
2014 // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
2015 // no questions are present for a newer pass.
2016 if ($result->numRows() == 0) {
2017 $result = $ilDB->queryF(
2018 "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",
2019 array('integer'),
2020 array($active_id)
2021 );
2022 }
2023 } else {
2024 $result = $ilDB->queryF(
2025 "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",
2026 array('integer'),
2027 array($this->test_id)
2028 );
2029 }
2030 $index = 1;
2031 while ($data = $ilDB->fetchAssoc($result)) {
2032 $this->questions[$index++] = $data["question_fi"];
2033 }
2034 }
2035
2039 public function isIntroductionEnabled()
2040 {
2042 }
2043
2048 {
2049 $this->introductionEnabled = $introductionEnabled;
2050 }
2051
2058 public function getIntroduction()
2059 {
2060 return (strlen($this->introduction)) ? $this->introduction : null;
2061 }
2062
2070 public function setIntroduction($introduction = "")
2071 {
2072 if (is_null($introduction)) {
2073 $introduction = '';
2074 }
2075 $this->introduction = $this->getHtmlQuestionContentPurifier()->purify($introduction);
2076 }
2077
2078
2086 public function setFinalStatement($a_statement = "")
2087 {
2088 if (is_null($a_statement)) {
2089 $a_statement = '';
2090 }
2091 $this->_finalstatement = $this->getHtmlQuestionContentPurifier()->purify($a_statement);
2092 }
2093
2101 public function setShowInfo($a_info = 1)
2102 {
2103 $this->_showinfo = ($a_info) ? 1 : 0;
2104 }
2105
2113 public function setForceJS($a_js = 1)
2114 {
2115 $this->_forcejs = ($a_js) ? 1 : 0;
2116 }
2117
2125 public function setCustomStyle($a_customStyle = null)
2126 {
2127 $this->_customStyle = $a_customStyle;
2128 }
2129
2137 public function getCustomStyle()
2138 {
2139 return (strlen($this->_customStyle)) ? $this->_customStyle : null;
2140 }
2141
2142
2150 public function setShowFinalStatement($show = 0)
2151 {
2152 $this->_showfinalstatement = ($show) ? 1 : 0;
2153 }
2154
2161 public function getFinalStatement()
2162 {
2163 return (strlen($this->_finalstatement)) ? $this->_finalstatement : null;
2164 }
2165
2173 public function getShowInfo()
2174 {
2175 return ($this->_showinfo) ? 1 : 0;
2176 }
2177
2185 public function getForceJS()
2186 {
2187 return ($this->_forcejs) ? 1 : 0;
2188 }
2189
2197 public function getShowFinalStatement()
2198 {
2199 return ($this->_showfinalstatement) ? 1 : 0;
2200 }
2201
2209 public function getTestId()
2210 {
2211 return $this->test_id;
2212 }
2213
2217 public function getECTSOutput()
2218 {
2219 return ($this->ects_output) ? 1 : 0;
2220 }
2221
2225 public function setECTSOutput($a_ects_output)
2226 {
2227 $this->ects_output = $a_ects_output ? 1 : 0;
2228 }
2229
2233 public function getECTSFX()
2234 {
2235 return (strlen($this->ects_fx)) ? $this->ects_fx : null;
2236 }
2237
2241 public function setECTSFX($a_ects_fx)
2242 {
2243 $this->ects_fx = $a_ects_fx;
2244 }
2245
2249 public function getECTSGrades()
2250 {
2251 return $this->ects_grades;
2252 }
2253
2257 public function setECTSGrades(array $a_ects_grades)
2258 {
2259 $this->ects_grades = $a_ects_grades;
2260 }
2261
2267 public function getSequenceSettings()
2268 {
2269 return ($this->sequence_settings) ? $this->sequence_settings : 0;
2270 }
2271
2278 {
2279 $this->sequence_settings = $sequence_settings;
2280 }
2281
2285 public function isPostponingEnabled()
2286 {
2287 return (bool) $this->getSequenceSettings();
2288 }
2289
2293 public function setPostponingEnabled($postponingEnabled)
2294 {
2295 $this->setSequenceSettings((int) $postponingEnabled);
2296 }
2297
2306 {
2307 $this->score_reporting = $score_reporting;
2308 }
2309
2317 public function setInstantFeedbackSolution($instant_feedback = 0)
2318 {
2319 switch ($instant_feedback) {
2320 case 1:
2321 $this->instant_verification = 1;
2322 break;
2323 default:
2324 $this->instant_verification = 0;
2325 break;
2326 }
2327 }
2328
2337 {
2338 switch ($answer_feedback) {
2339 case 1:
2340 $this->answer_feedback = 1;
2341 break;
2342 default:
2343 $this->answer_feedback = 0;
2344 break;
2345 }
2346 }
2347
2353 public function setGenericAnswerFeedback($generic_answer_feedback = 0)
2354 {
2355 switch ($generic_answer_feedback) {
2356 case 1:
2357 $this->answer_feedback = 1;
2358 break;
2359 default:
2360 $this->answer_feedback = 0;
2361 break;
2362 }
2363 }
2364
2373 {
2374 switch ($answer_feedback_points) {
2375 case 1:
2376 $this->answer_feedback_points = 1;
2377 break;
2378 default:
2379 $this->answer_feedback_points = 0;
2380 break;
2381 }
2382 }
2383
2389 {
2390 if (!$reporting_date) {
2391 $this->reporting_date = '';
2392 $this->setECTSOutput(false);
2393 } else {
2394 $this->reporting_date = $reporting_date;
2395 }
2396 }
2397
2403
2411 public function getScoreReporting()
2412 {
2413 return ($this->score_reporting) ? $this->score_reporting : 0;
2414 }
2415
2416 public function isScoreReportingEnabled()
2417 {
2418 switch ($this->getScoreReporting()) {
2423
2424 return true;
2425
2427 default:
2428
2429 return false;
2430 }
2431 }
2432
2441 {
2442 return ($this->instant_verification) ? $this->instant_verification : 0;
2443 }
2444
2453 public function getAnswerFeedback()
2454 {
2455 return ($this->answer_feedback) ? $this->answer_feedback : 0;
2456 }
2457
2465 {
2466 return ($this->answer_feedback) ? $this->answer_feedback : 0;
2467 }
2468
2476 public function getAnswerFeedbackPoints()
2477 {
2478 return ($this->answer_feedback_points) ? $this->answer_feedback_points : 0;
2479 }
2480
2488 public function getCountSystem()
2489 {
2490 return ($this->count_system) ? $this->count_system : 0;
2491 }
2492
2500 public static function _getCountSystem($active_id)
2501 {
2502 global $DIC;
2503 $ilDB = $DIC['ilDB'];
2504 $result = $ilDB->queryF(
2505 "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",
2506 array('integer'),
2507 array($active_id)
2508 );
2509 if ($result->numRows()) {
2510 $row = $ilDB->fetchAssoc($result);
2511 return $row["count_system"];
2512 }
2513 return false;
2514 }
2515
2523 public function getMCScoring()
2524 {
2525 return ($this->mc_scoring) ? $this->mc_scoring : 0;
2526 }
2527
2535 public function getScoreCutting()
2536 {
2537 return ($this->score_cutting) ? $this->score_cutting : 0;
2538 }
2539
2547 public function getPassScoring()
2548 {
2549 return ($this->pass_scoring) ? $this->pass_scoring : 0;
2550 }
2551
2559 public static function _getPassScoring($active_id)
2560 {
2561 global $DIC;
2562 $ilDB = $DIC['ilDB'];
2563 $result = $ilDB->queryF(
2564 "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",
2565 array('integer'),
2566 array($active_id)
2567 );
2568 if ($result->numRows()) {
2569 $row = $ilDB->fetchAssoc($result);
2570 return $row["pass_scoring"];
2571 }
2572 return 0;
2573 }
2574
2582 public static function _getMCScoring($active_id)
2583 {
2584 global $DIC;
2585 $ilDB = $DIC['ilDB'];
2586 $result = $ilDB->queryF(
2587 "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",
2588 array('integer'),
2589 array($active_id)
2590 );
2591 if ($result->numRows()) {
2592 $row = $ilDB->fetchAssoc($result);
2593 return $row["mc_scoring"];
2594 }
2595 return false;
2596 }
2597
2605 public static function _getScoreCutting($active_id)
2606 {
2607 global $DIC;
2608 $ilDB = $DIC['ilDB'];
2609 $result = $ilDB->queryF(
2610 "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",
2611 array('integer'),
2612 array($active_id)
2613 );
2614 if ($result->numRows()) {
2615 $row = $ilDB->fetchAssoc($result);
2616 return $row["score_cutting"];
2617 }
2618 return false;
2619 }
2620
2628 public function getReportingDate()
2629 {
2630 return (strlen($this->reporting_date)) ? $this->reporting_date : null;
2631 }
2632
2640 public function getNrOfTries()
2641 {
2642 return ($this->nr_of_tries) ? $this->nr_of_tries : 0;
2643 }
2644
2649 {
2651 }
2652
2657 {
2658 $this->blockPassesAfterPassedEnabled = $blockPassesAfterPassedEnabled;
2659 }
2660
2668 public function getKiosk()
2669 {
2670 return ($this->_kiosk) ? $this->_kiosk : 0;
2671 }
2672
2673
2681 public function setKiosk($kiosk = 0)
2682 {
2683 $this->_kiosk = $kiosk;
2684 }
2685
2693 public function getKioskMode()
2694 {
2695 if (($this->_kiosk & 1) > 0) {
2696 return true;
2697 } else {
2698 return false;
2699 }
2700 }
2701
2709 public function setKioskMode($a_kiosk = false)
2710 {
2711 if ($a_kiosk) {
2712 $this->_kiosk = $this->_kiosk | 1;
2713 } else {
2714 if ($this->getKioskMode()) {
2715 $this->_kiosk = $this->_kiosk ^ 1;
2716 }
2717 }
2718 }
2719
2727 public function getShowKioskModeTitle()
2728 {
2729 if (($this->_kiosk & 2) > 0) {
2730 return true;
2731 } else {
2732 return false;
2733 }
2734 }
2735
2742 public function setShowKioskModeTitle($a_title = false)
2743 {
2744 if ($a_title) {
2745 $this->_kiosk = $this->_kiosk | 2;
2746 } else {
2747 if ($this->getShowKioskModeTitle()) {
2748 $this->_kiosk = $this->_kiosk ^ 2;
2749 }
2750 }
2751 }
2752
2761 {
2762 if (($this->_kiosk & 4) > 0) {
2763 return true;
2764 } else {
2765 return false;
2766 }
2767 }
2768
2775 public function setShowKioskModeParticipant($a_participant = false)
2776 {
2777 if ($a_participant) {
2778 $this->_kiosk = $this->_kiosk | 4;
2779 } else {
2780 if ($this->getShowKioskModeParticipant()) {
2781 $this->_kiosk = $this->_kiosk ^ 4;
2782 }
2783 }
2784 }
2785
2793 public function getUsePreviousAnswers()
2794 {
2795 return ($this->use_previous_answers) ? $this->use_previous_answers : 0;
2796 }
2797
2805 public function getTitleOutput()
2806 {
2807 return ($this->title_output) ? $this->title_output : 0;
2808 }
2809
2818 public function _getTitleOutput($active_id)
2819 {
2820 global $DIC;
2821 $ilDB = $DIC['ilDB'];
2822
2823 $result = $ilDB->queryF(
2824 "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",
2825 array('integer'),
2826 array($active_id)
2827 );
2828 if ($result->numRows()) {
2829 $row = $ilDB->fetchAssoc($result);
2830 return $row["title_output"];
2831 }
2832 return 0;
2833 }
2834
2835 // hey: prevPassSolutions - serious (nonstatic) identifier, for use in high level controller gui
2836 public function isPreviousSolutionReuseEnabled($activeId)
2837 {
2838 // checks if allowed in general and if enabled by participant
2839 return self::_getUsePreviousAnswers($activeId, true);
2840 }
2841 // hey.
2842
2852 public static function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
2853 {
2854 global $DIC;
2855 $ilDB = $DIC['ilDB'];
2856 $ilUser = $DIC['ilUser'];
2857
2859
2860 $result = $ilDB->queryF(
2861 "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",
2862 array("integer"),
2863 array($active_id)
2864 );
2865 if ($result->numRows()) {
2866 $row = $ilDB->fetchAssoc($result);
2867 $use_previous_answers = $row["use_previous_answers"];
2868 }
2869
2870 if ($use_previous_answers == 1) {
2871 if ($user_active_user_setting) {
2872 $res = $ilUser->getPref("tst_use_previous_answers");
2873 if ($res !== false) {
2875 }
2876 }
2877 }
2878 return $use_previous_answers;
2879 }
2880
2888 public function getProcessingTime()
2889 {
2890 return (strlen($this->processing_time)) ? $this->processing_time : null;
2891 }
2892
2900 {
2901 if (strlen($this->processing_time)) {
2902 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2903 if ((int) $matches[1] + (int) $matches[2] + (int) $matches[3] == 0) {
2904 return $this->getEstimatedWorkingTime();
2905 } else {
2906 return array(
2907 'hh' => $matches[1],
2908 'mm' => $matches[2],
2909 'ss' => $matches[3],
2910 );
2911 }
2912 }
2913 }
2914 return $this->getEstimatedWorkingTime();
2915 }
2916
2918 {
2919 if (strlen($this->processing_time)) {
2920 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2921 return ($matches[1] * 60) + $matches[2];
2922 }
2923 }
2924
2926 }
2927
2935 public function getProcessingTimeInSeconds($active_id = "")
2936 {
2937 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches)) {
2938 $extratime = $this->getExtraTime($active_id) * 60;
2939 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
2940 } else {
2941 return 0;
2942 }
2943 }
2944
2953 {
2954 if ($this->getEndingTime() != 0) {
2955 $ending = $this->getEndingTime();
2956 $now = time();
2957 return $ending - $now;
2958 } else {
2959 return 0;
2960 }
2961 }
2962
2970 public function getEnableProcessingTime()
2971 {
2972 return ($this->enable_processing_time) ? $this->enable_processing_time : 0;
2973 }
2974
2982 public function getResetProcessingTime()
2983 {
2984 return ($this->reset_processing_time) ? $this->reset_processing_time : 0;
2985 }
2986
2990 public function isStartingTimeEnabled()
2991 {
2993 }
2994
2999 {
3000 $this->starting_time_enabled = $starting_time_enabled;
3001 }
3002
3010 public function getStartingTime()
3011 {
3012 return ($this->starting_time != 0) ? $this->starting_time : 0;
3013 }
3014
3022 public function setStartingTime($starting_time = null)
3023 {
3024 $this->starting_time = $starting_time;
3025 }
3026
3030 public function isEndingTimeEnabled()
3031 {
3033 }
3034
3039 {
3040 $this->ending_time_enabled = $ending_time_enabled;
3041 }
3042
3050 public function getEndingTime()
3051 {
3052 return ($this->ending_time != 0) ? $this->ending_time : 0;
3053 }
3054
3062 public function setEndingTime($ending_time = null)
3063 {
3064 $this->ending_time = $ending_time;
3065 }
3066
3074 public function setNrOfTries($nr_of_tries = 0)
3075 {
3076 $this->nr_of_tries = $nr_of_tries;
3077 }
3078
3087 {
3089 $this->use_previous_answers = 1;
3090 } else {
3091 $this->use_previous_answers = 0;
3092 }
3093 }
3094
3096 {
3097 $this->redirection_mode = $redirection_mode;
3098 }
3099 public function getRedirectionMode()
3100 {
3102 }
3103 public function setRedirectionUrl($redirection_url = null)
3104 {
3105 $this->redirection_url = $redirection_url;
3106 }
3107 public function getRedirectionUrl()
3108 {
3110 }
3111
3119 public function setTitleOutput($title_output = 0)
3120 {
3121 switch ($title_output) {
3122 case 1:
3123 $this->title_output = 1;
3124 break;
3125 case 2:
3126 $this->title_output = 2;
3127 break;
3128 default:
3129 $this->title_output = 0;
3130 break;
3131 }
3132 }
3133
3141 public function setProcessingTime($processing_time = "00:00:00")
3142 {
3143 $this->processing_time = $processing_time;
3144 }
3145
3146 public function setProcessingTimeByMinutes($minutes)
3147 {
3148 $this->processing_time = sprintf("%02d:%02d:00", floor($minutes / 60), $minutes % 60);
3149 }
3150
3158 public function setEnableProcessingTime($enable = 0)
3159 {
3160 if ($enable) {
3161 $this->enable_processing_time = "1";
3162 } else {
3163 $this->enable_processing_time = "0";
3164 }
3165 }
3166
3174 public function setResetProcessingTime($reset = 0)
3175 {
3176 if ($reset) {
3177 $this->reset_processing_time = 1;
3178 } else {
3179 $this->reset_processing_time = 0;
3180 }
3181 }
3182
3190 public function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3191 {
3192 $this->count_system = $a_count_system;
3193 }
3194
3198 public function isPasswordEnabled()
3199 {
3201 }
3202
3207 {
3208 $this->passwordEnabled = $passwordEnabled;
3209 }
3210
3218 public function getPassword()
3219 {
3220 return (strlen($this->password)) ? $this->password : null;
3221 }
3222
3230 public function setPassword($a_password = null)
3231 {
3232 $this->password = $a_password;
3233 }
3234
3242 public function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3243 {
3244 $this->score_cutting = $a_score_cutting;
3245 }
3246
3254 public function setMCScoring($a_mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED)
3255 {
3256 $this->mc_scoring = $a_mc_scoring;
3257 }
3258
3266 public function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3267 {
3268 switch ($a_pass_scoring) {
3269 case SCORE_BEST_PASS:
3270 $this->pass_scoring = SCORE_BEST_PASS;
3271 break;
3272 default:
3273 $this->pass_scoring = SCORE_LAST_PASS;
3274 break;
3275 }
3276 }
3277
3281 public function getPassWaiting()
3282 {
3283 return $this->pass_waiting;
3284 }
3285
3290 {
3291 $this->pass_waiting = $pass_waiting;
3292 }
3296 public function isPassWaitingEnabled()
3297 {
3298 if (array_sum(explode(':', $this->getPassWaiting())) > 0) {
3299 return true;
3300 }
3301 return false;
3302 }
3303
3309 public function removeQuestionFromSequences($questionId, $activeIds, ilTestReindexedSequencePositionMap $reindexedSequencePositionMap)
3310 {
3311 global $DIC; /* @var ILIAS\DI\Container $DIC */
3312
3313 $testSequenceFactory = new ilTestSequenceFactory(
3314 $DIC->database(),
3315 $DIC->language(),
3316 $DIC['refinery'],
3317 $DIC['ilPluginAdmin'],
3318 $this
3319 );
3320
3321 foreach ($activeIds as $activeId) {
3322 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
3323 $passSelector->setActiveId($activeId);
3324
3325 foreach ($passSelector->getExistingPasses() as $pass) {
3326 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $pass);
3327 $testSequence->loadFromDb();
3328
3329 $testSequence->removeQuestion($questionId, $reindexedSequencePositionMap);
3330 $testSequence->saveToDb();
3331 }
3332 }
3333 }
3334
3338 public function removeQuestions($removeQuestionIds)
3339 {
3340 foreach ($removeQuestionIds as $value) {
3341 $this->removeQuestion($value);
3342 }
3343
3345 }
3346
3354 public function removeQuestion($question_id)
3355 {
3356 $question = &ilObjTest::_instanciateQuestion($question_id);
3357 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3359 $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3360 }
3361 $question->delete($question_id);
3362 }
3363
3373 {
3374 $this->removeTestResultsByUserIds($userIds);
3375
3376 global $DIC;
3377 $ilDB = $DIC['ilDB'];
3378 $lng = $DIC['lng'];
3379
3380 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3381 $participantData = new ilTestParticipantData($ilDB, $lng);
3382 $participantData->setUserIdsFilter($userIds);
3383 $participantData->load($this->getTestId());
3384
3385 $this->removeTestActives($participantData->getActiveIds());
3386 }
3387
3388 public function removeTestResults(ilTestParticipantData $participantData)
3389 {
3390 if (count($participantData->getAnonymousActiveIds())) {
3391 $this->removeTestResultsByActiveIds($participantData->getAnonymousActiveIds());
3392 }
3393
3394 if (count($participantData->getUserIds())) {
3395 /* @var ilTestLP $testLP */
3396 require_once 'Services/Object/classes/class.ilObjectLP.php';
3397 $testLP = ilObjectLP::getInstance($this->getId());
3398 $testLP->setTestObject($this);
3399 $testLP->resetLPDataForUserIds($participantData->getUserIds(), false);
3400 }
3401
3402 if (count($participantData->getActiveIds())) {
3403 $this->removeTestActives($participantData->getActiveIds());
3404 }
3405 }
3406
3407 public function removeTestResultsByUserIds($userIds)
3408 {
3409 global $DIC;
3410 $ilDB = $DIC['ilDB'];
3411 $lng = $DIC['lng'];
3412
3413 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3414 $participantData = new ilTestParticipantData($ilDB, $lng);
3415 $participantData->setUserIdsFilter($userIds);
3416 $participantData->load($this->getTestId());
3417
3418 $IN_userIds = $ilDB->in('usr_id', $participantData->getUserIds(), false, 'integer');
3419 $ilDB->manipulateF(
3420 "DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
3421 array('text'),
3422 array("tst_password_" . $this->getTestId())
3423 );
3424
3425 if (count($participantData->getActiveIds())) {
3426 $this->removeTestResultsByActiveIds($participantData->getActiveIds());
3427 }
3428 }
3429
3430 public function removeTestResultsByActiveIds($activeIds)
3431 {
3432 global $DIC;
3433 $ilDB = $DIC['ilDB'];
3434
3435 $IN_activeIds = $ilDB->in('active_fi', $activeIds, false, 'integer');
3436
3437 $ilDB->manipulate("DELETE FROM tst_solutions WHERE $IN_activeIds");
3438 $ilDB->manipulate("DELETE FROM tst_qst_solved WHERE $IN_activeIds");
3439 $ilDB->manipulate("DELETE FROM tst_test_result WHERE $IN_activeIds");
3440 $ilDB->manipulate("DELETE FROM tst_pass_result WHERE $IN_activeIds");
3441 $ilDB->manipulate("DELETE FROM tst_result_cache WHERE $IN_activeIds");
3442 $ilDB->manipulate("DELETE FROM tst_sequence WHERE $IN_activeIds");
3443 $ilDB->manipulate("DELETE FROM tst_times WHERE $IN_activeIds");
3444
3445 if ($this->isRandomTest()) {
3446 $ilDB->manipulate("DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
3447 } elseif ($this->isDynamicTest()) {
3448 $ilDB->manipulate("DELETE FROM tst_seq_qst_tracking WHERE $IN_activeIds");
3449 $ilDB->manipulate("DELETE FROM tst_seq_qst_answstatus WHERE $IN_activeIds");
3450 $ilDB->manipulate("DELETE FROM tst_seq_qst_postponed WHERE $IN_activeIds");
3451 $ilDB->manipulate("DELETE FROM tst_seq_qst_checked WHERE $IN_activeIds");
3452 }
3453
3454 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3455
3456 foreach ($activeIds as $active_id) {
3457 // remove file uploads
3458 if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id")) {
3459 ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3460 }
3461
3463 $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3464 }
3465 }
3466
3467 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3469 }
3470
3471 public function removeTestActives($activeIds)
3472 {
3473 global $DIC;
3474 $ilDB = $DIC['ilDB'];
3475
3476 $IN_activeIds = $ilDB->in('active_id', $activeIds, false, 'integer');
3477 $ilDB->manipulate("DELETE FROM tst_active WHERE $IN_activeIds");
3478 }
3479
3487 public function questionMoveUp($question_id)
3488 {
3489 global $DIC;
3490 $ilDB = $DIC['ilDB'];
3491
3492 // Move a question up in sequence
3493 $result = $ilDB->queryF(
3494 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3495 array('integer', 'integer'),
3496 array($this->getTestId(), $question_id)
3497 );
3498 $data = $ilDB->fetchObject($result);
3499 if ($data->sequence > 1) {
3500 // OK, it's not the top question, so move it up
3501 $result = $ilDB->queryF(
3502 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3503 array('integer','integer'),
3504 array($this->getTestId(), $data->sequence - 1)
3505 );
3506 $data_previous = $ilDB->fetchObject($result);
3507 // change previous dataset
3508 $affectedRows = $ilDB->manipulateF(
3509 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3510 array('integer','integer'),
3511 array($data->sequence, $data_previous->test_question_id)
3512 );
3513 // move actual dataset up
3514 $affectedRows = $ilDB->manipulateF(
3515 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3516 array('integer','integer'),
3517 array($data->sequence - 1, $data->test_question_id)
3518 );
3519 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3521 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence - 1), $question_id);
3522 }
3523 }
3524 $this->loadQuestions();
3525 }
3526
3534 public function questionMoveDown($question_id)
3535 {
3536 global $DIC;
3537 $ilDB = $DIC['ilDB'];
3538
3539 // Move a question down in sequence
3540 $result = $ilDB->queryF(
3541 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3542 array('integer','integer'),
3543 array($this->getTestId(), $question_id)
3544 );
3545 $data = $ilDB->fetchObject($result);
3546 $result = $ilDB->queryF(
3547 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3548 array('integer','integer'),
3549 array($this->getTestId(), $data->sequence + 1)
3550 );
3551 if ($result->numRows() == 1) {
3552 // OK, it's not the last question, so move it down
3553 $data_next = $ilDB->fetchObject($result);
3554 // change next dataset
3555 $affectedRows = $ilDB->manipulateF(
3556 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3557 array('integer','integer'),
3558 array($data->sequence, $data_next->test_question_id)
3559 );
3560 // move actual dataset down
3561 $affectedRows = $ilDB->manipulateF(
3562 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3563 array('integer','integer'),
3564 array($data->sequence + 1, $data->test_question_id)
3565 );
3566 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3568 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence + 1), $question_id);
3569 }
3570 }
3571 $this->loadQuestions();
3572 }
3573
3581 public function duplicateQuestionForTest($question_id)
3582 {
3583 global $DIC;
3584 $ilUser = $DIC['ilUser'];
3585 $question = &ilObjTest::_instanciateQuestion($question_id);
3586 $duplicate_id = $question->duplicate(true, null, null, null, $this->getId());
3587
3588 return $duplicate_id;
3589 }
3590
3599 public function insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly = false)
3600 {
3601 global $DIC;
3602 $ilDB = $DIC['ilDB'];
3603 if ($linkOnly) {
3604 $duplicate_id = $question_id;
3605 } else {
3606 $duplicate_id = $this->duplicateQuestionForTest($question_id);
3607 }
3608
3609 // get maximum sequence index in test
3610 $result = $ilDB->queryF(
3611 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
3612 array('integer'),
3613 array($this->getTestId())
3614 );
3615 $sequence = 1;
3616
3617 if ($result->numRows() == 1) {
3618 $data = $ilDB->fetchObject($result);
3619 $sequence = $data->seq + 1;
3620 }
3621
3622 $next_id = $ilDB->nextId('tst_test_question');
3623 $affectedRows = $ilDB->manipulateF(
3624 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
3625 array('integer', 'integer','integer','integer','integer'),
3626 array($next_id, $this->getTestId(), $duplicate_id, $sequence, time())
3627 );
3628 if ($affectedRows == 1) {
3629 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3631 $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3632 }
3633 }
3634 // remove test_active entries, because test has changed
3635 $affectedRows = $ilDB->manipulateF(
3636 "DELETE FROM tst_active WHERE test_fi = %s",
3637 array('integer'),
3638 array($this->getTestId())
3639 );
3640 $this->loadQuestions();
3641 $this->saveCompleteStatus($testQuestionSetConfig);
3642 return $duplicate_id;
3643 }
3644
3652 public function &getQuestionTitles()
3653 {
3654 $titles = array();
3655 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3656 global $DIC;
3657 $ilDB = $DIC['ilDB'];
3658 $result = $ilDB->queryF(
3659 "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",
3660 array('integer'),
3661 array($this->getTestId())
3662 );
3663 while ($row = $ilDB->fetchAssoc($result)) {
3664 array_push($titles, $row["title"]);
3665 }
3666 }
3667 return $titles;
3668 }
3669
3678 {
3679 $titles = array();
3680 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3681 global $DIC;
3682 $ilDB = $DIC['ilDB'];
3683 $result = $ilDB->queryF(
3684 "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",
3685 array('integer'),
3686 array($this->getTestId())
3687 );
3688 while ($row = $ilDB->fetchAssoc($result)) {
3689 $titles[$row['question_id']] = $row["title"];
3690 }
3691 }
3692 return $titles;
3693 }
3694
3695 // fau: testNav - add number parameter (to show if title should not be shown)
3705 public function getQuestionTitle($title, $nr = null)
3706 {
3707 if ($this->getTitleOutput() == 2) {
3708 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC) {
3709 // avoid legacy setting combination: ctm without question titles
3710 return $title;
3711 } elseif (isset($nr)) {
3712 return $this->lng->txt("ass_question") . ' ' . $nr;
3713 } else {
3714 return $this->lng->txt("ass_question");
3715 }
3716 } else {
3717 return $title;
3718 }
3719 }
3720 // fau.
3721
3730 public function getQuestionDataset($question_id)
3731 {
3732 global $DIC;
3733 $ilDB = $DIC['ilDB'];
3734
3735 $result = $ilDB->queryF(
3736 "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",
3737 array('integer'),
3738 array($question_id)
3739 );
3740 $row = $ilDB->fetchObject($result);
3741 return $row;
3742 }
3743
3750 public function &getExistingQuestions($pass = null)
3751 {
3752 global $DIC;
3753 $ilUser = $DIC['ilUser'];
3754 $ilDB = $DIC['ilDB'];
3755
3756 $existing_questions = array();
3757 $active_id = $this->getActiveIdOfUser($ilUser->getId());
3758 if ($this->isRandomTest()) {
3759 if (is_null($pass)) {
3760 $pass = 0;
3761 }
3762 $result = $ilDB->queryF(
3763 "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",
3764 array('integer','integer'),
3765 array($active_id, $pass)
3766 );
3767 } else {
3768 $result = $ilDB->queryF(
3769 "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",
3770 array('integer'),
3771 array($this->getTestId())
3772 );
3773 }
3774 while ($data = $ilDB->fetchObject($result)) {
3775 if ($data->original_id === null) {
3776 continue;
3777 }
3778
3779 array_push($existing_questions, $data->original_id);
3780 }
3781 return $existing_questions;
3782 }
3783
3791 public function getQuestionType($question_id)
3792 {
3793 global $DIC;
3794 $ilDB = $DIC['ilDB'];
3795
3796 if ($question_id < 1) {
3797 return -1;
3798 }
3799 $result = $ilDB->queryF(
3800 "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",
3801 array('integer'),
3802 array($question_id)
3803 );
3804 if ($result->numRows() == 1) {
3805 $data = $ilDB->fetchObject($result);
3806 return $data->type_tag;
3807 } else {
3808 return "";
3809 }
3810 }
3811
3818 public function startWorkingTime($active_id, $pass)
3819 {
3820 global $DIC;
3821 $ilDB = $DIC['ilDB'];
3822
3823 $next_id = $ilDB->nextId('tst_times');
3824 $affectedRows = $ilDB->manipulateF(
3825 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
3826 array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'),
3827 array($next_id, $active_id, strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"), $pass, time())
3828 );
3829 return $next_id;
3830 }
3831
3838 public function updateWorkingTime($times_id)
3839 {
3840 global $DIC;
3841 $ilDB = $DIC['ilDB'];
3842
3843 $affectedRows = $ilDB->manipulateF(
3844 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
3845 array('timestamp', 'integer', 'integer'),
3846 array(strftime("%Y-%m-%d %H:%M:%S"), time(), $times_id)
3847 );
3848 }
3849
3856 public function &getWorkedQuestions($active_id, $pass = null)
3857 {
3858 global $DIC;
3859 $ilUser = $DIC['ilUser'];
3860 $ilDB = $DIC['ilDB'];
3861
3862 if (is_null($pass)) {
3863 $result = $ilDB->queryF(
3864 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3865 array('integer','integer'),
3866 array($active_id, 0)
3867 );
3868 } else {
3869 $result = $ilDB->queryF(
3870 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3871 array('integer','integer'),
3872 array($active_id, $pass)
3873 );
3874 }
3875 $result_array = array();
3876 while ($row = $ilDB->fetchAssoc($result)) {
3877 array_push($result_array, $row["question_fi"]);
3878 }
3879 return $result_array;
3880 }
3881
3890 public function isTestFinishedToViewResults($active_id, $currentpass)
3891 {
3892 $num = ilObjTest::lookupPassResultsUpdateTimestamp($active_id, $currentpass);
3893 return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ? true : false;
3894 }
3895
3902 public function &getAllQuestions($pass = null)
3903 {
3904 global $DIC;
3905 $ilUser = $DIC['ilUser'];
3906 $ilDB = $DIC['ilDB'];
3907
3908 $result_array = array();
3909 if ($this->isRandomTest()) {
3910 $active_id = $this->getActiveIdOfUser($ilUser->getId());
3911 $this->loadQuestions($active_id, $pass);
3912 if (count($this->questions) == 0) {
3913 return $result_array;
3914 }
3915 if (is_null($pass)) {
3916 $pass = self::_getPass($active_id);
3917 }
3918 $result = $ilDB->queryF(
3919 "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'),
3920 array('integer','integer'),
3921 array($active_id, $pass)
3922 );
3923 } else {
3924 if (count($this->questions) == 0) {
3925 return $result_array;
3926 }
3927 $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'));
3928 }
3929 while ($row = $ilDB->fetchAssoc($result)) {
3930 $result_array[$row["question_id"]] = $row;
3931 }
3932 return $result_array;
3933 }
3934
3943 public function getActiveIdOfUser($user_id = "", $anonymous_id = "")
3944 {
3945 global $DIC;
3946 $ilDB = $DIC['ilDB'];
3947 $ilUser = $DIC['ilUser'];
3948
3949 if (!$user_id) {
3950 $user_id = $ilUser->getId();
3951 }
3952 if (($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()]))) {
3953 $result = $ilDB->queryF(
3954 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3955 array('integer','integer','text'),
3956 array($user_id, $this->test_id, $_SESSION["tst_access_code"][$this->getTestId()])
3957 );
3958 } elseif (strlen($anonymous_id)) {
3959 $result = $ilDB->queryF(
3960 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3961 array('integer','integer','text'),
3962 array($user_id, $this->test_id, $anonymous_id)
3963 );
3964 } else {
3965 if ($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) {
3966 return null;
3967 }
3968 $result = $ilDB->queryF(
3969 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
3970 array('integer','integer'),
3971 array($user_id, $this->test_id)
3972 );
3973 }
3974 if ($result->numRows()) {
3975 $row = $ilDB->fetchAssoc($result);
3976 return $row["active_id"];
3977 } else {
3978 return 0;
3979 }
3980 }
3981
3990 public static function _getActiveIdOfUser($user_id = "", $test_id = "")
3991 {
3992 global $DIC;
3993 $ilDB = $DIC['ilDB'];
3994 $ilUser = $DIC['ilUser'];
3995
3996 if (!$user_id) {
3997 $user_id = $ilUser->id;
3998 }
3999 if (!$test_id) {
4000 return "";
4001 }
4002 $result = $ilDB->queryF(
4003 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4004 array('integer', 'integer'),
4005 array($user_id, $test_id)
4006 );
4007 if ($result->numRows()) {
4008 $row = $ilDB->fetchAssoc($result);
4009 return $row["active_id"];
4010 } else {
4011 return "";
4012 }
4013 }
4014
4021 public function pcArrayShuffle($array)
4022 {
4023 $keys = array_keys($array);
4024 shuffle($keys);
4025 $result = array();
4026 foreach ($keys as $key) {
4027 $result[$key] = $array[$key];
4028 }
4029 return $result;
4030 }
4031
4039 public function &getTestResult($active_id, $pass = null, $ordered_sequence = false, $considerHiddenQuestions = true, $considerOptionalQuestions = true)
4040 {
4041 global $DIC;
4042 $tree = $DIC['tree'];
4043 $ilDB = $DIC['ilDB'];
4044 $lng = $DIC['lng'];
4045 $refinery = $DIC['refinery'];
4046 $ilPluginAdmin = $DIC['ilPluginAdmin'];
4047
4048 $results = $this->getResultsForActiveId($active_id);
4049
4050 if ($pass === null) {
4051 $pass = $results['pass'];
4052 }
4053
4054 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
4055 $testSessionFactory = new ilTestSessionFactory($this);
4056 $testSession = $testSessionFactory->getSession($active_id);
4057
4058 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4059 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $refinery, $ilPluginAdmin, $this);
4060 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $pass);
4061
4062 if ($this->isDynamicTest()) {
4063 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4064 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
4065 $dynamicQuestionSetConfig->loadFromDb();
4066
4067 $testSequence->loadFromDb($dynamicQuestionSetConfig);
4068 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4069
4070 $sequence = $testSequence->getUserSequenceQuestions();
4071 } else {
4072 $testSequence->setConsiderHiddenQuestionsEnabled($considerHiddenQuestions);
4073 $testSequence->setConsiderOptionalQuestionsEnabled($considerOptionalQuestions);
4074
4075 $testSequence->loadFromDb();
4076 $testSequence->loadQuestions();
4077
4078 if ($ordered_sequence) {
4079 $sequence = $testSequence->getOrderedSequenceQuestions();
4080 } else {
4081 $sequence = $testSequence->getUserSequenceQuestions();
4082 }
4083 }
4084
4085 $arrResults = [];
4086
4087 $query = "
4088 SELECT tst_test_result.question_fi,
4089 tst_test_result.points reached,
4090 tst_test_result.hint_count requested_hints,
4091 tst_test_result.hint_points hint_points,
4092 tst_test_result.answered answered
4093
4094 FROM tst_test_result
4095
4096 LEFT JOIN tst_solutions
4097 ON tst_solutions.active_fi = tst_test_result.active_fi
4098 AND tst_solutions.question_fi = tst_test_result.question_fi
4099
4100 WHERE tst_test_result.active_fi = %s
4101 AND tst_test_result.pass = %s
4102 ";
4103
4104 $solutionresult = $ilDB->queryF(
4105 $query,
4106 array('integer', 'integer'),
4107 array($active_id, $pass)
4108 );
4109
4110 while ($row = $ilDB->fetchAssoc($solutionresult)) {
4111 $arrResults[ $row['question_fi'] ] = $row;
4112 }
4113
4114 $numWorkedThrough = count($arrResults);
4115
4116 require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4117
4118 $IN_question_ids = $ilDB->in('qpl_questions.question_id', $sequence, false, 'integer');
4119
4120 $query = "
4121 SELECT qpl_questions.*,
4122 qpl_qst_type.type_tag,
4123 qpl_sol_sug.question_fi has_sug_sol
4124
4125 FROM qpl_qst_type,
4126 qpl_questions
4127
4128 LEFT JOIN qpl_sol_sug
4129 ON qpl_sol_sug.question_fi = qpl_questions.question_id
4130
4131 WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi
4132 AND $IN_question_ids
4133 ";
4134
4135 $result = $ilDB->query($query);
4136
4137 $unordered = [];
4138
4139 $key = 1;
4140
4141 $obligationsAnswered = true;
4142
4143 while ($row = $ilDB->fetchAssoc($result)) {
4144 $percentvalue = (
4145 $row['points'] ? $arrResults[ $row['question_id'] ]['reached'] / $row['points'] : 0
4146 );
4147
4148 if ($percentvalue < 0) {
4149 $percentvalue = 0.0;
4150 }
4151
4152 $data = array(
4153 "nr" => "$key",
4154 "title" => ilUtil::prepareFormOutput($row['title']),
4155 "max" => round($row['points'], 2),
4156 "reached" => round($arrResults[$row['question_id']]['reached'], 2),
4157 'requested_hints' => $arrResults[$row['question_id']]['requested_hints'],
4158 'hint_points' => $arrResults[$row['question_id']]['hint_points'],
4159 "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4160 "solution" => ($row['has_sug_sol']) ? assQuestion::_getSuggestedSolutionOutput($row['question_id']) : '',
4161 "type" => $row["type_tag"],
4162 "qid" => $row['question_id'],
4163 "original_id" => $row["original_id"],
4164 "workedthrough" => isset($arrResults[$row['question_id']]) ? 1 : 0,
4165 'answered' => $arrResults[$row['question_id']]['answered']
4166 );
4167
4168 if (!$arrResults[ $row['question_id'] ]['answered']) {
4169 $obligationsAnswered = false;
4170 }
4171
4172 $unordered[ $row['question_id'] ] = $data;
4173
4174 $key++;
4175 }
4176
4177 $numQuestionsTotal = count($unordered);
4178
4179 $pass_max = 0;
4180 $pass_reached = 0;
4181 $pass_requested_hints = 0;
4182 $pass_hint_points = 0;
4183 $key = 1;
4184
4185 $found = [];
4186
4187 foreach ($sequence as $qid) {
4188 // building pass point sums based on prepared data
4189 // for question that exists in users qst sequence
4190 $pass_max += round($unordered[$qid]['max'], 2);
4191 $pass_reached += round($unordered[$qid]['reached'], 2);
4192 $pass_requested_hints += $unordered[$qid]['requested_hints'];
4193 $pass_hint_points += $unordered[$qid]['hint_points'];
4194
4195 // pickup prepared data for question
4196 // that exists in users qst sequence
4197 $unordered[$qid]['nr'] = $key;
4198 array_push($found, $unordered[$qid]);
4199
4200 // increment key counter
4201 $key++;
4202 }
4203
4204 $unordered = null;
4205
4206 if ($this->getScoreCutting() == 1) {
4207 if ($results['reached_points'] < 0) {
4208 $results['reached_points'] = 0;
4209 }
4210
4211 if ($pass_reached < 0) {
4212 $pass_reached = 0;
4213 }
4214 }
4215
4216 $found['pass']['total_max_points'] = $pass_max;
4217 $found['pass']['total_reached_points'] = $pass_reached;
4218 $found['pass']['total_requested_hints'] = $pass_requested_hints;
4219 $found['pass']['total_hint_points'] = $pass_hint_points;
4220 $found['pass']['percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
4221 $found['pass']['obligationsAnswered'] = $obligationsAnswered;
4222 $found['pass']['num_workedthrough'] = $numWorkedThrough;
4223 $found['pass']['num_questions_total'] = $numQuestionsTotal;
4224
4225 $found["test"]["total_max_points"] = $results['max_points'];
4226 $found["test"]["total_reached_points"] = $results['reached_points'];
4227 $found["test"]["total_requested_hints"] = $results['hint_count'];
4228 $found["test"]["total_hint_points"] = $results['hint_points'];
4229 $found["test"]["result_pass"] = $results['pass'];
4230 $found['test']['result_tstamp'] = $results['tstamp'];
4231 $found['test']['obligations_answered'] = $results['obligations_answered'];
4232
4233 if ((!$found['pass']['total_reached_points']) or (!$found['pass']['total_max_points'])) {
4234 $percentage = 0.0;
4235 } else {
4236 $percentage = ($found['pass']['total_reached_points'] / $found['pass']['total_max_points']) * 100.0;
4237
4238 if ($percentage < 0) {
4239 $percentage = 0.0;
4240 }
4241 }
4242
4243 $found["test"]["passed"] = $results['passed'];
4244
4245 return $found;
4246 }
4247
4254 public function evalTotalPersons()
4255 {
4256 global $DIC;
4257 $ilDB = $DIC['ilDB'];
4258
4259 $result = $ilDB->queryF(
4260 "SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
4261 array('integer'),
4262 array($this->getTestId())
4263 );
4264 $row = $ilDB->fetchAssoc($result);
4265 return $row["total"];
4266 }
4267
4274 public function getCompleteWorkingTime($user_id)
4275 {
4276 global $DIC;
4277 $ilDB = $DIC['ilDB'];
4278
4279 $result = $ilDB->queryF(
4280 "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",
4281 array('integer','integer'),
4282 array($this->getTestId(), $user_id)
4283 );
4284 $time = 0;
4285 while ($row = $ilDB->fetchAssoc($result)) {
4286 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4287 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4288 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4289 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4290 $time += ($epoch_2 - $epoch_1);
4291 }
4292 return $time;
4293 }
4294
4302 {
4303 return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4304 }
4305
4314 {
4315 global $DIC;
4316 $ilDB = $DIC['ilDB'];
4317
4318 $result = $ilDB->queryF(
4319 "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",
4320 array('integer'),
4321 array($test_id)
4322 );
4323 $time = 0;
4324 $times = array();
4325 while ($row = $ilDB->fetchAssoc($result)) {
4326 if (!array_key_exists($row["active_fi"], $times)) {
4327 $times[$row["active_fi"]] = 0;
4328 }
4329 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4330 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4331 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4332 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4333 $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4334 }
4335 return $times;
4336 }
4337
4344 public function getCompleteWorkingTimeOfParticipant($active_id)
4345 {
4346 global $DIC;
4347 $ilDB = $DIC['ilDB'];
4348
4349 $result = $ilDB->queryF(
4350 "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",
4351 array('integer','integer'),
4352 array($this->getTestId(), $active_id)
4353 );
4354 $time = 0;
4355 while ($row = $ilDB->fetchAssoc($result)) {
4356 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4357 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4358 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4359 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4360 $time += ($epoch_2 - $epoch_1);
4361 }
4362 return $time;
4363 }
4364
4371 public static function _getWorkingTimeOfParticipantForPass($active_id, $pass)
4372 {
4373 global $DIC;
4374 $ilDB = $DIC['ilDB'];
4375
4376 $result = $ilDB->queryF(
4377 "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4378 array('integer','integer'),
4379 array($active_id, $pass)
4380 );
4381 $time = 0;
4382 while ($row = $ilDB->fetchAssoc($result)) {
4383 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4384 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4385 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4386 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4387 $time += ($epoch_2 - $epoch_1);
4388 }
4389 return $time;
4390 }
4391
4399 public function getVisitTimeOfParticipant($active_id)
4400 {
4401 return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4402 }
4403
4412 public function _getVisitTimeOfParticipant($test_id, $active_id)
4413 {
4414 global $DIC;
4415 $ilDB = $DIC['ilDB'];
4416
4417 $result = $ilDB->queryF(
4418 "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",
4419 array('integer','integer'),
4420 array($test_id, $active_id)
4421 );
4422 $firstvisit = 0;
4423 $lastvisit = 0;
4424 while ($row = $ilDB->fetchAssoc($result)) {
4425 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4426 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4427 if ($firstvisit == 0 || $epoch_1 < $firstvisit) {
4428 $firstvisit = $epoch_1;
4429 }
4430 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4431 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4432 if ($epoch_2 > $lastvisit) {
4433 $lastvisit = $epoch_2;
4434 }
4435 }
4436 return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4437 }
4438
4445 public function &evalStatistical($active_id)
4446 {
4447 global $DIC;
4448 $ilDB = $DIC['ilDB'];
4449 // $ilBench = $DIC['ilBench'];
4450 $pass = ilObjTest::_getResultPass($active_id);
4451 $test_result = &$this->getTestResult($active_id, $pass);
4452 $result = $ilDB->queryF(
4453 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
4454 array('integer'),
4455 array($active_id)
4456 );
4457 $times = array();
4458 $first_visit = 0;
4459 $last_visit = 0;
4460 while ($row = $ilDB->fetchObject($result)) {
4461 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4462 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4463 if (!$first_visit) {
4464 $first_visit = $epoch_1;
4465 }
4466 if ($epoch_1 < $first_visit) {
4467 $first_visit = $epoch_1;
4468 }
4469 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4470 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4471 if (!$last_visit) {
4472 $last_visit = $epoch_2;
4473 }
4474 if ($epoch_2 > $last_visit) {
4475 $last_visit = $epoch_2;
4476 }
4477 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4478 }
4479 $max_time = 0;
4480 foreach ($times as $key => $value) {
4481 $max_time += $value;
4482 }
4483 if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"])) {
4484 $percentage = 0.0;
4485 } else {
4486 $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4487 if ($percentage < 0) {
4488 $percentage = 0.0;
4489 }
4490 }
4491 $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4492 $first_date = getdate($first_visit);
4493 $last_date = getdate($last_visit);
4494 $qworkedthrough = 0;
4495 foreach ($test_result as $key => $value) {
4496 if (preg_match("/\d+/", $key)) {
4497 $qworkedthrough += $value["workedthrough"];
4498 }
4499 }
4500 if (!$qworkedthrough) {
4501 $atimeofwork = 0;
4502 } else {
4503 $atimeofwork = $max_time / $qworkedthrough;
4504 }
4505
4506 $obligationsAnswered = $test_result["test"]["obligations_answered"];
4507
4508 $result_mark = "";
4509 $passed = "";
4510
4511 if ($mark_obj) {
4512 $result_mark = $mark_obj->getShortName();
4513
4514 if ($mark_obj->getPassed() && $obligationsAnswered) {
4515 $passed = 1;
4516 } else {
4517 $passed = 0;
4518 }
4519 }
4520 $percent_worked_through = 0;
4521 if (count($this->questions)) {
4522 $percent_worked_through = $qworkedthrough / count($this->questions);
4523 }
4524 $result_array = array(
4525 "qworkedthrough" => $qworkedthrough,
4526 "qmax" => count($this->questions),
4527 "pworkedthrough" => $percent_worked_through,
4528 "timeofwork" => $max_time,
4529 "atimeofwork" => $atimeofwork,
4530 "firstvisit" => $first_date,
4531 "lastvisit" => $last_date,
4532 "resultspoints" => $test_result["test"]["total_reached_points"],
4533 "maxpoints" => $test_result["test"]["total_max_points"],
4534 "resultsmarks" => $result_mark,
4535 "passed" => $passed,
4536 "distancemedian" => "0"
4537 );
4538 foreach ($test_result as $key => $value) {
4539 if (preg_match("/\d+/", $key)) {
4540 $result_array[$key] = $value;
4541 }
4542 }
4543 return $result_array;
4544 }
4545
4553 public function &getTotalPointsPassedArray()
4554 {
4555 $totalpoints_array = array();
4556 $all_users = &$this->evalTotalParticipantsArray();
4557 foreach ($all_users as $active_id => $user_name) {
4558 $test_result = &$this->getTestResult($active_id);
4559 $reached = $test_result["test"]["total_reached_points"];
4560 $total = $test_result["test"]["total_max_points"];
4561 $percentage = $total != 0 ? $reached / $total : 0;
4562 $mark = $this->mark_schema->getMatchingMark($percentage * 100.0);
4563
4564 $obligationsAnswered = $test_result["test"]["obligations_answered"];
4565
4566 if ($mark) {
4567 if ($mark->getPassed() && $obligationsAnswered) {
4568 array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4569 }
4570 }
4571 }
4572 return $totalpoints_array;
4573 }
4574
4580 public function &getParticipants()
4581 {
4582 global $DIC;
4583 $ilDB = $DIC['ilDB'];
4584 $result = $ilDB->queryF(
4585 "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",
4586 array('integer'),
4587 array($this->getTestId())
4588 );
4589 $persons_array = array();
4590 while ($row = $ilDB->fetchAssoc($result)) {
4591 $name = $this->lng->txt("anonymous");
4592 $fullname = $this->lng->txt("anonymous");
4593 $login = "";
4594 if (!$this->getAnonymity()) {
4595 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4596 $name = $this->lng->txt("deleted_user");
4597 $fullname = $this->lng->txt("deleted_user");
4598 $login = $this->lng->txt("unknown");
4599 } else {
4600 $login = $row["login"];
4601 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4602 $name = $this->lng->txt("anonymous");
4603 $fullname = $this->lng->txt("anonymous");
4604 } else {
4605 $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4606 $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4607 }
4608 }
4609 }
4610 $persons_array[$row["active_id"]] = array(
4611 "name" => $name,
4612 "fullname" => $fullname,
4613 "login" => $login
4614 );
4615 }
4616 return $persons_array;
4617 }
4618
4625 public function &evalTotalPersonsArray($name_sort_order = "asc")
4626 {
4627 global $DIC;
4628 $ilDB = $DIC['ilDB'];
4629 $result = $ilDB->queryF(
4630 "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),
4631 array('integer'),
4632 array($this->getTestId())
4633 );
4634 $persons_array = array();
4635 while ($row = $ilDB->fetchAssoc($result)) {
4636 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row["active_id"])) {
4637 continue;
4638 }
4639
4640 if ($this->getAnonymity()) {
4641 $persons_array[$row["active_id"]] = $this->lng->txt("anonymous");
4642 } else {
4643 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4644 $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4645 } else {
4646 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4647 $persons_array[$row["active_id"]] = $row["lastname"];
4648 } else {
4649 $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4650 }
4651 }
4652 }
4653 }
4654 return $persons_array;
4655 }
4656
4663 public function &evalTotalParticipantsArray($name_sort_order = "asc")
4664 {
4665 global $DIC;
4666 $ilDB = $DIC['ilDB'];
4667 $result = $ilDB->queryF(
4668 "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),
4669 array('integer'),
4670 array($this->getTestId())
4671 );
4672 $persons_array = array();
4673 while ($row = $ilDB->fetchAssoc($result)) {
4674 if ($this->getAnonymity()) {
4675 $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("anonymous"));
4676 } else {
4677 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4678 $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4679 } else {
4680 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4681 $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4682 } else {
4683 $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4684 }
4685 }
4686 }
4687 }
4688 return $persons_array;
4689 }
4690
4697 public function &getQuestionsOfTest($active_id)
4698 {
4699 global $DIC;
4700 $ilDB = $DIC['ilDB'];
4701 if ($this->isRandomTest()) {
4702 $ilDB->setLimit($this->getQuestionCount(), 0);
4703 $result = $ilDB->queryF(
4704 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4705 "tst_test_rnd_qst.pass, qpl_questions.points " .
4706 "FROM tst_test_rnd_qst, qpl_questions " .
4707 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4708 "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4709 array('integer'),
4710 array($active_id)
4711 );
4712 } else {
4713 $result = $ilDB->queryF(
4714 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4715 "qpl_questions.points " .
4716 "FROM tst_test_question, tst_active, qpl_questions " .
4717 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4718 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4719 array('integer'),
4720 array($active_id)
4721 );
4722 }
4723 $qtest = array();
4724 if ($result->numRows()) {
4725 while ($row = $ilDB->fetchAssoc($result)) {
4726 array_push($qtest, $row);
4727 }
4728 }
4729 return $qtest;
4730 }
4731
4738 public function &getQuestionsOfPass($active_id, $pass)
4739 {
4740 global $DIC;
4741 $ilDB = $DIC['ilDB'];
4742 if ($this->isRandomTest()) {
4743 $ilDB->setLimit($this->getQuestionCount(), 0);
4744 $result = $ilDB->queryF(
4745 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4746 "qpl_questions.points " .
4747 "FROM tst_test_rnd_qst, qpl_questions " .
4748 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4749 "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
4750 "ORDER BY tst_test_rnd_qst.sequence",
4751 array('integer', 'integer'),
4752 array($active_id, $pass)
4753 );
4754 } else {
4755 $result = $ilDB->queryF(
4756 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4757 "qpl_questions.points " .
4758 "FROM tst_test_question, tst_active, qpl_questions " .
4759 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4760 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4761 array('integer'),
4762 array($active_id)
4763 );
4764 }
4765 $qpass = array();
4766 if ($result->numRows()) {
4767 while ($row = $ilDB->fetchAssoc($result)) {
4768 array_push($qpass, $row);
4769 }
4770 }
4771 return $qpass;
4772 }
4773
4778
4783 {
4785 }
4786
4791 {
4792 $this->accessFilteredParticipantList = $accessFilteredParticipantList;
4793 }
4794
4799 {
4800 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
4801 require_once 'Modules/Test/classes/class.ilTestParticipantAccessFilter.php';
4802
4803 $list = new ilTestParticipantList($this);
4804 $list->initializeFromDbRows($this->getTestParticipants());
4805
4806 $list = $list->getAccessFilteredList(
4808 );
4809
4810 return $list;
4811 }
4812
4813 public function getUnfilteredEvaluationData()
4814 {
4816 global $DIC;
4817
4818 $ilDB = $DIC->database();
4819
4820 include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
4821 include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
4822 include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
4823
4824 $data = new ilTestEvaluationData($this);
4825
4826 $query = "
4827 SELECT tst_test_result.*,
4828 qpl_questions.original_id,
4829 qpl_questions.title questiontitle,
4830 qpl_questions.points maxpoints
4831
4832 FROM tst_test_result, qpl_questions, tst_active
4833
4834 WHERE tst_active.active_id = tst_test_result.active_fi
4835 AND qpl_questions.question_id = tst_test_result.question_fi
4836 AND tst_active.test_fi = %s
4837
4838 ORDER BY tst_active.active_id ASC, tst_test_result.pass ASC, tst_test_result.tstamp DESC
4839 ";
4840
4841 $result = $ilDB->queryF(
4842 $query,
4843 array('integer'),
4844 array($this->getTestId())
4845 );
4846
4847 $pass = null;
4848 $checked = array();
4849 $datasets = 0;
4850 $questionData = [];
4851
4852 while ($row = $ilDB->fetchAssoc($result)) {
4853 $participantObject = $data->getParticipant($row["active_fi"]);
4854
4855 if (!($participantObject instanceof ilTestEvaluationUserData)) {
4856 continue;
4857 }
4858
4859 $passObject = $participantObject->getPass($row["pass"]);
4860
4861 if (!($passObject instanceof ilTestEvaluationPassData)) {
4862 continue;
4863 }
4864
4865 $passObject->addAnsweredQuestion(
4866 $row["question_fi"],
4867 $row["maxpoints"],
4868 $row["points"],
4869 $row['answered'],
4870 null,
4871 $row['manual']
4872 );
4873 }
4874
4875 foreach (array_keys($data->getParticipants()) as $active_id) {
4876 if ($this->isRandomTest()) {
4877 for ($testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++) {
4878 $ilDB->setLimit($this->getQuestionCount(), 0);
4879
4880 $query = "
4881 SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, qpl_questions.original_id,
4882 tst_test_rnd_qst.pass, qpl_questions.points, qpl_questions.title
4883 FROM tst_test_rnd_qst, qpl_questions
4884 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
4885 AND tst_test_rnd_qst.pass = %s
4886 AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence
4887 ";
4888
4889 $result = $ilDB->queryF(
4890 $query,
4891 array('integer','integer'),
4892 array($testpass, $active_id)
4893 );
4894
4895 if ($result->numRows()) {
4896 while ($row = $ilDB->fetchAssoc($result)) {
4897 $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
4898
4899 $data->getParticipant($active_id)->addQuestion(
4900 $row["original_id"],
4901 $row["question_fi"],
4902 $row["points"],
4903 $row["sequence"],
4904 $tpass
4905 );
4906
4907 $data->addQuestionTitle($row["question_fi"], $row["title"]);
4908 }
4909 }
4910 }
4911 } elseif ($this->isDynamicTest()) {
4912 $lastPass = $data->getParticipant($active_id)->getLastPass();
4913 for ($testpass = 0; $testpass <= $lastPass; $testpass++) {
4914 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4915 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig(
4916 $DIC->repositoryTree(),
4917 $DIC->database(),
4918 $DIC['ilPluginAdmin'],
4919 $this
4920 );
4921 $dynamicQuestionSetConfig->loadFromDb();
4922
4923 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4924 $testSequenceFactory = new ilTestSequenceFactory($DIC->database(), $DIC->language(), $DIC['refinery'], $DIC['ilPluginAdmin'], $this);
4925 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $testpass);
4926
4927 $testSequence->loadFromDb($dynamicQuestionSetConfig);
4928 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4929
4930 $sequence = (array) $testSequence->getUserSequenceQuestions();
4931
4932 $questionsIdsToRequest = array_diff(array_values($sequence), array_values($questionData));
4933 if (count($questionsIdsToRequest) > 0) {
4934 $questionIdsCondition = ' ' . $DIC->database()->in('question_id', array_values($questionsIdsToRequest), false, 'integer') . ' ';
4935
4936 $res = $DIC->database()->queryF(
4937 "
4938 SELECT *
4939 FROM qpl_questions
4940 WHERE {$questionIdsCondition}",
4941 array('integer'),
4942 array($active_id)
4943 );
4944 while ($row = $DIC->database()->fetchAssoc($res)) {
4945 $questionData[$row['question_id']] = $row;
4946 $data->addQuestionTitle($row['question_id'], $row['title']);
4947 }
4948 }
4949
4950 foreach ($sequence as $questionId) {
4951 if (!isset($questionData[$questionId])) {
4952 continue;
4953 }
4954
4955 $row = $questionData[$questionId];
4956
4957 $data->getParticipant(
4958 $active_id
4959 )->addQuestion(
4960 $row['original_id'],
4961 $row['question_id'],
4962 $row['points'],
4963 null,
4964 $testpass
4965 );
4966 }
4967 }
4968 } else {
4969 $query = "
4970 SELECT tst_test_question.sequence, tst_test_question.question_fi,
4971 qpl_questions.points, qpl_questions.title, qpl_questions.original_id
4972 FROM tst_test_question, tst_active, qpl_questions
4973 WHERE tst_test_question.question_fi = qpl_questions.question_id
4974 AND tst_active.active_id = %s
4975 AND tst_active.test_fi = tst_test_question.test_fi
4976 ORDER BY tst_test_question.sequence
4977 ";
4978
4979 $result = $ilDB->queryF(
4980 $query,
4981 array('integer'),
4982 array($active_id)
4983 );
4984
4985 if ($result->numRows()) {
4986 $questionsbysequence = array();
4987
4988 while ($row = $ilDB->fetchAssoc($result)) {
4989 $questionsbysequence[$row["sequence"]] = $row;
4990 }
4991
4992 $seqresult = $ilDB->queryF(
4993 "SELECT * FROM tst_sequence WHERE active_fi = %s",
4994 array('integer'),
4995 array($active_id)
4996 );
4997
4998 while ($seqrow = $ilDB->fetchAssoc($seqresult)) {
4999 $questionsequence = unserialize($seqrow["sequence"]);
5000
5001 foreach ($questionsequence as $sidx => $seq) {
5002 $data->getParticipant($active_id)->addQuestion(
5003 $questionsbysequence[$seq]["original_id"],
5004 $questionsbysequence[$seq]["question_fi"],
5005 $questionsbysequence[$seq]["points"],
5006 $sidx + 1,
5007 $seqrow["pass"]
5008 );
5009
5010 $data->addQuestionTitle(
5011 $questionsbysequence[$seq]["question_fi"],
5012 $questionsbysequence[$seq]["title"]
5013 );
5014 }
5015 }
5016 }
5017 }
5018 }
5019
5020 if ($this->getECTSOutput()) {
5021 $passed_array = &$this->getTotalPointsPassedArray();
5022 }
5023
5024 foreach (array_keys($data->getParticipants()) as $active_id) {
5025 $tstUserData = $data->getParticipant($active_id);
5026
5027 $percentage = $tstUserData->getReachedPointsInPercent();
5028
5029 $obligationsAnswered = $tstUserData->areObligationsAnswered();
5030
5031 $mark = $this->mark_schema->getMatchingMark($percentage);
5032
5033 if (is_object($mark)) {
5034 $tstUserData->setMark($mark->getShortName());
5035 $tstUserData->setMarkOfficial($mark->getOfficialName());
5036
5037 $tstUserData->setPassed(
5038 $mark->getPassed() && $tstUserData->areObligationsAnswered()
5039 );
5040 }
5041
5042 if ($this->getECTSOutput()) {
5043 $ects_mark = $this->getECTSGrade(
5044 $passed_array,
5045 $tstUserData->getReached(),
5046 $tstUserData->getMaxPoints()
5047 );
5048
5049 $tstUserData->setECTSMark($ects_mark);
5050 }
5051
5052 $visitingTime = &$this->getVisitTimeOfParticipant($active_id);
5053
5054 $tstUserData->setFirstVisit($visitingTime["firstvisit"]);
5055 $tstUserData->setLastVisit($visitingTime["lastvisit"]);
5056 }
5057
5058 return $data;
5059 }
5060
5061 public static function _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
5062 {
5063 global $DIC;
5064 $ilDB = $DIC['ilDB'];
5065
5067
5068 switch ($questionSetType) {
5070
5071 $res = $ilDB->queryF(
5072 "
5073 SELECT COUNT(qpl_questions.question_id) qcount,
5074 SUM(qpl_questions.points) qsum
5075 FROM tst_active
5076 INNER JOIN tst_tests
5077 ON tst_tests.test_id = tst_active.test_fi
5078 INNER JOIN tst_dyn_quest_set_cfg
5079 ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
5080 INNER JOIN qpl_questions
5081 ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
5082 AND qpl_questions.original_id IS NULL
5083 AND qpl_questions.complete = %s
5084 WHERE tst_active.active_id = %s
5085 ",
5086 array('integer', 'integer'),
5087 array(1, $active_id)
5088 );
5089
5090 break;
5091
5093
5094 $res = $ilDB->queryF(
5095 "
5096 SELECT tst_test_rnd_qst.pass,
5097 COUNT(tst_test_rnd_qst.question_fi) qcount,
5098 SUM(qpl_questions.points) qsum
5099
5100 FROM tst_test_rnd_qst,
5101 qpl_questions
5102
5103 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
5104 AND tst_test_rnd_qst.active_fi = %s
5105 AND pass = %s
5106
5107 GROUP BY tst_test_rnd_qst.active_fi,
5108 tst_test_rnd_qst.pass
5109 ",
5110 array('integer', 'integer'),
5111 array($active_id, $pass)
5112 );
5113
5114 break;
5115
5117
5118 $res = $ilDB->queryF(
5119 "
5120 SELECT COUNT(tst_test_question.question_fi) qcount,
5121 SUM(qpl_questions.points) qsum
5122
5123 FROM tst_test_question,
5124 qpl_questions,
5125 tst_active
5126
5127 WHERE tst_test_question.question_fi = qpl_questions.question_id
5128 AND tst_test_question.test_fi = tst_active.test_fi
5129 AND tst_active.active_id = %s
5130
5131 GROUP BY tst_test_question.test_fi
5132 ",
5133 array('integer'),
5134 array($active_id)
5135 );
5136
5137 break;
5138
5139 default:
5140
5141 throw new ilTestException("not supported question set type: $questionSetType");
5142 }
5143
5144 $row = $ilDB->fetchAssoc($res);
5145
5146 if (is_array($row)) {
5147 return array("count" => $row["qcount"], "points" => $row["qsum"]);
5148 }
5149
5150 return array("count" => 0, "points" => 0);
5151 }
5152
5153 public function &getCompleteEvaluationData($withStatistics = true, $filterby = "", $filtertext = "")
5154 {
5155 include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5156 include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5157 include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5158 $data = $this->getUnfilteredEvaluationData();
5159 if ($withStatistics) {
5160 $data->calculateStatistics();
5161 }
5162 $data->setFilter($filterby, $filtertext);
5163 return $data;
5164 }
5165
5172 public function &evalResultsOverview()
5173 {
5174 return $this->_evalResultsOverview($this->getTestId());
5175 }
5176
5184 {
5185 global $DIC;
5186 $ilDB = $DIC['ilDB'];
5187
5188 $result = $ilDB->queryF(
5189 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5190 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5191 "qpl_questions.points maxpoints " .
5192 "FROM tst_test_result, qpl_questions, tst_active " .
5193 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5194 "WHERE tst_active.active_id = tst_test_result.active_fi " .
5195 "AND qpl_questions.question_id = tst_test_result.question_fi " .
5196 "AND tst_active.test_fi = %s " .
5197 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5198 array('integer'),
5199 array($test_id)
5200 );
5201 $overview = array();
5202 while ($row = $ilDB->fetchAssoc($result)) {
5203 if (!array_key_exists($row["active_fi"], $overview)) {
5204 $overview[$row["active_fi"]] = array();
5205 $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5206 $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5207 $overview[$row["active_fi"]]["title"] = $row["title"];
5208 $overview[$row["active_fi"]]["login"] = $row["login"];
5209 $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5210 $overview[$row["active_fi"]]["started"] = $row["started"];
5211 $overview[$row["active_fi"]]["finished"] = $row["finished"];
5212 }
5213 if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5214 $overview[$row["active_fi"]][$row["pass"]] = array();
5215 $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5216 $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5217 }
5218 array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5219 $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5220 }
5221 return $overview;
5222 }
5223
5231 public function &evalResultsOverviewOfParticipant($active_id)
5232 {
5233 global $DIC;
5234 $ilDB = $DIC['ilDB'];
5235
5236 $result = $ilDB->queryF(
5237 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5238 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5239 "qpl_questions.points maxpoints " .
5240 "FROM tst_test_result, qpl_questions, tst_active " .
5241 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5242 "WHERE tst_active.active_id = tst_test_result.active_fi " .
5243 "AND qpl_questions.question_id = tst_test_result.question_fi " .
5244 "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5245 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5246 array('integer', 'integer'),
5247 array($this->getTestId(), $active_id)
5248 );
5249 $overview = array();
5250 while ($row = $ilDB->fetchAssoc($result)) {
5251 if (!array_key_exists($row["active_fi"], $overview)) {
5252 $overview[$row["active_fi"]] = array();
5253 $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5254 $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5255 $overview[$row["active_fi"]]["title"] = $row["title"];
5256 $overview[$row["active_fi"]]["login"] = $row["login"];
5257 $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5258 $overview[$row["active_fi"]]["started"] = $row["started"];
5259 $overview[$row["active_fi"]]["finished"] = $row["finished"];
5260 }
5261 if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5262 $overview[$row["active_fi"]][$row["pass"]] = array();
5263 $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5264 $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5265 }
5266 array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5267 $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5268 }
5269 return $overview;
5270 }
5271
5283 public function buildName($user_id, $firstname, $lastname, $title)
5284 {
5285 $name = "";
5286 if (strlen($firstname . $lastname . $title) == 0) {
5287 $name = $this->lng->txt("deleted_user");
5288 } else {
5289 if ($user_id == ANONYMOUS_USER_ID) {
5290 $name = $lastname;
5291 } else {
5292 $name = trim($lastname . ", " . $firstname . " " . $title);
5293 }
5294 if ($this->getAnonymity()) {
5295 $name = $this->lng->txt("anonymous");
5296 }
5297 }
5298 return $name;
5299 }
5300
5313 public function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5314 {
5315 global $DIC;
5316 $lng = $DIC['lng'];
5317 $name = "";
5318 if (strlen($firstname . $lastname . $title) == 0) {
5319 $name = $lng->txt("deleted_user");
5320 } else {
5321 if ($user_id == ANONYMOUS_USER_ID) {
5322 $name = $lastname;
5323 } else {
5324 $name = trim($lastname . ", " . $firstname . " " . $title);
5325 }
5326 if ($is_anonymous) {
5327 $name = $lng->txt("anonymous");
5328 }
5329 }
5330 return $name;
5331 }
5332
5339 public function evalTotalStartedAverageTime($activeIdsFilter = null)
5340 {
5341 global $DIC; /* @var ILIAS\DI\Container $DIC */
5342
5343 $query = "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
5344
5345 if (is_array($activeIdsFilter) && count($activeIdsFilter)) {
5346 $query .= " AND " . $DIC->database()->in('active_id', $activeIdsFilter, false, 'integer');
5347 }
5348
5349 $result = $DIC->database()->queryF($query, array('integer'), array($this->getTestId()));
5350 $times = array();
5351 while ($row = $DIC->database()->fetchObject($result)) {
5352 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5353 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5354 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5355 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5356 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5357 }
5358 $max_time = 0;
5359 $counter = 0;
5360 foreach ($times as $key => $value) {
5361 $max_time += $value;
5362 $counter++;
5363 }
5364 if ($counter) {
5365 $average_time = round($max_time / $counter);
5366 } else {
5367 $average_time = 0;
5368 }
5369 return $average_time;
5370 }
5371
5378 public function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = false, $with_questioncount = false, $permission = "read")
5379 {
5380 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5381 return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5382 }
5383
5390 public function getEstimatedWorkingTime()
5391 {
5392 $time_in_seconds = 0;
5393 foreach ($this->questions as $question_id) {
5394 $question = &ilObjTest::_instanciateQuestion($question_id);
5395 $est_time = $question->getEstimatedWorkingTime();
5396 $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5397 }
5398 $hours = (int) ($time_in_seconds / 3600) ;
5399 $time_in_seconds = $time_in_seconds - ($hours * 3600);
5400 $minutes = (int) ($time_in_seconds / 60);
5401 $time_in_seconds = $time_in_seconds - ($minutes * 60);
5402 $result = array("hh" => $hours, "mm" => $minutes, "ss" => $time_in_seconds);
5403 return $result;
5404 }
5405
5412 public function getImagePath()
5413 {
5414 return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5415 }
5416
5423 public function getImagePathWeb()
5424 {
5425 $relative_path = "/assessment/" . $this->getId() . "/images/";
5426 return self::getDataWebPath($relative_path);
5427 }
5428
5437 public function &createQuestionGUI($question_type, $question_id = -1)
5438 {
5439 if ((!$question_type) and ($question_id > 0)) {
5440 $question_type = $this->getQuestionType($question_id);
5441 }
5442
5443 if (!strlen($question_type)) {
5444 return null;
5445 }
5446
5447 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5448 assQuestion::_includeClass($question_type, 1);
5449
5450 $question_type_gui = assQuestion::getGuiClassNameByQuestionType($question_type);
5451 $question = new $question_type_gui();
5452
5453 if ($question_id > 0) {
5454 $question->object->loadFromDb($question_id);
5455
5456 global $DIC;
5457 $ilCtrl = $DIC['ilCtrl'];
5458 $ilDB = $DIC['ilDB'];
5459 $ilUser = $DIC['ilUser'];
5460 $lng = $DIC['lng'];
5461
5462 $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
5463 $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
5464
5465 $assSettings = new ilSetting('assessment');
5466 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
5467 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
5468 $processLockerFactory->setQuestionId($question->object->getId());
5469 $processLockerFactory->setUserId($ilUser->getId());
5470 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
5471 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
5472 $question->object->setProcessLocker($processLockerFactory->getLocker());
5473 }
5474
5475 return $question;
5476 }
5477
5487 public static function _instanciateQuestion($question_id)
5488 {
5489 if (strcmp($question_id, "") != 0) {
5490 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5491 return assQuestion::_instanciateQuestion($question_id);
5492 }
5493 }
5494
5503 public function moveQuestions($move_questions, $target_index, $insert_mode)
5504 {
5505 $this->questions = array_values($this->questions);
5506 $array_pos = array_search($target_index, $this->questions);
5507 if ($insert_mode == 0) {
5508 $part1 = array_slice($this->questions, 0, $array_pos);
5509 $part2 = array_slice($this->questions, $array_pos);
5510 } elseif ($insert_mode == 1) {
5511 $part1 = array_slice($this->questions, 0, $array_pos + 1);
5512 $part2 = array_slice($this->questions, $array_pos + 1);
5513 }
5514 foreach ($move_questions as $question_id) {
5515 if (!(array_search($question_id, $part1) === false)) {
5516 unset($part1[array_search($question_id, $part1)]);
5517 }
5518 if (!(array_search($question_id, $part2) === false)) {
5519 unset($part2[array_search($question_id, $part2)]);
5520 }
5521 }
5522 $part1 = array_values($part1);
5523 $part2 = array_values($part2);
5524 $new_array = array_values(array_merge($part1, $move_questions, $part2));
5525 $this->questions = array();
5526 $counter = 1;
5527 foreach ($new_array as $question_id) {
5528 $this->questions[$counter] = $question_id;
5529 $counter++;
5530 }
5531 $this->saveQuestionsToDb();
5532 }
5533
5534
5542 public function startingTimeReached()
5543 {
5544 if ($this->isStartingTimeEnabled() && $this->getStartingTime() != 0) {
5545 $now = time();
5546 if ($now < $this->getStartingTime()) {
5547 return false;
5548 }
5549 }
5550 return true;
5551 }
5552
5560 public function endingTimeReached()
5561 {
5562 if ($this->isEndingTimeEnabled() && $this->getEndingTime() != 0) {
5563 $now = time();
5564 if ($now > $this->getEndingTime()) {
5565 return true;
5566 }
5567 }
5568 return false;
5569 }
5570
5576 public function getAvailableQuestions($arrFilter, $completeonly = 0)
5577 {
5578 global $DIC;
5579 $pluginAdmin = $DIC['ilPluginAdmin'];
5580 $lng = $DIC['lng'];
5581 $ilUser = $DIC['ilUser'];
5582 $ilDB = $DIC['ilDB'];
5583
5584 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5585 $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = true, $equal_points = false, $could_be_offline = false, $showPath = false, $with_questioncount = false));
5586 $available = "";
5587 if (count($available_pools)) {
5588 $available = " AND " . $ilDB->in('qpl_questions.obj_fi', $available_pools, false, 'integer');
5589 } else {
5590 return array();
5591 }
5592 if ($completeonly) {
5593 $available .= " AND qpl_questions.complete = " . $ilDB->quote("1", 'text');
5594 }
5595
5596 $where = "";
5597 if (is_array($arrFilter)) {
5598 if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title'])) {
5599 $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
5600 }
5601 if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description'])) {
5602 $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
5603 }
5604 if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author'])) {
5605 $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
5606 }
5607 if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type'])) {
5608 $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
5609 }
5610 if (array_key_exists('qpl', $arrFilter) && strlen($arrFilter['qpl'])) {
5611 $where .= " AND " . $ilDB->like('object_data.title', 'text', "%%" . $arrFilter['qpl'] . "%%");
5612 }
5613 }
5614
5615 $original_ids = &$this->getExistingQuestions();
5616 $original_clause = " qpl_questions.original_id IS NULL";
5617 if (count($original_ids)) {
5618 $original_clause = " qpl_questions.original_id IS NULL AND " . $ilDB->in('qpl_questions.question_id', $original_ids, true, 'integer');
5619 }
5620
5621 $query_result = $ilDB->query("
5622 SELECT qpl_questions.*, qpl_questions.tstamp,
5623 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,
5624 object_data.title parent_title
5625 FROM qpl_questions, qpl_qst_type, object_data
5626 WHERE $original_clause $available
5627 AND object_data.obj_id = qpl_questions.obj_fi
5628 AND qpl_questions.tstamp > 0
5629 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
5630 $where
5631 ");
5632 $rows = array();
5633 $types = $this->getQuestionTypeTranslations();
5634 if ($query_result->numRows()) {
5635 while ($row = $ilDB->fetchAssoc($query_result)) {
5637
5638 if (!$row['plugin']) {
5639 $row[ 'ttype' ] = $lng->txt($row[ "type_tag" ]);
5640
5641 $rows[] = $row;
5642 continue;
5643 }
5644
5645 if (!$pluginAdmin->isActive(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name'])) {
5646 continue;
5647 }
5648
5649 $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name']);
5650 $row[ 'ttype' ] = $pl->getQuestionTypeTranslation();
5651
5652 $rows[] = $row;
5653 }
5654 }
5655 return $rows;
5656 }
5657
5662 public function fromXML(ilQTIAssessment $assessment)
5663 {
5664 unset($_SESSION["import_mob_xhtml"]);
5665
5666 $this->setDescription($assessment->getComment());
5667 $this->setTitle($assessment->getTitle());
5668
5669 $this->setIntroductionEnabled(false);
5670 foreach ($assessment->objectives as $objectives) {
5671 foreach ($objectives->materials as $material) {
5672 $intro = $this->QTIMaterialToString($material);
5673 $this->setIntroduction($intro);
5674 $this->setIntroductionEnabled(strlen($intro) > 0);
5675 }
5676 }
5677
5678 if (
5679 $assessment->getPresentationMaterial() &&
5680 $assessment->getPresentationMaterial()->getFlowMat(0) &&
5681 $assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)
5682 ) {
5683 $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)));
5684 }
5685
5686 foreach ($assessment->assessmentcontrol as $assessmentcontrol) {
5687 switch ($assessmentcontrol->getSolutionswitch()) {
5688 case "Yes":
5690 break;
5691 default:
5693 break;
5694 }
5695 }
5696
5697 $this->setStartingTimeEnabled(false);
5698 $this->setEndingTimeEnabled(false);
5699 $this->setPasswordEnabled(false);
5700 $this->setLimitUsersEnabled(false);
5701
5702 foreach ($assessment->qtimetadata as $metadata) {
5703 switch ($metadata["label"]) {
5704 case "test_type":
5705 // for old tests with a test type
5706 $type = $metadata["entry"];
5707 switch ($type) {
5708 case 1:
5709 // assessment
5710 $this->setAnonymity(1);
5711 break;
5712 case 2:
5713 // self assessment
5714 break;
5715 case 4:
5716 // online exam
5717 $this->setFixedParticipants(1);
5719 $this->setShowSolutionPrintview(1);
5720 break;
5721 case 5:
5722 // varying random test
5723 break;
5724 }
5725 break;
5726 case "sequence_settings":
5727 $this->setSequenceSettings($metadata["entry"]);
5728 break;
5729 case "solution_details":
5730 $this->setShowSolutionDetails((int) $metadata["entry"]);
5731 break;
5732 case "print_bs_with_res":
5733 $this->setPrintBestSolutionWithResult((int) $metadata["entry"]);
5734 break;
5735 case "author":
5736 $this->setAuthor($metadata["entry"]);
5737 break;
5738 case "nr_of_tries":
5739 $this->setNrOfTries($metadata["entry"]);
5740 break;
5741 case 'block_after_passed':
5742 $this->setBlockPassesAfterPassedEnabled((bool) $metadata['entry']);
5743 break;
5744 case "pass_waiting":
5745 $this->setPassWaiting($metadata["entry"]);
5746 break;
5747 case "kiosk":
5748 $this->setKiosk($metadata["entry"]);
5749 break;
5750 case "showfinalstatement":
5751 $this->setShowFinalStatement($metadata["entry"]);
5752 break;
5753 case "showinfo":
5754 $this->setShowInfo($metadata["entry"]);
5755 break;
5756 case "forcejs":
5757 $this->setForceJS($metadata["entry"]);
5758 break;
5759 case "customstyle":
5760 $this->setCustomStyle($metadata["entry"]);
5761 break;
5762
5763 case "highscore_enabled":
5764 $this->setHighscoreEnabled($metadata["entry"]);
5765 break;
5766
5767 case "highscore_anon":
5768 $this->setHighscoreAnon($metadata["entry"]);
5769 break;
5770
5771 case "highscore_achieved_ts":
5772 $this->setHighscoreAchievedTS($metadata["entry"]);
5773 break;
5774
5775 case "highscore_score":
5776 $this->setHighscoreScore($metadata["entry"]);
5777 break;
5778
5779 case "highscore_percentage":
5780 $this->setHighscorePercentage($metadata["entry"]);
5781 break;
5782
5783 case "highscore_hints":
5784 $this->setHighscoreHints($metadata["entry"]);
5785 break;
5786
5787 case "highscore_wtime":
5788 $this->setHighscoreWTime($metadata["entry"]);
5789 break;
5790
5791 case "highscore_own_table":
5792 $this->setHighscoreOwnTable($metadata["entry"]);
5793 break;
5794
5795 case "highscore_top_table":
5796 $this->setHighscoreTopTable($metadata["entry"]);
5797 break;
5798
5799 case "highscore_top_num":
5800 $this->setHighscoreTopNum($metadata["entry"]);
5801 break;
5802
5803 case "hide_previous_results":
5804 if ($metadata["entry"] == 0) {
5805 $this->setUsePreviousAnswers(1);
5806 } else {
5807 $this->setUsePreviousAnswers(0);
5808 }
5809 break;
5810 case "use_previous_answers":
5811 $this->setUsePreviousAnswers($metadata["entry"]);
5812 break;
5813 case "answer_feedback":
5814 $this->setAnswerFeedback($metadata["entry"]);
5815 break;
5816 case "hide_title_points":
5817 $this->setTitleOutput($metadata["entry"]);
5818 break;
5819 case "title_output":
5820 $this->setTitleOutput($metadata["entry"]);
5821 break;
5822 case "question_set_type":
5823 $this->setQuestionSetType($metadata["entry"]);
5824 break;
5825 case "random_test":
5826 if ($metadata["entry"]) {
5827 $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
5828 } else {
5829 $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
5830 }
5831 break;
5832 case "results_presentation":
5833 $this->setResultsPresentation($metadata["entry"]);
5834 break;
5835 case "reset_processing_time":
5836 $this->setResetProcessingTime($metadata["entry"]);
5837 break;
5838 case "instant_verification":
5839 $this->setInstantFeedbackSolution($metadata["entry"]);
5840 break;
5841 case "follow_qst_answer_fixation":
5842 $this->setFollowupQuestionAnswerFixationEnabled((bool) $metadata["entry"]);
5843 break;
5844 case "instant_feedback_answer_fixation":
5845 $this->setInstantFeedbackAnswerFixationEnabled((bool) $metadata["entry"]);
5846 break;
5847 case "force_instant_feedback":
5848 $this->setForceInstantFeedbackEnabled((bool) $metadata["entry"]);
5849 break;
5850 case "answer_feedback_points":
5851 $this->setAnswerFeedbackPoints($metadata["entry"]);
5852 break;
5853 case "anonymity":
5854 $this->setAnonymity($metadata["entry"]);
5855 break;
5856 case "use_pool":
5857 $this->setPoolUsage((int) $metadata["entry"]);
5858 break;
5859 case "show_cancel":
5860 $this->setShowCancel($metadata["entry"]);
5861 break;
5862 case "show_marker":
5863 $this->setShowMarker($metadata["entry"]);
5864 break;
5865 case "fixed_participants":
5866 $this->setFixedParticipants($metadata["entry"]);
5867 break;
5868 case "score_reporting":
5869 $this->setScoreReporting($metadata["entry"]);
5870 break;
5871 case "shuffle_questions":
5872 $this->setShuffleQuestions($metadata["entry"]);
5873 break;
5874 case "count_system":
5875 $this->setCountSystem($metadata["entry"]);
5876 break;
5877 case "mc_scoring":
5878 $this->setMCScoring($metadata["entry"]);
5879 break;
5880 case "mailnotification":
5881 $this->setMailNotification($metadata["entry"]);
5882 break;
5883 case "mailnottype":
5884 $this->setMailNotificationType($metadata["entry"]);
5885 break;
5886 case "exportsettings":
5887 $this->setExportSettings($metadata['entry']);
5888 break;
5889 case "score_cutting":
5890 $this->setScoreCutting($metadata["entry"]);
5891 break;
5892 case "password":
5893 $this->setPassword($metadata["entry"]);
5894 $this->setPasswordEnabled(strlen($metadata["entry"]) > 0);
5895 break;
5896 case "allowedUsers":
5897 $this->setAllowedUsers($metadata["entry"]);
5898 $this->setLimitUsersEnabled((int) $metadata["entry"] > 0);
5899 break;
5900 case "allowedUsersTimeGap":
5901 $this->setAllowedUsersTimeGap($metadata["entry"]);
5902 break;
5903 case "pass_scoring":
5904 $this->setPassScoring($metadata["entry"]);
5905 break;
5906 case 'pass_deletion_allowed':
5907 $this->setPassDeletionAllowed((int) $metadata['entry']);
5908 break;
5909 case "show_summary":
5910 $this->setListOfQuestionsSettings($metadata["entry"]);
5911 break;
5912 case "reporting_date":
5913 $iso8601period = $metadata["entry"];
5914 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5915 $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
5916 }
5917 break;
5918 case 'enable_processing_time':
5919 $this->setEnableProcessingTime($metadata['entry']);
5920 break;
5921 case "processing_time":
5922 $this->setProcessingTime($metadata['entry']);
5923 break;
5924 case "starting_time":
5925 $iso8601period = $metadata["entry"];
5926 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5927 $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);
5928 $this->setStartingTime($date_time->get(IL_CAL_UNIX));
5929 $this->setStartingTimeEnabled(true);
5930 }
5931 break;
5932 case "ending_time":
5933 $iso8601period = $metadata["entry"];
5934 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5935 $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);
5936 $this->setEndingTime($date_time->get(IL_CAL_UNIX));
5937 $this->setEndingTimeEnabled(true);
5938 }
5939 break;
5940 case "enable_examview":
5941 $this->setEnableExamview($metadata["entry"]);
5942 break;
5943 case 'show_examview_html':
5944 $this->setShowExamviewHtml($metadata['entry']);
5945 break;
5946 case 'show_examview_pdf':
5947 $this->setShowExamviewPdf($metadata['entry']);
5948 break;
5949 case 'redirection_mode':
5950 $this->setRedirectionMode($metadata['entry']);
5951 break;
5952 case 'redirection_url':
5953 $this->setRedirectionUrl($metadata['entry']);
5954 break;
5955 case 'examid_in_kiosk':
5956 case 'examid_in_test_pass':
5957 $this->setShowExamIdInTestPassEnabled($metadata['entry']);
5958 break;
5959 case 'show_exam_id':
5960 case 'examid_in_test_res':
5961 $this->setShowExamIdInTestResultsEnabled($metadata['entry']);
5962 break;
5963 case 'enable_archiving':
5964 $this->setEnableArchiving($metadata['entry']);
5965 break;
5966 case 'sign_submission':
5967 $this->setSignSubmission($metadata['entry']);
5968 break;
5969 case 'char_selector_availability':
5970 $this->setCharSelectorAvailability($metadata['entry']);
5971 break;
5972 case 'char_selector_definition':
5973 $this->setCharSelectorDefinition($metadata['entry']);
5974 break;
5975 case 'skill_service':
5976 $this->setSkillServiceEnabled((bool) $metadata['entry']);
5977 break;
5978 case 'result_tax_filters':
5979 $this->setResultFilterTaxIds(strlen($metadata['entry']) ? unserialize($metadata['entry']) : array());
5980 break;
5981 case 'show_grading_status':
5982 $this->setShowGradingStatusEnabled((bool) $metadata['entry']);
5983 break;
5984 case 'show_grading_mark':
5985 $this->setShowGradingMarkEnabled((bool) $metadata['entry']);
5986 break;
5987 case 'activation_limited':
5988 $this->setActivationLimited($metadata['entry']);
5989 break;
5990 case 'activation_start_time':
5991 $this->setActivationStartingTime($metadata['entry']);
5992 break;
5993 case 'activation_end_time':
5994 $this->setActivationEndingTime($metadata['entry']);
5995 break;
5996 case 'activation_visibility':
5997 $this->setActivationVisibility($metadata['entry']);
5998 break;
5999 case 'autosave':
6000 $this->setAutosave($metadata['entry']);
6001 break;
6002 case 'autosave_ival':
6003 $this->setAutosaveIval($metadata['entry']);
6004 break;
6005 case 'offer_question_hints':
6006 $this->setOfferingQuestionHintsEnabled($metadata['entry']);
6007 break;
6008 case 'instant_feedback_specific':
6009 $this->setSpecificAnswerFeedback($metadata['entry']);
6010 break;
6011 case 'obligations_enabled':
6012 $this->setObligationsEnabled($metadata['entry']);
6013 break;
6014 }
6015 if (preg_match("/mark_step_\d+/", $metadata["label"])) {
6016 $xmlmark = $metadata["entry"];
6017 preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
6018 $mark_short = $matches[1];
6019 preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
6020 $mark_official = $matches[1];
6021 preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
6022 $mark_percentage = $matches[1];
6023 preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
6024 $mark_passed = $matches[1];
6025 $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
6026 }
6027 }
6028 // handle the import of media objects in XHTML code
6029 if (is_array($_SESSION["import_mob_xhtml"])) {
6030 include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6031 include_once "./Services/RTE/classes/class.ilRTE.php";
6032 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
6033 foreach ($_SESSION["import_mob_xhtml"] as $mob) {
6034 $importfile = ilObjTest::_getImportDirectory() . '/' . $_SESSION["tst_import_subdir"] . '/' . $mob["uri"];
6035 if (file_exists($importfile)) {
6036 $media_object = &ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false);
6037 ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
6038 $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
6039 $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
6040 } else {
6041 global $DIC;
6042 $ilLog = $DIC['ilLog'];
6043 $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
6044 }
6045 }
6046 $this->saveToDb();
6047 }
6048 }
6049
6055 public function toXML()
6056 {
6057 include_once("./Services/Xml/classes/class.ilXmlWriter.php");
6058 $a_xml_writer = new ilXmlWriter;
6059 // set xml header
6060 $a_xml_writer->xmlHeader();
6061 $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
6062 $a_xml_writer->xmlStartTag("questestinterop");
6063
6064 $attrs = array(
6065 "ident" => "il_" . IL_INST_ID . "_tst_" . $this->getTestId(),
6066 "title" => $this->getTitle()
6067 );
6068 $a_xml_writer->xmlStartTag("assessment", $attrs);
6069 // add qti comment
6070 $a_xml_writer->xmlElement("qticomment", null, $this->getDescription());
6071
6072 // add qti duration
6073 if ($this->enable_processing_time) {
6074 preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
6075 $a_xml_writer->xmlElement("duration", null, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
6076 }
6077
6078 // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
6079 $a_xml_writer->xmlStartTag("qtimetadata");
6080 $a_xml_writer->xmlStartTag("qtimetadatafield");
6081 $a_xml_writer->xmlElement("fieldlabel", null, "ILIAS_VERSION");
6082 $a_xml_writer->xmlElement("fieldentry", null, $this->ilias->getSetting("ilias_version"));
6083 $a_xml_writer->xmlEndTag("qtimetadatafield");
6084
6085 // anonymity
6086 $a_xml_writer->xmlStartTag("qtimetadatafield");
6087 $a_xml_writer->xmlElement("fieldlabel", null, "anonymity");
6088 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnonymity()));
6089 $a_xml_writer->xmlEndTag("qtimetadatafield");
6090
6091 $a_xml_writer->xmlStartTag("qtimetadatafield");
6092 $a_xml_writer->xmlElement("fieldlabel", null, "use_pool");
6093 $a_xml_writer->xmlElement("fieldentry", null, $this->getPoolUsage() ? 1 : 0);
6094 $a_xml_writer->xmlEndTag("qtimetadatafield");
6095
6096 // question set type (fixed, random, dynamic, ...)
6097 $a_xml_writer->xmlStartTag("qtimetadatafield");
6098 $a_xml_writer->xmlElement("fieldlabel", null, "question_set_type");
6099 $a_xml_writer->xmlElement("fieldentry", null, $this->getQuestionSetType());
6100 $a_xml_writer->xmlEndTag("qtimetadatafield");
6101
6102 // sequence settings
6103 $a_xml_writer->xmlStartTag("qtimetadatafield");
6104 $a_xml_writer->xmlElement("fieldlabel", null, "sequence_settings");
6105 $a_xml_writer->xmlElement("fieldentry", null, $this->getSequenceSettings());
6106 $a_xml_writer->xmlEndTag("qtimetadatafield");
6107
6108 // author
6109 $a_xml_writer->xmlStartTag("qtimetadatafield");
6110 $a_xml_writer->xmlElement("fieldlabel", null, "author");
6111 $a_xml_writer->xmlElement("fieldentry", null, $this->getAuthor());
6112 $a_xml_writer->xmlEndTag("qtimetadatafield");
6113
6114 // reset processing time
6115 $a_xml_writer->xmlStartTag("qtimetadatafield");
6116 $a_xml_writer->xmlElement("fieldlabel", null, "reset_processing_time");
6117 $a_xml_writer->xmlElement("fieldentry", null, $this->getResetProcessingTime());
6118 $a_xml_writer->xmlEndTag("qtimetadatafield");
6119
6120 // count system
6121 $a_xml_writer->xmlStartTag("qtimetadatafield");
6122 $a_xml_writer->xmlElement("fieldlabel", null, "count_system");
6123 $a_xml_writer->xmlElement("fieldentry", null, $this->getCountSystem());
6124 $a_xml_writer->xmlEndTag("qtimetadatafield");
6125
6126 // multiple choice scoring
6127 $a_xml_writer->xmlStartTag("qtimetadatafield");
6128 $a_xml_writer->xmlElement("fieldlabel", null, "mc_scoring");
6129 $a_xml_writer->xmlElement("fieldentry", null, $this->getMCScoring());
6130 $a_xml_writer->xmlEndTag("qtimetadatafield");
6131
6132 // multiple choice scoring
6133 $a_xml_writer->xmlStartTag("qtimetadatafield");
6134 $a_xml_writer->xmlElement("fieldlabel", null, "score_cutting");
6135 $a_xml_writer->xmlElement("fieldentry", null, $this->getScoreCutting());
6136 $a_xml_writer->xmlEndTag("qtimetadatafield");
6137
6138 // multiple choice scoring
6139 $a_xml_writer->xmlStartTag("qtimetadatafield");
6140 $a_xml_writer->xmlElement("fieldlabel", null, "password");
6141 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassword());
6142 $a_xml_writer->xmlEndTag("qtimetadatafield");
6143
6144 // allowed users
6145 $a_xml_writer->xmlStartTag("qtimetadatafield");
6146 $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsers");
6147 $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsers());
6148 $a_xml_writer->xmlEndTag("qtimetadatafield");
6149
6150 // allowed users time gap
6151 $a_xml_writer->xmlStartTag("qtimetadatafield");
6152 $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsersTimeGap");
6153 $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsersTimeGap());
6154 $a_xml_writer->xmlEndTag("qtimetadatafield");
6155
6156 // pass scoring
6157 $a_xml_writer->xmlStartTag("qtimetadatafield");
6158 $a_xml_writer->xmlElement("fieldlabel", null, "pass_scoring");
6159 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassScoring());
6160 $a_xml_writer->xmlEndTag("qtimetadatafield");
6161
6162 $a_xml_writer->xmlStartTag('qtimetadatafield');
6163 $a_xml_writer->xmlElement('fieldlabel', null, 'pass_deletion_allowed');
6164 $a_xml_writer->xmlElement('fieldentry', null, (int) $this->isPassDeletionAllowed());
6165 $a_xml_writer->xmlEndTag('qtimetadatafield');
6166
6167 // score reporting date
6168 if ($this->getReportingDate()) {
6169 $a_xml_writer->xmlStartTag("qtimetadatafield");
6170 $a_xml_writer->xmlElement("fieldlabel", null, "reporting_date");
6171 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6172 $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]));
6173 $a_xml_writer->xmlEndTag("qtimetadatafield");
6174 }
6175 // number of tries
6176 $a_xml_writer->xmlStartTag("qtimetadatafield");
6177 $a_xml_writer->xmlElement("fieldlabel", null, "nr_of_tries");
6178 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getNrOfTries()));
6179 $a_xml_writer->xmlEndTag("qtimetadatafield");
6180
6181 // number of tries
6182 $a_xml_writer->xmlStartTag('qtimetadatafield');
6183 $a_xml_writer->xmlElement('fieldlabel', null, 'block_after_passed');
6184 $a_xml_writer->xmlElement('fieldentry', null, (int) $this->isBlockPassesAfterPassedEnabled());
6185 $a_xml_writer->xmlEndTag('qtimetadatafield');
6186
6187 // pass_waiting
6188 $a_xml_writer->xmlStartTag("qtimetadatafield");
6189 $a_xml_writer->xmlElement("fieldlabel", null, "pass_waiting");
6190 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassWaiting());
6191 $a_xml_writer->xmlEndTag("qtimetadatafield");
6192
6193 // kiosk
6194 $a_xml_writer->xmlStartTag("qtimetadatafield");
6195 $a_xml_writer->xmlElement("fieldlabel", null, "kiosk");
6196 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getKiosk()));
6197 $a_xml_writer->xmlEndTag("qtimetadatafield");
6198
6199
6200 //redirection_mode
6201 $a_xml_writer->xmlStartTag('qtimetadatafield');
6202 $a_xml_writer->xmlElement("fieldlabel", null, "redirection_mode");
6203 $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionMode());
6204 $a_xml_writer->xmlEndTag("qtimetadatafield");
6205
6206 //redirection_url
6207 $a_xml_writer->xmlStartTag('qtimetadatafield');
6208 $a_xml_writer->xmlElement("fieldlabel", null, "redirection_url");
6209 $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionUrl());
6210 $a_xml_writer->xmlEndTag("qtimetadatafield");
6211
6212 // use previous answers
6213 $a_xml_writer->xmlStartTag("qtimetadatafield");
6214 $a_xml_writer->xmlElement("fieldlabel", null, "use_previous_answers");
6215 $a_xml_writer->xmlElement("fieldentry", null, $this->getUsePreviousAnswers());
6216 $a_xml_writer->xmlEndTag("qtimetadatafield");
6217
6218 // hide title points
6219 $a_xml_writer->xmlStartTag("qtimetadatafield");
6220 $a_xml_writer->xmlElement("fieldlabel", null, "title_output");
6221 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getTitleOutput()));
6222 $a_xml_writer->xmlEndTag("qtimetadatafield");
6223
6224 // results presentation
6225 $a_xml_writer->xmlStartTag("qtimetadatafield");
6226 $a_xml_writer->xmlElement("fieldlabel", null, "results_presentation");
6227 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getResultsPresentation()));
6228 $a_xml_writer->xmlEndTag("qtimetadatafield");
6229
6230 // examid in test pass
6231 $a_xml_writer->xmlStartTag("qtimetadatafield");
6232 $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_pass");
6233 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestPassEnabled()));
6234 $a_xml_writer->xmlEndTag("qtimetadatafield");
6235
6236 // examid in kiosk
6237 $a_xml_writer->xmlStartTag("qtimetadatafield");
6238 $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_res");
6239 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestResultsEnabled()));
6240 $a_xml_writer->xmlEndTag("qtimetadatafield");
6241
6242 // solution details
6243 $a_xml_writer->xmlStartTag("qtimetadatafield");
6244 $a_xml_writer->xmlElement("fieldlabel", null, "show_summary");
6245 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getListOfQuestionsSettings()));
6246 $a_xml_writer->xmlEndTag("qtimetadatafield");
6247
6248 // solution details
6249 $a_xml_writer->xmlStartTag("qtimetadatafield");
6250 $a_xml_writer->xmlElement("fieldlabel", null, "score_reporting");
6251 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getScoreReporting()));
6252 $a_xml_writer->xmlEndTag("qtimetadatafield");
6253
6254 $a_xml_writer->xmlStartTag("qtimetadatafield");
6255 $a_xml_writer->xmlElement("fieldlabel", null, "solution_details");
6256 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails());
6257 $a_xml_writer->xmlEndTag("qtimetadatafield");
6258 $a_xml_writer->xmlStartTag("qtimetadatafield");
6259 $a_xml_writer->xmlElement("fieldlabel", null, "print_bs_with_res");
6260 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails() ? (int) $this->isBestSolutionPrintedWithResult() : 0);
6261 $a_xml_writer->xmlEndTag("qtimetadatafield");
6262
6263 // solution details
6264 $a_xml_writer->xmlStartTag("qtimetadatafield");
6265 $a_xml_writer->xmlElement("fieldlabel", null, "instant_verification");
6266 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getInstantFeedbackSolution()));
6267 $a_xml_writer->xmlEndTag("qtimetadatafield");
6268
6269 // answer specific feedback
6270 $a_xml_writer->xmlStartTag("qtimetadatafield");
6271 $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback");
6272 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedback()));
6273 $a_xml_writer->xmlEndTag("qtimetadatafield");
6274
6275 // answer specific feedback of reached points
6276 $a_xml_writer->xmlStartTag("qtimetadatafield");
6277 $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback_points");
6278 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedbackPoints()));
6279 $a_xml_writer->xmlEndTag("qtimetadatafield");
6280
6281 // followup question previous answer freezing
6282 $a_xml_writer->xmlStartTag("qtimetadatafield");
6283 $a_xml_writer->xmlElement("fieldlabel", null, "follow_qst_answer_fixation");
6284 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isFollowupQuestionAnswerFixationEnabled());
6285 $a_xml_writer->xmlEndTag("qtimetadatafield");
6286
6287 // instant response answer freezing
6288 $a_xml_writer->xmlStartTag("qtimetadatafield");
6289 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6290 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6291 $a_xml_writer->xmlEndTag("qtimetadatafield");
6292
6293 // instant response forced
6294 $a_xml_writer->xmlStartTag("qtimetadatafield");
6295 $a_xml_writer->xmlElement("fieldlabel", null, "force_instant_feedback");
6296 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isForceInstantFeedbackEnabled());
6297 $a_xml_writer->xmlEndTag("qtimetadatafield");
6298
6299
6300 // highscore
6301 $highscore_metadata = array(
6302 'highscore_enabled' => array('value' => $this->getHighscoreEnabled()),
6303 'highscore_anon' => array('value' => $this->getHighscoreAnon()),
6304 'highscore_achieved_ts' => array('value' => $this->getHighscoreAchievedTS()),
6305 'highscore_score' => array('value' => $this->getHighscoreScore()),
6306 'highscore_percentage' => array('value' => $this->getHighscorePercentage()),
6307 'highscore_hints' => array('value' => $this->getHighscoreHints()),
6308 'highscore_wtime' => array('value' => $this->getHighscoreWTime()),
6309 'highscore_own_table' => array('value' => $this->getHighscoreOwnTable()),
6310 'highscore_top_table' => array('value' => $this->getHighscoreTopTable()),
6311 'highscore_top_num' => array('value' => $this->getHighscoreTopNum()),
6312 );
6313 foreach ($highscore_metadata as $label => $data) {
6314 $a_xml_writer->xmlStartTag("qtimetadatafield");
6315 $a_xml_writer->xmlElement("fieldlabel", null, $label);
6316 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $data['value']));
6317 $a_xml_writer->xmlEndTag("qtimetadatafield");
6318 }
6319
6320 // show cancel
6321 $a_xml_writer->xmlStartTag("qtimetadatafield");
6322 $a_xml_writer->xmlElement("fieldlabel", null, "show_cancel");
6323 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowCancel()));
6324 $a_xml_writer->xmlEndTag("qtimetadatafield");
6325
6326 // show marker
6327 $a_xml_writer->xmlStartTag("qtimetadatafield");
6328 $a_xml_writer->xmlElement("fieldlabel", null, "show_marker");
6329 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowMarker()));
6330 $a_xml_writer->xmlEndTag("qtimetadatafield");
6331
6332 // fixed participants
6333 $a_xml_writer->xmlStartTag("qtimetadatafield");
6334 $a_xml_writer->xmlElement("fieldlabel", null, "fixed_participants");
6335 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getFixedParticipants()));
6336 $a_xml_writer->xmlEndTag("qtimetadatafield");
6337
6338 // show final statement
6339 $a_xml_writer->xmlStartTag("qtimetadatafield");
6340 $a_xml_writer->xmlElement("fieldlabel", null, "showfinalstatement");
6341 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6342 $a_xml_writer->xmlEndTag("qtimetadatafield");
6343
6344 // show introduction only
6345 $a_xml_writer->xmlStartTag("qtimetadatafield");
6346 $a_xml_writer->xmlElement("fieldlabel", null, "showinfo");
6347 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6348 $a_xml_writer->xmlEndTag("qtimetadatafield");
6349
6350 // mail notification
6351 $a_xml_writer->xmlStartTag("qtimetadatafield");
6352 $a_xml_writer->xmlElement("fieldlabel", null, "mailnotification");
6353 $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotification());
6354 $a_xml_writer->xmlEndTag("qtimetadatafield");
6355
6356 // mail notification type
6357 $a_xml_writer->xmlStartTag("qtimetadatafield");
6358 $a_xml_writer->xmlElement("fieldlabel", null, "mailnottype");
6359 $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotificationType());
6360 $a_xml_writer->xmlEndTag("qtimetadatafield");
6361
6362 // export settings
6363 $a_xml_writer->xmlStartTag("qtimetadatafield");
6364 $a_xml_writer->xmlElement("fieldlabel", null, "exportsettings");
6365 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getExportSettings());
6366 $a_xml_writer->xmlEndTag("qtimetadatafield");
6367
6368 // force JavaScript
6369 $a_xml_writer->xmlStartTag("qtimetadatafield");
6370 $a_xml_writer->xmlElement("fieldlabel", null, "forcejs");
6371 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6372 $a_xml_writer->xmlEndTag("qtimetadatafield");
6373
6374 // custom style
6375 $a_xml_writer->xmlStartTag("qtimetadatafield");
6376 $a_xml_writer->xmlElement("fieldlabel", null, "customstyle");
6377 $a_xml_writer->xmlElement("fieldentry", null, $this->getCustomStyle());
6378 $a_xml_writer->xmlEndTag("qtimetadatafield");
6379
6380 // shuffle questions
6381 $a_xml_writer->xmlStartTag("qtimetadatafield");
6382 $a_xml_writer->xmlElement("fieldlabel", null, "shuffle_questions");
6383 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShuffleQuestions()));
6384 $a_xml_writer->xmlEndTag("qtimetadatafield");
6385
6386 // processing time
6387 $a_xml_writer->xmlStartTag("qtimetadatafield");
6388 $a_xml_writer->xmlElement("fieldlabel", null, "processing_time");
6389 $a_xml_writer->xmlElement("fieldentry", null, $this->getProcessingTime());
6390 $a_xml_writer->xmlEndTag("qtimetadatafield");
6391
6392 // enable_examview
6393 $a_xml_writer->xmlStartTag("qtimetadatafield");
6394 $a_xml_writer->xmlElement("fieldlabel", null, "enable_examview");
6395 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableExamview());
6396 $a_xml_writer->xmlEndTag("qtimetadatafield");
6397
6398 // show_examview_html
6399 $a_xml_writer->xmlStartTag("qtimetadatafield");
6400 $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_html");
6401 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewHtml());
6402 $a_xml_writer->xmlEndTag("qtimetadatafield");
6403
6404 // show_examview_pdf
6405 $a_xml_writer->xmlStartTag("qtimetadatafield");
6406 $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_pdf");
6407 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewPdf());
6408 $a_xml_writer->xmlEndTag("qtimetadatafield");
6409
6410 // enable_archiving
6411 $a_xml_writer->xmlStartTag("qtimetadatafield");
6412 $a_xml_writer->xmlElement("fieldlabel", null, "enable_archiving");
6413 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableArchiving());
6414 $a_xml_writer->xmlEndTag("qtimetadatafield");
6415
6416 // sign_submission
6417 $a_xml_writer->xmlStartTag("qtimetadatafield");
6418 $a_xml_writer->xmlElement("fieldlabel", null, "sign_submission");
6419 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSignSubmission());
6420 $a_xml_writer->xmlEndTag("qtimetadatafield");
6421
6422 // char_selector_availability
6423 $a_xml_writer->xmlStartTag("qtimetadatafield");
6424 $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_availability");
6425 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getCharSelectorAvailability()));
6426 $a_xml_writer->xmlEndTag("qtimetadatafield");
6427
6428 // char_selector_definition
6429 $a_xml_writer->xmlStartTag("qtimetadatafield");
6430 $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_definition");
6431 $a_xml_writer->xmlElement("fieldentry", null, $this->getCharSelectorDefinition());
6432 $a_xml_writer->xmlEndTag("qtimetadatafield");
6433
6434 // skill_service
6435 $a_xml_writer->xmlStartTag("qtimetadatafield");
6436 $a_xml_writer->xmlElement("fieldlabel", null, "skill_service");
6437 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isSkillServiceEnabled());
6438 $a_xml_writer->xmlEndTag("qtimetadatafield");
6439
6440 // result_tax_filters
6441 $a_xml_writer->xmlStartTag("qtimetadatafield");
6442 $a_xml_writer->xmlElement("fieldlabel", null, "result_tax_filters");
6443 $a_xml_writer->xmlElement("fieldentry", null, serialize((array) $this->getResultFilterTaxIds()));
6444 $a_xml_writer->xmlEndTag("qtimetadatafield");
6445
6446 // show_grading_status
6447 $a_xml_writer->xmlStartTag("qtimetadatafield");
6448 $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_status");
6449 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingStatusEnabled());
6450 $a_xml_writer->xmlEndTag("qtimetadatafield");
6451
6452 // show_grading_mark
6453 $a_xml_writer->xmlStartTag("qtimetadatafield");
6454 $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_mark");
6455 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingMarkEnabled());
6456 $a_xml_writer->xmlEndTag("qtimetadatafield");
6457
6458
6459 // starting time
6460 if ($this->getStartingTime()) {
6461 $a_xml_writer->xmlStartTag("qtimetadatafield");
6462 $a_xml_writer->xmlElement("fieldlabel", null, "starting_time");
6463 $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->starting_time);
6464 $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6465 $a_xml_writer->xmlEndTag("qtimetadatafield");
6466 }
6467 // ending time
6468 if ($this->getEndingTime()) {
6469 $a_xml_writer->xmlStartTag("qtimetadatafield");
6470 $a_xml_writer->xmlElement("fieldlabel", null, "ending_time");
6471 $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->ending_time);
6472 $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6473 $a_xml_writer->xmlEndTag("qtimetadatafield");
6474 }
6475
6476
6477 //activation_limited
6478 $a_xml_writer->xmlStartTag("qtimetadatafield");
6479 $a_xml_writer->xmlElement("fieldlabel", null, "activation_limited");
6480 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isActivationLimited());
6481 $a_xml_writer->xmlEndTag("qtimetadatafield");
6482
6483 //activation_start_time
6484 $a_xml_writer->xmlStartTag("qtimetadatafield");
6485 $a_xml_writer->xmlElement("fieldlabel", null, "activation_start_time");
6486 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationStartingTime());
6487 $a_xml_writer->xmlEndTag("qtimetadatafield");
6488
6489 //activation_end_time
6490 $a_xml_writer->xmlStartTag("qtimetadatafield");
6491 $a_xml_writer->xmlElement("fieldlabel", null, "activation_end_time");
6492 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationEndingTime());
6493 $a_xml_writer->xmlEndTag("qtimetadatafield");
6494
6495 //activation_visibility
6496 $a_xml_writer->xmlStartTag("qtimetadatafield");
6497 $a_xml_writer->xmlElement("fieldlabel", null, "activation_visibility");
6498 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationVisibility());
6499 $a_xml_writer->xmlEndTag("qtimetadatafield");
6500
6501 // autosave
6502 $a_xml_writer->xmlStartTag("qtimetadatafield");
6503 $a_xml_writer->xmlElement("fieldlabel", null, "autosave");
6504 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosave());
6505 $a_xml_writer->xmlEndTag("qtimetadatafield");
6506
6507 // autosave_ival
6508 $a_xml_writer->xmlStartTag("qtimetadatafield");
6509 $a_xml_writer->xmlElement("fieldlabel", null, "autosave_ival");
6510 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosaveIval());
6511 $a_xml_writer->xmlEndTag("qtimetadatafield");
6512
6513 //offer_question_hints
6514 $a_xml_writer->xmlStartTag("qtimetadatafield");
6515 $a_xml_writer->xmlElement("fieldlabel", null, "offer_question_hints");
6516 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isOfferingQuestionHintsEnabled());
6517 $a_xml_writer->xmlEndTag("qtimetadatafield");
6518
6519 //instant_feedback_specific
6520 $a_xml_writer->xmlStartTag("qtimetadatafield");
6521 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_specific");
6522 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSpecificAnswerFeedback());
6523 $a_xml_writer->xmlEndTag("qtimetadatafield");
6524
6525 //instant_feedback_answer_fixation
6526 $a_xml_writer->xmlStartTag("qtimetadatafield");
6527 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6528 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6529 $a_xml_writer->xmlEndTag("qtimetadatafield");
6530
6531 //obligations_enabled
6532 $a_xml_writer->xmlStartTag("qtimetadatafield");
6533 $a_xml_writer->xmlElement("fieldlabel", null, "obligations_enabled");
6534 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->areObligationsEnabled());
6535 $a_xml_writer->xmlEndTag("qtimetadatafield");
6536
6537 //enable_processing_time
6538 $a_xml_writer->xmlStartTag("qtimetadatafield");
6539 $a_xml_writer->xmlElement("fieldlabel", null, "enable_processing_time");
6540 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableProcessingTime());
6541 $a_xml_writer->xmlEndTag("qtimetadatafield");
6542
6543 foreach ($this->mark_schema->mark_steps as $index => $mark) {
6544 // mark steps
6545 $a_xml_writer->xmlStartTag("qtimetadatafield");
6546 $a_xml_writer->xmlElement("fieldlabel", null, "mark_step_$index");
6547 $a_xml_writer->xmlElement("fieldentry", null, sprintf(
6548 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
6549 $mark->getShortName(),
6550 $mark->getOfficialName(),
6551 $mark->getMinimumLevel(),
6552 $mark->getPassed()
6553 ));
6554 $a_xml_writer->xmlEndTag("qtimetadatafield");
6555 }
6556 $a_xml_writer->xmlEndTag("qtimetadata");
6557
6558 // add qti objectives
6559 $a_xml_writer->xmlStartTag("objectives");
6560 $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6561 $a_xml_writer->xmlEndTag("objectives");
6562
6563 // add qti assessmentcontrol
6564 if ($this->getInstantFeedbackSolution() == 1) {
6565 $attrs = array(
6566 "solutionswitch" => "Yes"
6567 );
6568 } else {
6569 $attrs = null;
6570 }
6571 $a_xml_writer->xmlElement("assessmentcontrol", $attrs, null);
6572
6573 if (strlen($this->getFinalStatement())) {
6574 // add qti presentation_material
6575 $a_xml_writer->xmlStartTag("presentation_material");
6576 $a_xml_writer->xmlStartTag("flow_mat");
6577 $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6578 $a_xml_writer->xmlEndTag("flow_mat");
6579 $a_xml_writer->xmlEndTag("presentation_material");
6580 }
6581
6582 $attrs = array(
6583 "ident" => "1"
6584 );
6585 $a_xml_writer->xmlElement("section", $attrs, null);
6586 $a_xml_writer->xmlEndTag("assessment");
6587 $a_xml_writer->xmlEndTag("questestinterop");
6588
6589 $xml = $a_xml_writer->xmlDumpMem(false);
6590 return $xml;
6591 }
6592
6598 {
6599 $date_time_unix = new ilDateTime($unix_timestamp, IL_CAL_UNIX);
6600 $date_time = $date_time_unix->get(IL_CAL_DATETIME);
6601 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $date_time, $matches);
6602 $iso8601_period = sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]);
6603 return $iso8601_period;
6604 }
6605
6612 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6613 {
6614 global $DIC;
6615 $ilBench = $DIC['ilBench'];
6616
6617 $this->mob_ids = array();
6618 $this->file_ids = array();
6619
6620 // MetaData
6621 $this->exportXMLMetaData($a_xml_writer);
6622
6623 // PageObjects
6624 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Page Objects");
6625 $ilBench->start("ContentObjectExport", "exportPageObjects");
6626 $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6627 $ilBench->stop("ContentObjectExport", "exportPageObjects");
6628 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Page Objects");
6629
6630 // MediaObjects
6631 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Media Objects");
6632 $ilBench->start("ContentObjectExport", "exportMediaObjects");
6633 $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6634 $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6635 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Media Objects");
6636
6637 // FileItems
6638 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export File Items");
6639 $ilBench->start("ContentObjectExport", "exportFileItems");
6640 $this->exportFileItems($a_target_dir, $expLog);
6641 $ilBench->stop("ContentObjectExport", "exportFileItems");
6642 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export File Items");
6643 }
6644
6651 public function exportXMLMetaData(&$a_xml_writer)
6652 {
6653 include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6654 $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6655 $md2xml->setExportMode(true);
6656 $md2xml->startExport();
6657 $a_xml_writer->appendXML($md2xml->getXML());
6658 }
6659
6665 public function modifyExportIdentifier($a_tag, $a_param, $a_value)
6666 {
6667 if ($a_tag == "Identifier" && $a_param == "Entry") {
6668 include_once "./Services/Utilities/classes/class.ilUtil.php";
6669 $a_value = ilUtil::insertInstIntoID($a_value);
6670 }
6671
6672 return $a_value;
6673 }
6674
6675
6682 public function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6683 {
6684 global $DIC;
6685 $ilBench = $DIC['ilBench'];
6686
6687 include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6688
6689 foreach ($this->questions as $question_id) {
6690 $ilBench->start("ContentObjectExport", "exportPageObject");
6691 $expLog->write(date("[y-m-d H:i:s] ") . "Page Object " . $question_id);
6692
6693 $attrs = array();
6694 $a_xml_writer->xmlStartTag("PageObject", $attrs);
6695
6696
6697 // export xml to writer object
6698 $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6699 include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
6700 $page_object = new ilAssQuestionPage($question_id);
6701 $page_object->buildDom();
6702 $page_object->insertInstIntoIDs($a_inst);
6703 $mob_ids = $page_object->collectMediaObjects(false);
6704 require_once 'Services/COPage/classes/class.ilPCFileList.php';
6705 $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
6706 $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6707 $xml = str_replace("&", "&amp;", $xml);
6708 $a_xml_writer->appendXML($xml);
6709 $page_object->freeDom();
6710 unset($page_object);
6711
6712 $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6713
6714 // collect media objects
6715 $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6716 //$mob_ids = $page_obj->getMediaObjectIDs();
6717 foreach ($mob_ids as $mob_id) {
6718 $this->mob_ids[$mob_id] = $mob_id;
6719 }
6720 $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6721
6722 // collect all file items
6723 $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6724 //$file_ids = $page_obj->getFileItemIds();
6725 foreach ($file_ids as $file_id) {
6726 $this->file_ids[$file_id] = $file_id;
6727 }
6728 $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6729
6730 $a_xml_writer->xmlEndTag("PageObject");
6731 //unset($page_obj);
6732
6733 $ilBench->stop("ContentObjectExport", "exportPageObject");
6734 }
6735 }
6736
6743 public function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6744 {
6745 include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6746
6747 foreach ($this->mob_ids as $mob_id) {
6748 $expLog->write(date("[y-m-d H:i:s] ") . "Media Object " . $mob_id);
6749 if (ilObjMediaObject::_exists($mob_id)) {
6750 $media_obj = new ilObjMediaObject($mob_id);
6751 $media_obj->exportXML($a_xml_writer, $a_inst);
6752 $media_obj->exportFiles($a_target_dir);
6753 unset($media_obj);
6754 }
6755 }
6756 }
6757
6762 public function exportFileItems($target_dir, &$expLog)
6763 {
6764 include_once "./Modules/File/classes/class.ilObjFile.php";
6765
6766 foreach ($this->file_ids as $file_id) {
6767 $expLog->write(date("[y-m-d H:i:s] ") . "File Item " . $file_id);
6768 $file_dir = $target_dir . '/objects/il_' . IL_INST_ID . '_file_' . $file_id;
6769 ilUtil::makeDir($file_dir);
6770 $file_obj = new ilObjFile($file_id, false);
6771 $source_file = $file_obj->getFile($file_obj->getVersion());
6772 if (!is_file($source_file)) {
6773 $source_file = $file_obj->getFile();
6774 }
6775 if (is_file($source_file)) {
6776 copy($source_file, $file_dir . '/' . $file_obj->getFileName());
6777 }
6778 unset($file_obj);
6779 }
6780 }
6781
6786 public function getImportMapping()
6787 {
6788 if (!is_array($this->import_mapping)) {
6789 return array();
6790 } else {
6791 return $this->import_mapping;
6792 }
6793 }
6794
6798 public function canEditEctsGrades()
6799 {
6800 return $this->canShowEctsGrades() && $this->canEditMarks();
6801 }
6802
6806 public function canShowEctsGrades()
6807 {
6808 return $this->getReportingDate();
6809 }
6810
6814 public function getECTSGrade($passed_array, $reached_points, $max_points)
6815 {
6816 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);
6817 }
6818
6822 public static function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6823 {
6824 include_once "./Modules/Test/classes/class.ilStatistics.php";
6825 // calculate the median
6826 $passed_statistics = new ilStatistics();
6827 $passed_statistics->setData($points_passed);
6828 $ects_percentiles = array(
6829 "A" => $passed_statistics->quantile($a),
6830 "B" => $passed_statistics->quantile($b),
6831 "C" => $passed_statistics->quantile($c),
6832 "D" => $passed_statistics->quantile($d),
6833 "E" => $passed_statistics->quantile($e)
6834 );
6835 if (count($points_passed) && ($reached_points >= $ects_percentiles["A"])) {
6836 return "A";
6837 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["B"])) {
6838 return "B";
6839 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["C"])) {
6840 return "C";
6841 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["D"])) {
6842 return "D";
6843 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["E"])) {
6844 return "E";
6845 } elseif (strcmp($fx, "") != 0) {
6846 if ($max_points > 0) {
6847 $percentage = ($reached_points / $max_points) * 100.0;
6848 if ($percentage < 0) {
6849 $percentage = 0.0;
6850 }
6851 } else {
6852 $percentage = 0.0;
6853 }
6854 if ($percentage >= $fx) {
6855 return "FX";
6856 } else {
6857 return "F";
6858 }
6859 } else {
6860 return "F";
6861 }
6862 }
6863
6867 public function checkMarks()
6868 {
6869 return $this->mark_schema->checkMarks();
6870 }
6871
6875 public function getMarkSchema()
6876 {
6877 return $this->mark_schema;
6878 }
6879
6883 public function getMarkSchemaForeignId()
6884 {
6885 return $this->getTestId();
6886 }
6887
6890 public function onMarkSchemaSaved()
6891 {
6897 global $DIC;
6898 $ilDB = $DIC['ilDB'];
6899 $ilPluginAdmin = $DIC['ilPluginAdmin'];
6900 $tree = $DIC['tree'];
6901
6902 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
6903 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
6904 $this->saveCompleteStatus($testQuestionSetConfigFactory->getQuestionSetConfig());
6905
6906 if ($this->participantDataExist()) {
6907 $this->recalculateScores(true);
6908 }
6909 }
6910
6914 public function canEditMarks()
6915 {
6916 $total = $this->evalTotalPersons();
6917 if ($total > 0) {
6918 if ($this->getReportingDate()) {
6919 if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches)) {
6920 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
6921 $now = time();
6922 if ($now < $epoch_time) {
6923 return true;
6924 }
6925 }
6926 }
6927 return false;
6928 } else {
6929 return true;
6930 }
6931 }
6932
6940 public function setAuthor($author = "")
6941 {
6942 $this->author = $author;
6943 }
6944
6954 public function saveAuthorToMetadata($a_author = "")
6955 {
6956 $md = new ilMD($this->getId(), 0, $this->getType());
6957 $md_life = &$md->getLifecycle();
6958 if (!$md_life) {
6959 if (strlen($a_author) == 0) {
6960 global $DIC;
6961 $ilUser = $DIC['ilUser'];
6962 $a_author = $ilUser->getFullname();
6963 }
6964
6965 $md_life = &$md->addLifecycle();
6966 $md_life->save();
6967 $con = &$md_life->addContribute();
6968 $con->setRole("Author");
6969 $con->save();
6970 $ent = &$con->addEntity();
6971 $ent->setEntity($a_author);
6972 $ent->save();
6973 }
6974 }
6975
6981 public function createMetaData()
6982 {
6983 parent::createMetaData();
6984 $this->saveAuthorToMetadata();
6985 }
6986
6994 public function getAuthor()
6995 {
6996 $author = array();
6997 include_once "./Services/MetaData/classes/class.ilMD.php";
6998 $md = new ilMD($this->getId(), 0, $this->getType());
6999 $md_life = &$md->getLifecycle();
7000 if ($md_life) {
7001 $ids = &$md_life->getContributeIds();
7002 foreach ($ids as $id) {
7003 $md_cont = &$md_life->getContribute($id);
7004 if (strcmp($md_cont->getRole(), "Author") == 0) {
7005 $entids = &$md_cont->getEntityIds();
7006 foreach ($entids as $entid) {
7007 $md_ent = &$md_cont->getEntity($entid);
7008 array_push($author, $md_ent->getEntity());
7009 }
7010 }
7011 }
7012 }
7013 return join(",", $author);
7014 }
7015
7023 public static function _lookupAuthor($obj_id)
7024 {
7025 $author = array();
7026 include_once "./Services/MetaData/classes/class.ilMD.php";
7027 $md = new ilMD($obj_id, 0, "tst");
7028 $md_life = &$md->getLifecycle();
7029 if ($md_life) {
7030 $ids = &$md_life->getContributeIds();
7031 foreach ($ids as $id) {
7032 $md_cont = &$md_life->getContribute($id);
7033 if (strcmp($md_cont->getRole(), "Author") == 0) {
7034 $entids = &$md_cont->getEntityIds();
7035 foreach ($entids as $entid) {
7036 $md_ent = &$md_cont->getEntity($entid);
7037 array_push($author, $md_ent->getEntity());
7038 }
7039 }
7040 }
7041 }
7042 return join(",", $author);
7043 }
7044
7051 public static function _getAvailableTests($use_object_id = false)
7052 {
7053 global $DIC;
7054 $ilUser = $DIC['ilUser'];
7055 $ilDB = $DIC['ilDB'];
7056
7057 $result_array = array();
7058 $tests = array_slice(
7059 array_reverse(
7060 ilUtil::_getObjectsByOperations("tst", "write", $ilUser->getId(), PHP_INT_MAX)
7061 ),
7062 0,
7063 10000
7064 );
7065
7066 if (count($tests)) {
7067 $titles = ilObject::_prepareCloneSelection($tests, "tst");
7068 foreach ($tests as $ref_id) {
7069 if ($use_object_id) {
7071 $result_array[$obj_id] = $titles[$ref_id];
7072 } else {
7073 $result_array[$ref_id] = $titles[$ref_id];
7074 }
7075 }
7076 }
7077 return $result_array;
7078 }
7079
7088 public function cloneObject($a_target_id, $a_copy_id = 0, $a_omit_tree = false)
7089 {
7090 global $DIC;
7091
7092 $certificateLogger = $DIC->logger()->cert();
7093 $tree = $DIC['tree'];
7094 $ilDB = $DIC->database();
7095 $ilPluginAdmin = $DIC['ilPluginAdmin'];
7096
7097 $this->loadFromDb();
7098
7099 // Copy settings
7101 $newObj = parent::cloneObject($a_target_id, $a_copy_id, $a_omit_tree);
7102 $newObj->setTmpCopyWizardCopyId($a_copy_id);
7103 $this->cloneMetaData($newObj);
7104
7105 //copy online status if object is not the root copy object
7106 $cp_options = ilCopyWizardOptions::_getInstance($a_copy_id);
7107 if ($cp_options->isRootNode($this->getRefId())) {
7108 $newObj->setOfflineStatus(true);
7109 } else {
7110 $newObj->setOfflineStatus($this->getOfflineStatus());
7111 }
7112 $newObj->update();
7113
7114 $newObj->setAnonymity($this->getAnonymity());
7115 $newObj->setAnswerFeedback($this->getAnswerFeedback());
7116 $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
7117 $newObj->setAuthor($this->getAuthor());
7118 $newObj->setLimitUsersEnabled($this->isLimitUsersEnabled());
7119 $newObj->setAllowedUsers($this->getAllowedUsers());
7120 $newObj->setAllowedUsersTimeGap($this->getAllowedUsersTimeGap());
7121 $newObj->setCountSystem($this->getCountSystem());
7122 $newObj->setECTSFX($this->getECTSFX());
7123 $newObj->setECTSGrades($this->getECTSGrades());
7124 $newObj->setECTSOutput($this->getECTSOutput());
7125 $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
7126 $newObj->setEndingTimeEnabled($this->isEndingTimeEnabled());
7127 $newObj->setEndingTime($this->getEndingTime());
7128 $newObj->setFixedParticipants($this->getFixedParticipants());
7129 $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
7130 $newObj->setIntroductionEnabled($this->isIntroductionEnabled());
7131 $newObj->setIntroduction($this->getIntroduction());
7132 $newObj->setFinalStatement($this->getFinalStatement());
7133 $newObj->setShowInfo($this->getShowInfo());
7134 $newObj->setForceJS($this->getForceJS());
7135 $newObj->setCustomStyle($this->getCustomStyle());
7136 $newObj->setKiosk($this->getKiosk());
7137 $newObj->setShowFinalStatement($this->getShowFinalStatement());
7138 $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
7139 $newObj->setMCScoring($this->getMCScoring());
7140 $newObj->setMailNotification($this->getMailNotification());
7141 $newObj->setMailNotificationType($this->getMailNotificationType());
7142 $newObj->setNrOfTries($this->getNrOfTries());
7143 $newObj->setBlockPassesAfterPassedEnabled($this->isBlockPassesAfterPassedEnabled());
7144 $newObj->setPassScoring($this->getPassScoring());
7145 $newObj->setPasswordEnabled($this->isPasswordEnabled());
7146 $newObj->setPassword($this->getPassword());
7147 $newObj->setProcessingTime($this->getProcessingTime());
7148 $newObj->setQuestionSetType($this->getQuestionSetType());
7149 $newObj->setReportingDate($this->getReportingDate());
7150 $newObj->setResetProcessingTime($this->getResetProcessingTime());
7151 $newObj->setResultsPresentation($this->getResultsPresentation());
7152 $newObj->setScoreCutting($this->getScoreCutting());
7153 $newObj->setScoreReporting($this->getScoreReporting());
7154 $newObj->setShowGradingStatusEnabled($this->isShowGradingStatusEnabled());
7155 $newObj->setShowGradingMarkEnabled($this->isShowGradingMarkEnabled());
7156 $newObj->setSequenceSettings($this->getSequenceSettings());
7157 $newObj->setShowCancel($this->getShowCancel());
7158 $newObj->setShowMarker($this->getShowMarker());
7159 $newObj->setShuffleQuestions($this->getShuffleQuestions());
7160 $newObj->setStartingTimeEnabled($this->isStartingTimeEnabled());
7161 $newObj->setStartingTime($this->getStartingTime());
7162 $newObj->setTitleOutput($this->getTitleOutput());
7163 $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
7164 $newObj->setRedirectionMode($this->getRedirectionMode());
7165 $newObj->setRedirectionUrl($this->getRedirectionUrl());
7166 $newObj->setCertificateVisibility($this->getCertificateVisibility());
7167 $newObj->mark_schema = clone $this->mark_schema;
7168 $newObj->setEnabledViewMode($this->getEnabledViewMode());
7169 $newObj->setTemplate($this->getTemplate());
7170 $newObj->setPoolUsage($this->getPoolUsage());
7171 $newObj->setPrintBestSolutionWithResult($this->isBestSolutionPrintedWithResult());
7172 $newObj->setShowExamIdInTestPassEnabled($this->isShowExamIdInTestPassEnabled());
7173 $newObj->setShowExamIdInTestResultsEnabled($this->isShowExamIdInTestResultsEnabled());
7174 $newObj->setEnableExamView($this->getEnableExamview());
7175 $newObj->setShowExamViewHtml($this->getShowExamviewHtml());
7176 $newObj->setShowExamViewPdf($this->getShowExamviewPdf());
7177 $newObj->setEnableArchiving($this->getEnableArchiving());
7178 $newObj->setSignSubmission($this->getSignSubmission());
7179 $newObj->setCharSelectorAvailability((int) $this->getCharSelectorAvailability());
7180 $newObj->setCharSelectorDefinition($this->getCharSelectorDefinition());
7181 $newObj->setSkillServiceEnabled($this->isSkillServiceEnabled());
7182 $newObj->setResultFilterTaxIds($this->getResultFilterTaxIds());
7183 $newObj->setPassDeletionAllowed($this->isPassDeletionAllowed());
7184 $newObj->setFollowupQuestionAnswerFixationEnabled($this->isFollowupQuestionAnswerFixationEnabled());
7185 $newObj->setInstantFeedbackAnswerFixationEnabled($this->isInstantFeedbackAnswerFixationEnabled());
7186 $newObj->setForceInstantFeedbackEnabled($this->isForceInstantFeedbackEnabled());
7187 $newObj->setAutosave($this->getAutosave());
7188 $newObj->setAutosaveIval($this->getAutosaveIval());
7189 $newObj->setOfferingQuestionHintsEnabled($this->isOfferingQuestionHintsEnabled());
7190 $newObj->setSpecificAnswerFeedback($this->getSpecificAnswerFeedback());
7191 if ($this->isPassWaitingEnabled()) {
7192 $newObj->setPassWaiting($this->getPassWaiting());
7193 }
7194 $newObj->setObligationsEnabled($this->areObligationsEnabled());
7195 $newObj->saveToDb();
7196
7197 // clone certificate
7198 $pathFactory = new ilCertificatePathFactory();
7199 $templateRepository = new ilCertificateTemplateRepository($ilDB);
7200
7201 $cloneAction = new ilCertificateCloneAction(
7202 $ilDB,
7203 $pathFactory,
7204 $templateRepository,
7205 $DIC->filesystem()->web(),
7206 $certificateLogger,
7208 );
7209
7210 $cloneAction->cloneCertificate($this, $newObj);
7211
7212 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7213 $testQuestionSetConfigFactory->getQuestionSetConfig()->cloneQuestionSetRelatedData($newObj);
7214
7215 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdList.php';
7216 $skillLevelThresholdList = new ilTestSkillLevelThresholdList($ilDB);
7217 $skillLevelThresholdList->setTestId($this->getTestId());
7218 $skillLevelThresholdList->loadFromDb();
7219 $skillLevelThresholdList->cloneListForTest($newObj->getTestId());
7220
7221 $newObj->saveToDb();
7222 $newObj->updateMetaData();// #14467
7223
7224 include_once('./Services/Tracking/classes/class.ilLPObjSettings.php');
7225 $obj_settings = new ilLPObjSettings($this->getId());
7226 $obj_settings->cloneSettings($newObj->getId());
7227
7228 return $newObj;
7229 }
7230
7237 public function getQuestionCount()
7238 {
7239 $num = 0;
7240
7241 if ($this->isRandomTest()) {
7242 global $DIC;
7243 $tree = $DIC['tree'];
7244 $ilDB = $DIC['ilDB'];
7245 $ilPluginAdmin = $DIC['ilPluginAdmin'];
7246
7247 $questionSetConfig = new ilTestRandomQuestionSetConfig(
7248 $tree,
7249 $ilDB,
7250 $ilPluginAdmin,
7251 $this
7252 );
7253
7254 $questionSetConfig->loadFromDb();
7255
7256 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
7257 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php';
7258 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetBuilderWithAmountPerPool.php';
7259 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php';
7260
7261 $sourcePoolDefinitionList = new ilTestRandomQuestionSetSourcePoolDefinitionList(
7262 $ilDB,
7263 $this,
7265 );
7266
7267 $sourcePoolDefinitionList->loadDefinitions();
7268
7269 $num = $sourcePoolDefinitionList->getQuestionAmount();
7270 } else {
7271 $num = $questionSetConfig->getQuestionAmountPerTest();
7272 }
7273 } else {
7274 $num = count($this->questions);
7275 }
7276
7277 return $num;
7278 }
7279
7287 public function logAction($logtext = "", $question_id = "")
7288 {
7289 global $DIC;
7290 $ilUser = $DIC['ilUser'];
7291
7292 $original_id = "";
7293 if (strcmp($question_id, "") != 0) {
7294 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7295 $original_id = assQuestion::_getOriginalId($question_id);
7296 }
7297 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7298 ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, true, $this->getRefId());
7299 }
7300
7308 public static function _getObjectIDFromTestID($test_id)
7309 {
7310 global $DIC;
7311 $ilDB = $DIC['ilDB'];
7312 $object_id = false;
7313 $result = $ilDB->queryF(
7314 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7315 array('integer'),
7316 array($test_id)
7317 );
7318 if ($result->numRows()) {
7319 $row = $ilDB->fetchAssoc($result);
7320 $object_id = $row["obj_fi"];
7321 }
7322 return $object_id;
7323 }
7324
7332 public static function _getObjectIDFromActiveID($active_id)
7333 {
7334 global $DIC;
7335 $ilDB = $DIC['ilDB'];
7336 $object_id = false;
7337 $result = $ilDB->queryF(
7338 "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",
7339 array('integer'),
7340 array($active_id)
7341 );
7342 if ($result->numRows()) {
7343 $row = $ilDB->fetchAssoc($result);
7344 $object_id = $row["obj_fi"];
7345 }
7346 return $object_id;
7347 }
7348
7356 public static function _getTestIDFromObjectID($object_id)
7357 {
7358 global $DIC;
7359 $ilDB = $DIC['ilDB'];
7360 $test_id = false;
7361 $result = $ilDB->queryF(
7362 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7363 array('integer'),
7364 array($object_id)
7365 );
7366 if ($result->numRows()) {
7367 $row = $ilDB->fetchAssoc($result);
7368 $test_id = $row["test_id"];
7369 }
7370 return $test_id;
7371 }
7372
7381 public function getTextAnswer($active_id, $question_id, $pass = null)
7382 {
7383 global $DIC;
7384 $ilDB = $DIC['ilDB'];
7385
7386 $res = "";
7387 if (($active_id) && ($question_id)) {
7388 if (is_null($pass)) {
7389 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7390 $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7391 }
7392 $result = $ilDB->queryF(
7393 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7394 array('integer', 'integer', 'integer'),
7395 array($active_id, $question_id, $pass)
7396 );
7397 if ($result->numRows() == 1) {
7398 $row = $ilDB->fetchAssoc($result);
7399 $res = $row["value1"];
7400 }
7401 }
7402 return $res;
7403 }
7404
7412 public function getQuestiontext($question_id)
7413 {
7414 global $DIC;
7415 $ilDB = $DIC['ilDB'];
7416
7417 $res = "";
7418 if ($question_id) {
7419 $result = $ilDB->queryF(
7420 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
7421 array('integer'),
7422 array($question_id)
7423 );
7424 if ($result->numRows() == 1) {
7425 $row = $ilDB->fetchAssoc($result);
7426 $res = $row["question_text"];
7427 }
7428 }
7429 return $res;
7430 }
7431
7436 {
7437 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
7438 $participantList = new ilTestParticipantList($this);
7439 $participantList->initializeFromDbRows($this->getInvitedUsers());
7440
7441 return $participantList;
7442 }
7443
7448 {
7449 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
7450 $participantList = new ilTestParticipantList($this);
7451 $participantList->initializeFromDbRows($this->getTestParticipants());
7452
7453 return $participantList;
7454 }
7455
7462 public function &getInvitedUsers($user_id = "", $order = "login, lastname, firstname")
7463 {
7464 global $DIC;
7465 $ilDB = $DIC['ilDB'];
7466
7467 $result_array = array();
7468
7469 if ($this->getAnonymity()) {
7470 if (is_numeric($user_id)) {
7471 $result = $ilDB->queryF(
7472 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7473 "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 " .
7474 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7475 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7476 "ORDER BY $order",
7477 array('text', 'text', 'text', 'integer', 'integer'),
7478 array("", $this->lng->txt("anonymous"), "", $this->getTestId(), $user_id)
7479 );
7480 } else {
7481 $result = $ilDB->queryF(
7482 "SELECT tst_active.active_id, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7483 "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 " .
7484 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7485 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7486 "ORDER BY $order",
7487 array('text', 'text', 'text', 'integer'),
7488 array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7489 );
7490 }
7491 } else {
7492 if (is_numeric($user_id)) {
7493 $result = $ilDB->queryF(
7494 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7495 "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 " .
7496 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7497 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7498 "ORDER BY $order",
7499 array('integer', 'integer'),
7500 array($this->getTestId(), $user_id)
7501 );
7502 } else {
7503 $result = $ilDB->queryF(
7504 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7505 "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 " .
7506 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7507 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7508 "ORDER BY $order",
7509 array('integer'),
7510 array($this->getTestId())
7511 );
7512 }
7513 }
7514 $result_array = array();
7515 while ($row = $ilDB->fetchAssoc($result)) {
7516 $result_array[$row['usr_id']] = $row;
7517 }
7518 return $result_array;
7519 }
7520
7527 public function &getTestParticipants()
7528 {
7529 global $DIC;
7530 $ilDB = $DIC['ilDB'];
7531
7532 if ($this->getAnonymity()) {
7533 $query = "
7534 SELECT tst_active.active_id,
7535 tst_active.tries,
7536 tst_active.user_fi usr_id,
7537 %s login,
7538 %s lastname,
7539 %s firstname,
7540 tst_active.submitted test_finished,
7541 usr_data.matriculation,
7542 usr_data.active,
7543 tst_active.lastindex,
7544 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7545 FROM tst_active
7546 LEFT JOIN usr_data
7547 ON tst_active.user_fi = usr_data.usr_id
7548 WHERE tst_active.test_fi = %s
7549 ORDER BY usr_data.lastname
7550 ";
7551 $result = $ilDB->queryF(
7552 $query,
7553 array('text', 'text', 'text', 'integer'),
7554 array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7555 );
7556 } else {
7557 $query = "
7558 SELECT tst_active.active_id,
7559 tst_active.tries,
7560 tst_active.user_fi usr_id,
7561 usr_data.login,
7562 usr_data.lastname,
7563 usr_data.firstname,
7564 tst_active.submitted test_finished,
7565 usr_data.matriculation,
7566 usr_data.active,
7567 tst_active.lastindex,
7568 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7569 FROM tst_active
7570 LEFT JOIN usr_data
7571 ON tst_active.user_fi = usr_data.usr_id
7572 WHERE tst_active.test_fi = %s
7573 ORDER BY usr_data.lastname
7574 ";
7575 $result = $ilDB->queryF(
7576 $query,
7577 array('integer'),
7578 array($this->getTestId())
7579 );
7580 }
7581 $data = array();
7582 while ($row = $ilDB->fetchAssoc($result)) {
7583 $data[$row['active_id']] = $row;
7584 }
7585 foreach ($data as $index => $participant) {
7586 if (strlen(trim($participant["firstname"] . $participant["lastname"])) == 0) {
7587 $data[$index]["lastname"] = $this->lng->txt("deleted_user");
7588 }
7589 }
7590 return $data;
7591 }
7592
7593 public function getTestParticipantsForManualScoring($filter = null)
7594 {
7595 global $DIC;
7596 $ilDB = $DIC['ilDB'];
7597
7598 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7600 if (count($scoring) == 0) {
7601 return array();
7602 }
7603
7604 $participants = &$this->getTestParticipants();
7605 $filtered_participants = array();
7606 foreach ($participants as $active_id => $participant) {
7607 $qstType_IN_manScoreableQstTypes = $ilDB->in('qpl_questions.question_type_fi', $scoring, false, 'integer');
7608
7609 $queryString = "
7610 SELECT tst_test_result.manual
7611
7612 FROM tst_test_result
7613
7614 INNER JOIN qpl_questions
7615 ON tst_test_result.question_fi = qpl_questions.question_id
7616
7617 WHERE tst_test_result.active_fi = %s
7618 AND $qstType_IN_manScoreableQstTypes
7619 ";
7620
7621 $result = $ilDB->queryF(
7622 $queryString,
7623 array("integer"),
7624 array($active_id)
7625 );
7626
7627 $count = $result->numRows();
7628
7629 if ($count > 0) {
7630 switch ($filter) {
7631 case 1: // only active users
7632 if ($participant->active) {
7633 $filtered_participants[$active_id] = $participant;
7634 }
7635 break;
7636 case 2: // only inactive users
7637 if (!$participant->active) {
7638 $filtered_participants[$active_id] = $participant;
7639 }
7640 break;
7641 case 3: // all users
7642 $filtered_participants[$active_id] = $participant;
7643 break;
7644 case 4:
7645 // already scored participants
7646 //$found = 0;
7647 //while ($row = $ilDB->fetchAssoc($result))
7648 //{
7649 // if ($row["manual"]) $found++;
7650 //}
7651 //if ($found == $count)
7652 //{
7653 //$filtered_participants[$active_id] = $participant;
7654 //}
7655 //else
7656 //{
7657 $assessmentSetting = new ilSetting("assessment");
7658 $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7659 if ($manscoring_done) {
7660 $filtered_participants[$active_id] = $participant;
7661 }
7662 //}
7663 break;
7664 case 5:
7665 // unscored participants
7666 //$found = 0;
7667 //while ($row = $ilDB->fetchAssoc($result))
7668 //{
7669 // if ($row["manual"]) $found++;
7670 //}
7671 //if ($found == 0)
7672 //{
7673 $assessmentSetting = new ilSetting("assessment");
7674 $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7675 if (!$manscoring_done) {
7676 $filtered_participants[$active_id] = $participant;
7677 }
7678 //}
7679 break;
7680 case 6:
7681 // partially scored participants
7682 $found = 0;
7683 while ($row = $ilDB->fetchAssoc($result)) {
7684 if ($row["manual"]) {
7685 $found++;
7686 }
7687 }
7688 if (($found > 0) && ($found < $count)) {
7689 $filtered_participants[$active_id] = $participant;
7690 }
7691 break;
7692 default:
7693 $filtered_participants[$active_id] = $participant;
7694 break;
7695 }
7696 }
7697 }
7698 return $filtered_participants;
7699 }
7700
7708 public function &getUserData($ids)
7709 {
7710 global $DIC;
7711 $ilDB = $DIC['ilDB'];
7712
7713 if (!is_array($ids) || count($ids) == 0) {
7714 return array();
7715 }
7716
7717 if ($this->getAnonymity()) {
7718 $result = $ilDB->queryF(
7719 "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",
7720 array('text', 'text', 'text'),
7721 array("", $this->lng->txt("anonymous"), "")
7722 );
7723 } else {
7724 $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");
7725 }
7726
7727 $result_array = array();
7728 while ($row = $ilDB->fetchAssoc($result)) {
7729 $result_array[$row["usr_id"]] = $row;
7730 }
7731 return $result_array;
7732 }
7733
7734 public function &getGroupData($ids)
7735 {
7736 if (!is_array($ids) || count($ids) == 0) {
7737 return array();
7738 }
7739 $result = array();
7740 foreach ($ids as $ref_id) {
7742 $result[$ref_id] = array("ref_id" => $ref_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7743 }
7744 return $result;
7745 }
7746
7747 public function &getRoleData($ids)
7748 {
7749 if (!is_array($ids) || count($ids) == 0) {
7750 return array();
7751 }
7752 $result = array();
7753 foreach ($ids as $obj_id) {
7754 $result[$obj_id] = array("obj_id" => $obj_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7755 }
7756 return $result;
7757 }
7758
7759
7766 public function inviteGroup($group_id)
7767 {
7768 include_once "./Modules/Group/classes/class.ilObjGroup.php";
7769 $group = new ilObjGroup($group_id);
7770 $members = $group->getGroupMemberIds();
7771 include_once './Services/User/classes/class.ilObjUser.php';
7772 foreach ($members as $user_id) {
7773 $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7774 }
7775 }
7776
7783 public function inviteRole($role_id)
7784 {
7785 global $DIC;
7786 $rbacreview = $DIC['rbacreview'];
7787 $members = $rbacreview->assignedUsers($role_id);
7788 include_once './Services/User/classes/class.ilObjUser.php';
7789 foreach ($members as $user_id) {
7790 $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7791 }
7792 }
7793
7794
7795
7802 public function disinviteUser($user_id)
7803 {
7804 global $DIC;
7805 $ilDB = $DIC['ilDB'];
7806
7807 $affectedRows = $ilDB->manipulateF(
7808 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7809 array('integer', 'integer'),
7810 array($this->getTestId(), $user_id)
7811 );
7812 }
7813
7820 public function inviteUser($user_id, $client_ip = "")
7821 {
7822 global $DIC;
7823 $ilDB = $DIC['ilDB'];
7824
7825 $affectedRows = $ilDB->manipulateF(
7826 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7827 array('integer', 'integer'),
7828 array($this->getTestId(), $user_id)
7829 );
7830 $affectedRows = $ilDB->manipulateF(
7831 "INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
7832 array('integer', 'integer', 'text', 'integer'),
7833 array($this->getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : null, time())
7834 );
7835 }
7836
7837
7838 public function setClientIP($user_id, $client_ip)
7839 {
7840 global $DIC;
7841 $ilDB = $DIC['ilDB'];
7842
7843 $affectedRows = $ilDB->manipulateF(
7844 "UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
7845 array('text', 'integer', 'integer', 'integer'),
7846 array((strlen($client_ip)) ? $client_ip : null, time(), $this->getTestId(), $user_id)
7847 );
7848 }
7849
7855 public static function _getSolvedQuestions($active_id, $question_fi = null)
7856 {
7857 global $DIC;
7858 $ilDB = $DIC['ilDB'];
7859 if (is_numeric($question_fi)) {
7860 $result = $ilDB->queryF(
7861 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
7862 array('integer', 'integer'),
7863 array($active_id, $question_fi)
7864 );
7865 } else {
7866 $result = $ilDB->queryF(
7867 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
7868 array('integer'),
7869 array($active_id)
7870 );
7871 }
7872 $result_array = array();
7873 while ($row = $ilDB->fetchAssoc($result)) {
7874 $result_array[$row["question_fi"]] = $row;
7875 }
7876 return $result_array;
7877 }
7878
7879
7883 public function setQuestionSetSolved($value, $question_id, $user_id)
7884 {
7885 global $DIC;
7886 $ilDB = $DIC['ilDB'];
7887
7888 $active_id = $this->getActiveIdOfUser($user_id);
7889 $affectedRows = $ilDB->manipulateF(
7890 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
7891 array('integer', 'integer'),
7892 array($active_id, $question_id)
7893 );
7894 $affectedRows = $ilDB->manipulateF(
7895 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
7896 array('integer', 'integer', 'integer'),
7897 array($value, $question_id, $active_id)
7898 );
7899 }
7900
7904 public function isTestFinished($active_id)
7905 {
7906 global $DIC;
7907 $ilDB = $DIC['ilDB'];
7908
7909 $result = $ilDB->queryF(
7910 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
7911 array('integer', 'integer'),
7912 array($active_id, 1)
7913 );
7914 return $result->numRows() == 1;
7915 }
7916
7920 public function isActiveTestSubmitted($user_id = null)
7921 {
7922 global $DIC;
7923 $ilUser = $DIC['ilUser'];
7924 $ilDB = $DIC['ilDB'];
7925
7926 if (!is_numeric($user_id)) {
7927 $user_id = $ilUser->getId();
7928 }
7929
7930 $result = $ilDB->queryF(
7931 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
7932 array('integer', 'integer', 'integer'),
7933 array($this->getTestId(), $user_id, 1)
7934 );
7935 return $result->numRows() == 1;
7936 }
7937
7941 public function hasNrOfTriesRestriction()
7942 {
7943 return $this->getNrOfTries() != 0;
7944 }
7945
7946
7952 public function isNrOfTriesReached($tries)
7953 {
7954 return $tries >= (int) $this->getNrOfTries();
7955 }
7956
7957
7966 public function getAllTestResults($participants, $prepareForCSV = true)
7967 {
7968 $results = array();
7969 $row = array(
7970 "user_id" => $this->lng->txt("user_id"),
7971 "matriculation" => $this->lng->txt("matriculation"),
7972 "lastname" => $this->lng->txt("lastname"),
7973 "firstname" => $this->lng->txt("firstname"),
7974 "login" => $this->lng->txt("login"),
7975 "reached_points" => $this->lng->txt("tst_reached_points"),
7976 "max_points" => $this->lng->txt("tst_maximum_points"),
7977 "percent_value" => $this->lng->txt("tst_percent_solved"),
7978 "mark" => $this->lng->txt("tst_mark"),
7979 "ects" => $this->lng->txt("ects_grade"),
7980 "passed" => $this->lng->txt("tst_mark_passed"),
7981 );
7982 $results[] = $row;
7983 if (count($participants)) {
7984 if ($this->getECTSOutput()) {
7985 $passed_array = &$this->getTotalPointsPassedArray();
7986 }
7987 foreach ($participants as $active_id => $user_rec) {
7988 $mark = $ects_mark = '';
7989 $row = array();
7990 $reached_points = 0;
7991 $max_points = 0;
7992 foreach ($this->questions as $value) {
7993 $question = &ilObjTest::_instanciateQuestion($value);
7994 if (is_object($question)) {
7995 $max_points += $question->getMaximumPoints();
7996 $reached_points += $question->getReachedPoints($active_id);
7997 }
7998 }
7999 if ($max_points > 0) {
8000 $percentvalue = $reached_points / $max_points;
8001 if ($percentvalue < 0) {
8002 $percentvalue = 0.0;
8003 }
8004 } else {
8005 $percentvalue = 0;
8006 }
8007 $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
8008 $passed = "";
8009 if ($mark_obj) {
8010 $mark = $mark_obj->getOfficialName();
8011 if ($this->getECTSOutput()) {
8012 $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
8013 }
8014 }
8015 if ($this->getAnonymity()) {
8016 $user_rec['firstname'] = "";
8017 $user_rec['lastname'] = $this->lng->txt("anonymous");
8018 }
8019 $row = array(
8020 "user_id" => $user_rec['usr_id'],
8021 "matriculation" => $user_rec['matriculation'],
8022 "lastname" => $user_rec['lastname'],
8023 "firstname" => $user_rec['firstname'],
8024 "login" => $user_rec['login'],
8025 "reached_points" => $reached_points,
8026 "max_points" => $max_points,
8027 "percent_value" => $percentvalue,
8028 "mark" => $mark,
8029 "ects" => $ects_mark,
8030 "passed" => $user_rec['passed'] ? '1' : '0',
8031 );
8032 $results[] = $prepareForCSV ? $this->processCSVRow($row, true) : $row;
8033 }
8034 }
8035 return $results;
8036 }
8037
8048 public function &processCSVRow($row, $quoteAll = false, $separator = ";")
8049 {
8050 $resultarray = array();
8051 foreach ($row as $rowindex => $entry) {
8052 $surround = false;
8053 if ($quoteAll) {
8054 $surround = true;
8055 }
8056 if (strpos($entry, "\"") !== false) {
8057 $entry = str_replace("\"", "\"\"", $entry);
8058 $surround = true;
8059 }
8060 if (strpos($entry, $separator) !== false) {
8061 $surround = true;
8062 }
8063 // replace all CR LF with LF (for Excel for Windows compatibility
8064 $entry = str_replace(chr(13) . chr(10), chr(10), $entry);
8065
8066 if ($surround) {
8067 $entry = "\"" . $entry . "\"";
8068 }
8069
8070 $resultarray[$rowindex] = $entry;
8071 }
8072 return $resultarray;
8073 }
8074
8083 public static function _getPass($active_id)
8084 {
8085 global $DIC;
8086 $ilDB = $DIC['ilDB'];
8087 $result = $ilDB->queryF(
8088 "SELECT tries FROM tst_active WHERE active_id = %s",
8089 array('integer'),
8090 array($active_id)
8091 );
8092 if ($result->numRows()) {
8093 $row = $ilDB->fetchAssoc($result);
8094 return $row["tries"];
8095 } else {
8096 return 0;
8097 }
8098 }
8099
8109 public static function _getMaxPass($active_id)
8110 {
8111 global $DIC;
8112 $ilDB = $DIC['ilDB'];
8113 $result = $ilDB->queryF(
8114 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
8115 array('integer'),
8116 array($active_id)
8117 );
8118 if ($result->numRows()) {
8119 $row = $ilDB->fetchAssoc($result);
8120 $max = $row["maxpass"];
8121 } else {
8122 $max = null;
8123 }
8124 return $max;
8125 }
8126
8132 public static function _getBestPass($active_id)
8133 {
8134 global $DIC;
8135 $ilDB = $DIC['ilDB'];
8136
8137 $result = $ilDB->queryF(
8138 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
8139 array('integer'),
8140 array($active_id)
8141 );
8142 if ($result->numRows()) {
8143 $bestrow = null;
8144 $bestfactor = 0.0;
8145 while ($row = $ilDB->fetchAssoc($result)) {
8146 if ($row["maxpoints"] > 0) {
8147 $factor = (float) ($row["points"] / $row["maxpoints"]);
8148 } else {
8149 $factor = 0.0;
8150 }
8151
8152 if ($factor === 0.0 && $bestfactor === 0.0
8153 || $factor > $bestfactor) {
8154 $bestrow = $row;
8155 $bestfactor = $factor;
8156 }
8157 }
8158 if (is_array($bestrow)) {
8159 return $bestrow["pass"];
8160 } else {
8161 return null;
8162 }
8163 } else {
8164 return null;
8165 }
8166 }
8167
8176 public static function _getResultPass($active_id)
8177 {
8178 $counted_pass = null;
8179 if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS) {
8180 $counted_pass = ilObjTest::_getBestPass($active_id);
8181 } else {
8182 $counted_pass = ilObjTest::_getMaxPass($active_id);
8183 }
8184 return $counted_pass;
8185 }
8186
8196 public function getAnsweredQuestionCount($active_id, $pass = null)
8197 {
8198 if ($this->isDynamicTest()) {
8199 global $DIC;
8200 $tree = $DIC['tree'];
8201 $ilDB = $DIC['ilDB'];
8202 $lng = $DIC['lng'];
8203 $refinery = $DIC['refinery'];
8204 $ilPluginAdmin = $DIC['ilPluginAdmin'];
8205
8206 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
8207 $testSessionFactory = new ilTestSessionFactory($this);
8208 $testSession = $testSessionFactory->getSession($active_id);
8209
8210 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
8211 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $refinery, $ilPluginAdmin, $this);
8212 $testSequence = $testSequenceFactory->getSequenceByTestSession($testSession);
8213
8214 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
8215 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
8216 $dynamicQuestionSetConfig->loadFromDb();
8217
8218 $testSequence->loadFromDb($dynamicQuestionSetConfig);
8219 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
8220
8221 return $testSequence->getTrackedQuestionCount();
8222 }
8223
8224 if ($this->isRandomTest()) {
8225 $this->loadQuestions($active_id, $pass);
8226 }
8227 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
8228 $workedthrough = 0;
8229 foreach ($this->questions as $value) {
8230 if (assQuestion::_isWorkedThrough($active_id, $value, $pass)) {
8231 $workedthrough += 1;
8232 }
8233 }
8234 return $workedthrough;
8235 }
8236
8243 public static function lookupPassResultsUpdateTimestamp($active_id, $pass)
8244 {
8245 global $DIC;
8246 $ilDB = $DIC['ilDB'];
8247
8248 if (is_null($pass)) {
8249 $pass = 0;
8250 }
8251
8252 $query = "
8253 SELECT tst_pass_result.tstamp pass_res_tstamp,
8254 tst_test_result.tstamp quest_res_tstamp
8255
8256 FROM tst_pass_result
8257
8258 LEFT JOIN tst_test_result
8259 ON tst_test_result.active_fi = tst_pass_result.active_fi
8260 AND tst_test_result.pass = tst_pass_result.pass
8261
8262 WHERE tst_pass_result.active_fi = %s
8263 AND tst_pass_result.pass = %s
8264
8265 ORDER BY tst_test_result.tstamp DESC
8266 ";
8267
8268 $result = $ilDB->queryF(
8269 $query,
8270 array('integer', 'integer'),
8271 array($active_id, $pass)
8272 );
8273
8274 while ($row = $ilDB->fetchAssoc($result)) {
8275 if ($row['qres_tstamp']) {
8276 return $row['quest_res_tstamp'];
8277 }
8278
8279 return $row['pass_res_tstamp'];
8280 }
8281
8282 return 0;
8283 }
8284
8293 public function isExecutable($testSession, $user_id, $allowPassIncrease = false)
8294 {
8295 $result = array(
8296 "executable" => true,
8297 "errormessage" => ""
8298 );
8299 if (!$this->startingTimeReached()) {
8300 $result["executable"] = false;
8301 $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getStartingTime(), IL_CAL_UNIX)));
8302 return $result;
8303 }
8304 if ($this->endingTimeReached()) {
8305 $result["executable"] = false;
8306 $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getEndingTime(), IL_CAL_UNIX)));
8307 return $result;
8308 }
8309
8310 $active_id = $this->getActiveIdOfUser($user_id);
8311
8312 if ($this->getEnableProcessingTime()) {
8313 if ($active_id > 0) {
8314 $starting_time = $this->getStartingTimeOfUser($active_id);
8315 if ($starting_time !== false) {
8316 if ($this->isMaxProcessingTimeReached($starting_time, $active_id)) {
8317 if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > (self::_getPass($active_id) + 1)))) {
8318 // a test pass was quitted because the maximum processing time was reached, but the time
8319 // will be resetted for future passes, so if there are more passes allowed, the participant may
8320 // start the test again.
8321 // This code block is only called when $allowPassIncrease is TRUE which only happens when
8322 // the test info page is opened. Otherwise this will lead to unexpected results!
8323 $testSession->increasePass();
8324 $testSession->setLastSequence(0);
8325 $testSession->saveToDb();
8326 } else {
8327 $result["executable"] = false;
8328 $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8329 }
8330 return $result;
8331 }
8332 }
8333 }
8334 }
8335 global $DIC;
8336 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8337 $testPassesSelector = new ilTestPassesSelector($DIC['ilDB'], $this);
8338 $testPassesSelector->setActiveId($active_id);
8339 $testPassesSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8340
8341 if ($this->hasNrOfTriesRestriction() && ($active_id > 0)) {
8342 $closedPasses = $testPassesSelector->getClosedPasses();
8343
8344 if (count($closedPasses) >= $this->getNrOfTries()) {
8345 $result["executable"] = false;
8346 $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8347 return $result;
8348 }
8349
8350 if ($this->isBlockPassesAfterPassedEnabled() && !$testPassesSelector->openPassExists()) {
8351 if (ilObjTestAccess::_isPassed($user_id, $this->getId())) {
8352 $result['executable'] = false;
8353 $result['errormessage'] = $this->lng->txt("tst_addit_passes_blocked_after_passed_msg");
8354 return $result;
8355 }
8356 }
8357 }
8358 if ($this->isPassWaitingEnabled() && $testPassesSelector->getLastFinishedPass() !== null) {
8359 $lastPass = $testPassesSelector->getLastFinishedPassTimestamp();
8360 if ($lastPass && strlen($this->getPassWaiting())) {
8361 $pass_waiting_string = $this->getPassWaiting();
8362 $time_values = explode(":", $pass_waiting_string);
8363 $next_pass_allowed = strtotime('+ ' . $time_values[0] . ' Months + ' . $time_values[1] . ' Days + ' . $time_values[2] . ' Hours' . $time_values[3] . ' Minutes', $lastPass);
8364
8365 if (time() < $next_pass_allowed) {
8366 $date = ilDatePresentation::formatDate(new ilDateTime($next_pass_allowed, IL_CAL_UNIX));
8367
8368 $result["executable"] = false;
8369 $result["errormessage"] = sprintf($this->lng->txt('wait_for_next_pass_hint_msg'), $date);
8370 return $result;
8371 }
8372 }
8373 }
8374 return $result;
8375 }
8376
8377
8379 {
8380 global $DIC; /* @var ILIAS\DI\Container $DIC */
8381
8382 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8383 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
8384
8385 $passSelector->setActiveId($testSession->getActiveId());
8386 $passSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8387
8388 return $passSelector->hasReportablePasses();
8389 }
8390
8392 {
8393 global $DIC; /* @var ILIAS\DI\Container $DIC */
8394
8395 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8396 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
8397
8398 $passSelector->setActiveId($testSession->getActiveId());
8399 $passSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8400
8401 return $passSelector->hasExistingPasses();
8402 }
8403
8411 public function getStartingTimeOfUser($active_id, $pass = null)
8412 {
8413 global $DIC;
8414 $ilDB = $DIC['ilDB'];
8415
8416 if ($active_id < 1) {
8417 return false;
8418 }
8419 if ($pass === null) {
8420 $pass = ($this->getResetProcessingTime()) ? self::_getPass($active_id) : 0;
8421 }
8422 $result = $ilDB->queryF(
8423 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
8424 array('integer', 'integer'),
8425 array($active_id, $pass)
8426 );
8427 if ($result->numRows()) {
8428 $row = $ilDB->fetchAssoc($result);
8429 if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches)) {
8430 return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8431 } else {
8432 return time();
8433 }
8434 } else {
8435 return time();
8436 }
8437 }
8438
8447 public function isMaxProcessingTimeReached($starting_time, $active_id)
8448 {
8449 if ($this->getEnableProcessingTime()) {
8450 $processing_time = $this->getProcessingTimeInSeconds($active_id);
8451 $now = time();
8452 if ($now > ($starting_time + $processing_time)) {
8453 return true;
8454 } else {
8455 return false;
8456 }
8457 } else {
8458 return false;
8459 }
8460 }
8461
8462 public function &getTestQuestions()
8463 {
8464 global $DIC;
8465 $ilDB = $DIC['ilDB'];
8466
8467 $tags_trafo = $this->refinery->string()->stripTags();
8468
8469 $query = "
8470 SELECT questions.*,
8471 questtypes.type_tag,
8472 tstquest.sequence,
8473 tstquest.obligatory,
8474 origquest.obj_fi orig_obj_fi
8475
8476 FROM qpl_questions questions
8477
8478 INNER JOIN qpl_qst_type questtypes
8479 ON questtypes.question_type_id = questions.question_type_fi
8480
8481 INNER JOIN tst_test_question tstquest
8482 ON tstquest.question_fi = questions.question_id
8483
8484 LEFT JOIN qpl_questions origquest
8485 ON origquest.question_id = questions.original_id
8486
8487 WHERE tstquest.test_fi = %s
8488
8489 ORDER BY tstquest.sequence
8490 ";
8491
8492 $query_result = $ilDB->queryF(
8493 $query,
8494 array('integer'),
8495 array($this->getTestId())
8496 );
8497
8498 $questions = array();
8499
8500 while ($row = $ilDB->fetchAssoc($query_result)) {
8501 $row['title'] = $tags_trafo->transform($row['title']);
8502 $row['description'] = $tags_trafo->transform($row['description'] !== '' && $row['description'] !== null ? $row['description'] : '&nbsp;');
8503 $row['author'] = $tags_trafo->transform($row['author']);
8504 $row['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8505
8506 $questions[] = $row;
8507 }
8508
8509 return $questions;
8510 }
8511
8516 public function isTestQuestion($questionId)
8517 {
8518 foreach ($this->getTestQuestions() as $questionData) {
8519 if ($questionData['question_id'] != $questionId) {
8520 continue;
8521 }
8522
8523 return true;
8524 }
8525
8526 return false;
8527 }
8528
8529 public function checkQuestionParent($questionId)
8530 {
8531 global $DIC; /* @var ILIAS\DI\Container $DIC */
8532
8533 $row = $DIC->database()->fetchAssoc($DIC->database()->queryF(
8534 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
8535 array('integer', 'integer'),
8536 array($questionId, $this->getId())
8537 ));
8538
8539 return (bool) $row['cnt'];
8540 }
8541
8546 {
8547 $points = 0;
8548
8549 foreach ($this->getTestQuestions() as $questionData) {
8550 $points += $questionData['points'];
8551 }
8552
8553 return $points;
8554 }
8555
8560 {
8561 $totalWorkingTime = '00:00:00';
8562
8563 foreach ($this->getTestQuestions() as $questionData) {
8565 $totalWorkingTime,
8566 $questionData['working_time']
8567 );
8568 }
8569
8570 return $totalWorkingTime;
8571 }
8572
8576 public function getPotentialRandomTestQuestions()
8577 {
8581 global $DIC;
8582 $ilDB = $DIC['ilDB'];
8583
8584 $query = "
8585 SELECT questions.*,
8586 questtypes.type_tag,
8587 origquest.obj_fi orig_obj_fi
8588
8589 FROM qpl_questions questions
8590
8591 INNER JOIN qpl_qst_type questtypes
8592 ON questtypes.question_type_id = questions.question_type_fi
8593
8594 INNER JOIN tst_rnd_cpy tstquest
8595 ON tstquest.qst_fi = questions.question_id
8596
8597 LEFT JOIN qpl_questions origquest
8598 ON origquest.question_id = questions.original_id
8599
8600 WHERE tstquest.tst_fi = %s
8601 ";
8602
8603 $query_result = $ilDB->queryF(
8604 $query,
8605 array('integer'),
8606 array($this->getTestId())
8607 );
8608
8609 $questions = array();
8610
8611 while ($row = $ilDB->fetchAssoc($query_result)) {
8612 $question = $row;
8613
8614 $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8615
8616 $questions[] = $question;
8617 }
8618
8619 return $questions;
8620 }
8621
8628 public function getShuffleQuestions()
8629 {
8630 return ($this->shuffle_questions) ? 1 : 0;
8631 }
8632
8639 public function setShuffleQuestions($a_shuffle)
8640 {
8641 $this->shuffle_questions = ($a_shuffle) ? 1 : 0;
8642 }
8643
8657 {
8658 return ($this->show_summary) ? $this->show_summary : 0;
8659 }
8660
8673 public function setListOfQuestionsSettings($a_value = 0)
8674 {
8675 $this->show_summary = $a_value;
8676 }
8677
8684 public function getListOfQuestions()
8685 {
8686 if (($this->show_summary & 1) > 0) {
8687 return true;
8688 } else {
8689 return false;
8690 }
8691 }
8692
8699 public function setListOfQuestions($a_value = true)
8700 {
8701 if ($a_value) {
8702 $this->show_summary = 1;
8703 } else {
8704 $this->show_summary = 0;
8705 }
8706 }
8707
8714 public function getListOfQuestionsStart()
8715 {
8716 if (($this->show_summary & 2) > 0) {
8717 return true;
8718 } else {
8719 return false;
8720 }
8721 }
8722
8729 public function setListOfQuestionsStart($a_value = true)
8730 {
8731 if ($a_value && $this->getListOfQuestions()) {
8732 $this->show_summary = $this->show_summary | 2;
8733 }
8734 if (!$a_value && $this->getListOfQuestions()) {
8735 if ($this->getListOfQuestionsStart()) {
8736 $this->show_summary = $this->show_summary ^ 2;
8737 }
8738 }
8739 }
8740
8747 public function getListOfQuestionsEnd()
8748 {
8749 if (($this->show_summary & 4) > 0) {
8750 return true;
8751 } else {
8752 return false;
8753 }
8754 }
8755
8762 public function setListOfQuestionsEnd($a_value = true)
8763 {
8764 if ($a_value && $this->getListOfQuestions()) {
8765 $this->show_summary = $this->show_summary | 4;
8766 }
8767 if (!$a_value && $this->getListOfQuestions()) {
8768 if ($this->getListOfQuestionsEnd()) {
8769 $this->show_summary = $this->show_summary ^ 4;
8770 }
8771 }
8772 }
8773
8781 {
8782 if (($this->show_summary & 8) > 0) {
8783 return true;
8784 } else {
8785 return false;
8786 }
8787 }
8788
8795 public function setListOfQuestionsDescription($a_value = true)
8796 {
8797 if ($a_value && $this->getListOfQuestions()) {
8798 $this->show_summary = $this->show_summary | 8;
8799 }
8800 if (!$a_value && $this->getListOfQuestions()) {
8801 if ($this->getListOfQuestionsDescription()) {
8802 $this->show_summary = $this->show_summary ^ 8;
8803 }
8804 }
8805 }
8806
8813 public function getResultsPresentation()
8814 {
8815 return ($this->results_presentation) ? $this->results_presentation : 0;
8816 }
8817
8824 public function getShowPassDetails()
8825 {
8826 if (($this->results_presentation & 1) > 0) {
8827 return true;
8828 } else {
8829 return false;
8830 }
8831 }
8832
8839 public function getShowSolutionDetails()
8840 {
8841 if (($this->results_presentation & 2) > 0) {
8842 return true;
8843 } else {
8844 return false;
8845 }
8846 }
8847
8855 {
8856 if (($this->results_presentation & 4) > 0) {
8857 return true;
8858 } else {
8859 return false;
8860 }
8861 }
8862
8869 public function getShowSolutionFeedback()
8870 {
8871 if (($this->results_presentation & 8) > 0) {
8872 return true;
8873 } else {
8874 return false;
8875 }
8876 }
8877
8885 {
8886 if (($this->results_presentation & 16) > 0) {
8887 return true;
8888 } else {
8889 return false;
8890 }
8891 }
8892
8900 {
8901 if (($this->results_presentation & 32) > 0) {
8902 return true;
8903 } else {
8904 return false;
8905 }
8906 }
8907
8913 {
8914 if (($this->results_presentation & 64) > 0) {
8915 return true;
8916 } else {
8917 return false;
8918 }
8919 }
8920
8926 {
8927 if (($this->results_presentation & 128) > 0) {
8928 return true;
8929 } else {
8930 return false;
8931 }
8932 }
8933
8940 public function setResultsPresentation($a_results_presentation = 3)
8941 {
8942 $this->results_presentation = $a_results_presentation;
8943 }
8944
8953 public function setShowPassDetails($a_details = 1)
8954 {
8955 if ($a_details) {
8956 $this->results_presentation = $this->results_presentation | 1;
8957 } else {
8958 if ($this->getShowPassDetails()) {
8959 $this->results_presentation = $this->results_presentation ^ 1;
8960 }
8961 }
8962 }
8963
8970 public function setShowSolutionDetails($a_details = 1)
8971 {
8972 if ($a_details) {
8973 $this->results_presentation = $this->results_presentation | 2;
8974 } else {
8975 if ($this->getShowSolutionDetails()) {
8976 $this->results_presentation = $this->results_presentation ^ 2;
8977 }
8978 }
8979 }
8980
8987 public function canShowSolutionPrintview($user_id = null)
8988 {
8989 return $this->getShowSolutionPrintview();
8990 }
8991
8998 public function setShowSolutionPrintview($a_printview = 1)
8999 {
9000 if ($a_printview) {
9001 $this->results_presentation = $this->results_presentation | 4;
9002 } else {
9003 if ($this->getShowSolutionPrintview()) {
9004 $this->results_presentation = $this->results_presentation ^ 4;
9005 }
9006 }
9007 }
9008
9015 public function setShowSolutionFeedback($a_feedback = true)
9016 {
9017 if ($a_feedback) {
9018 $this->results_presentation = $this->results_presentation | 8;
9019 } else {
9020 if ($this->getShowSolutionFeedback()) {
9021 $this->results_presentation = $this->results_presentation ^ 8;
9022 }
9023 }
9024 }
9025
9032 public function setShowSolutionAnswersOnly($a_full = true)
9033 {
9034 if ($a_full) {
9035 $this->results_presentation = $this->results_presentation | 16;
9036 } else {
9037 if ($this->getShowSolutionAnswersOnly()) {
9038 $this->results_presentation = $this->results_presentation ^ 16;
9039 }
9040 }
9041 }
9042
9049 public function setShowSolutionSignature($a_signature = false)
9050 {
9051 if ($a_signature) {
9052 $this->results_presentation = $this->results_presentation | 32;
9053 } else {
9054 if ($this->getShowSolutionSignature()) {
9055 $this->results_presentation = $this->results_presentation ^ 32;
9056 }
9057 }
9058 }
9059
9066 public function setShowSolutionSuggested($a_solution = false)
9067 {
9068 if ($a_solution) {
9069 $this->results_presentation = $this->results_presentation | 64;
9070 } else {
9071 if ($this->getShowSolutionSuggested()) {
9072 $this->results_presentation = $this->results_presentation ^ 64;
9073 }
9074 }
9075 }
9076
9082 public function setShowSolutionListComparison($a_comparison = false)
9083 {
9084 if ($a_comparison) {
9085 $this->results_presentation = $this->results_presentation | 128;
9086 } else {
9087 if ($this->getShowSolutionListComparison()) {
9088 $this->results_presentation = $this->results_presentation ^ 128;
9089 }
9090 }
9091 }
9092
9096 public static function _getUserIdFromActiveId($active_id)
9097 {
9098 global $DIC;
9099 $ilDB = $DIC['ilDB'];
9100 $result = $ilDB->queryF(
9101 "SELECT user_fi FROM tst_active WHERE active_id = %s",
9102 array('integer'),
9103 array($active_id)
9104 );
9105 if ($result->numRows()) {
9106 $row = $ilDB->fetchAssoc($result);
9107 return $row["user_fi"];
9108 } else {
9109 return -1;
9110 }
9111 }
9112
9116 public function isLimitUsersEnabled()
9117 {
9119 }
9120
9125 {
9126 $this->limitUsersEnabled = $limitUsersEnabled;
9127 }
9128
9129 public function getAllowedUsers()
9130 {
9131 return ($this->allowedUsers) ? $this->allowedUsers : 0;
9132 }
9133
9134 public function setAllowedUsers($a_allowed_users)
9135 {
9136 $this->allowedUsers = $a_allowed_users;
9137 }
9138
9139 public function getAllowedUsersTimeGap()
9140 {
9141 return ($this->allowedUsersTimeGap) ? $this->allowedUsersTimeGap : 0;
9142 }
9143
9144 public function setAllowedUsersTimeGap($a_allowed_users_time_gap)
9145 {
9146 $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
9147 }
9148
9150 {
9151 global $DIC;
9152 $ilDB = $DIC['ilDB'];
9153
9154 $nr_of_users = $this->getAllowedUsers();
9155 $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
9156 if (($nr_of_users > 0) && ($time_gap > 0)) {
9157 $now = time();
9158 $time_border = $now - $time_gap;
9159 $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
9160 $query = "
9161 SELECT DISTINCT tst_times.active_fi
9162 FROM tst_times
9163 INNER JOIN tst_active
9164 ON tst_times.active_fi = tst_active.active_id
9165 AND (
9166 tst_times.pass > tst_active.last_finished_pass OR tst_active.last_finished_pass IS NULL
9167 )
9168 WHERE tst_times.tstamp > %s
9169 AND tst_active.test_fi = %s
9170 ";
9171 $result = $ilDB->queryF($query, array('integer', 'integer'), array($time_border, $this->getTestId()));
9172 if ($result->numRows() >= $nr_of_users) {
9173 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
9175 $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
9176 }
9177 return false;
9178 } else {
9179 return true;
9180 }
9181 }
9182 return true;
9183 }
9184
9185 public function _getLastAccess($active_id)
9186 {
9187 global $DIC;
9188 $ilDB = $DIC['ilDB'];
9189
9190 $result = $ilDB->queryF(
9191 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
9192 array('integer'),
9193 array($active_id)
9194 );
9195 if ($result->numRows()) {
9196 $row = $ilDB->fetchAssoc($result);
9197 return $row["finished"];
9198 }
9199 return "";
9200 }
9201
9202 public static function lookupLastTestPassAccess($activeId, $passIndex)
9203 {
9204 global $DIC; /* @var \ILIAS\DI\Container $DIC */
9205
9206 $query = "
9207 SELECT MAX(tst_times.tstamp) as last_pass_access
9208 FROM tst_times
9209 WHERE active_fi = %s
9210 AND pass = %s
9211 ";
9212
9213 $res = $DIC->database()->queryF(
9214 $query,
9215 array('integer', 'integer'),
9216 array($activeId, $passIndex)
9217 );
9218
9219 while ($row = $DIC->database()->fetchAssoc($res)) {
9220 return $row['last_pass_access'];
9221 }
9222
9223 return null;
9224 }
9225
9233 public function isHTML($a_text)
9234 {
9235 if (preg_match("/<[^>]*?>/", $a_text)) {
9236 return true;
9237 } else {
9238 return false;
9239 }
9240 }
9241
9249 public function QTIMaterialToString($a_material)
9250 {
9251 $result = "";
9252 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
9253 $material = $a_material->getMaterial($i);
9254 if (strcmp($material["type"], "mattext") == 0) {
9255 $result .= $material["material"]->getContent();
9256 }
9257 if (strcmp($material["type"], "matimage") == 0) {
9258 $matimage = $material["material"];
9259 if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) {
9260 // import an mediaobject which was inserted using tiny mce
9261 if (!is_array($_SESSION["import_mob_xhtml"])) {
9262 $_SESSION["import_mob_xhtml"] = array();
9263 }
9264 array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
9265 }
9266 }
9267 }
9268 global $DIC;
9269 $ilLog = $DIC['ilLog'];
9270 $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
9271 return $result;
9272 }
9273
9282 public function addQTIMaterial(&$a_xml_writer, $a_material = '')
9283 {
9284 include_once "./Services/RTE/classes/class.ilRTE.php";
9285 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9286
9287 $a_xml_writer->xmlStartTag("material");
9288 $txt = $a_material;
9289 $attrs = array(
9290 "texttype" => "text/plain"
9291 );
9292 if ($this->isHTML($a_material)) {
9293 $attrs["texttype"] = "text/xhtml";
9294 $txt = ilRTE::_replaceMediaObjectImageSrc($a_material, 0);
9295 }
9296
9297 $a_xml_writer->xmlElement("mattext", $attrs, $txt);
9298
9299 $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9300 foreach ($mobs as $mob) {
9301 $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9302 if (strpos($a_material, "mm_$mob") !== false) {
9303 if (ilObjMediaObject::_exists($mob)) {
9304 $mob_obj = new ilObjMediaObject($mob);
9305 $imgattrs = array(
9306 "label" => $moblabel,
9307 "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9308 );
9309 }
9310 $a_xml_writer->xmlElement("matimage", $imgattrs, null);
9311 }
9312 }
9313 $a_xml_writer->xmlEndTag("material");
9314 }
9315
9322 public function prepareTextareaOutput($txt_output, $prepare_for_latex_output = false, $omitNl2BrWhenTextArea = false)
9323 {
9324 include_once "./Services/Utilities/classes/class.ilUtil.php";
9325 return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output, $omitNl2BrWhenTextArea);
9326 }
9327
9334 public function saveCertificateVisibility($a_value)
9335 {
9336 global $DIC;
9337 $ilDB = $DIC['ilDB'];
9338
9339 $affectedRows = $ilDB->manipulateF(
9340 "UPDATE tst_tests SET certificate_visibility = %s, tstamp = %s WHERE test_id = %s",
9341 array('text', 'integer', 'integer'),
9342 array($a_value, time(), $this->getTestId())
9343 );
9344 }
9345
9353 {
9354 return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0;
9355 }
9356
9363 public function setCertificateVisibility($a_value)
9364 {
9365 $this->certificate_visibility = $a_value;
9366 }
9367
9374 public function getAnonymity()
9375 {
9376 return ($this->anonymity) ? 1 : 0;
9377 }
9378
9385 public function setAnonymity($a_value = 0)
9386 {
9387 switch ($a_value) {
9388 case 1:
9389 $this->anonymity = 1;
9390 break;
9391 default:
9392 $this->anonymity = 0;
9393 break;
9394 }
9395 }
9396
9403 public function getShowCancel()
9404 {
9405 return ($this->show_cancel) ? 1 : 0;
9406 }
9407
9414 public function setShowCancel($a_value = 1)
9415 {
9416 switch ($a_value) {
9417 case 1:
9418 $this->show_cancel = 1;
9419 break;
9420 default:
9421 $this->show_cancel = 0;
9422 break;
9423 }
9424 }
9425
9432 public function getShowMarker()
9433 {
9434 return ($this->show_marker) ? 1 : 0;
9435 }
9436
9443 public function setShowMarker($a_value = 1)
9444 {
9445 switch ($a_value) {
9446 case 1:
9447 $this->show_marker = 1;
9448 break;
9449 default:
9450 $this->show_marker = 0;
9451 break;
9452 }
9453 }
9454
9461 public function getFixedParticipants()
9462 {
9463 return ($this->fixed_participants) ? 1 : 0;
9464 }
9465
9472 public function setFixedParticipants($a_value = 1)
9473 {
9474 switch ($a_value) {
9475 case 1:
9476 $this->fixed_participants = 1;
9477 break;
9478 default:
9479 $this->fixed_participants = 0;
9480 break;
9481 }
9482 }
9483
9491 public static function _lookupAnonymity($a_obj_id)
9492 {
9493 global $DIC;
9494 $ilDB = $DIC['ilDB'];
9495
9496 $result = $ilDB->queryF(
9497 "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
9498 array('integer'),
9499 array($a_obj_id)
9500 );
9501 while ($row = $ilDB->fetchAssoc($result)) {
9502 return $row['anonymity'];
9503 }
9504 return 0;
9505 }
9506
9513 public static function lookupQuestionSetTypeByActiveId($active_id)
9514 {
9515 global $DIC;
9516 $ilDB = $DIC['ilDB'];
9517
9518 $query = "
9519 SELECT tst_tests.question_set_type
9520 FROM tst_active
9521 INNER JOIN tst_tests
9522 ON tst_active.test_fi = tst_tests.test_id
9523 WHERE tst_active.active_id = %s
9524 ";
9525
9526 $res = $ilDB->queryF($query, array('integer'), array($active_id));
9527
9528 while ($row = $ilDB->fetchAssoc($res)) {
9529 return $row['question_set_type'];
9530 }
9531
9532 return null;
9533 }
9534
9543 public function _lookupRandomTestFromActiveId($active_id)
9544 {
9545 throw new Exception(__METHOD__ . ' is deprecated ... use ilObjTest::lookupQuestionSetTypeByActiveId() instead!');
9546
9547 global $DIC;
9548 $ilDB = $DIC['ilDB'];
9549
9550 $result = $ilDB->queryF(
9551 "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",
9552 array('integer'),
9553 array($active_id)
9554 );
9555 while ($row = $ilDB->fetchAssoc($result)) {
9556 return $row['random_test'];
9557 }
9558 return 0;
9559 }
9560
9571 public function userLookupFullName($user_id, $overwrite_anonymity = false, $sorted_order = false, $suffix = "")
9572 {
9573 if ($this->getAnonymity() && !$overwrite_anonymity) {
9574 return $this->lng->txt("anonymous") . $suffix;
9575 } else {
9576 include_once './Services/User/classes/class.ilObjUser.php';
9577 $uname = ilObjUser::_lookupName($user_id);
9578 if (strlen($uname["firstname"] . $uname["lastname"]) == 0) {
9579 $uname["firstname"] = $this->lng->txt("deleted_user");
9580 }
9581 if ($sorted_order) {
9582 return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9583 } else {
9584 return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9585 }
9586 }
9587 }
9588
9596 public function getStartTestLabel($active_id)
9597 {
9598 if ($this->getNrOfTries() == 1) {
9599 return $this->lng->txt("tst_start_test");
9600 }
9601 $active_pass = self::_getPass($active_id);
9602 $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9603 if ($res == 0) {
9604 if ($active_pass == 0) {
9605 return $this->lng->txt("tst_start_test");
9606 } else {
9607 return $this->lng->txt("tst_start_new_test_pass");
9608 }
9609 } else {
9610 return $this->lng->txt("tst_resume_test");
9611 }
9612 }
9613
9619 public function getAvailableDefaults()
9620 {
9625 global $DIC;
9626 $ilDB = $DIC['ilDB'];
9627 $ilUser = $DIC['ilUser'];
9628
9629 $result = $ilDB->queryF(
9630 "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
9631 array('integer'),
9632 array($ilUser->getId())
9633 );
9634 $defaults = array();
9635 while ($row = $ilDB->fetchAssoc($result)) {
9636 $defaults[$row["test_defaults_id"]] = $row;
9637 }
9638 return $defaults;
9639 }
9640
9648 public function &getTestDefaults($test_defaults_id)
9649 {
9650 return self::_getTestDefaults($test_defaults_id);
9651 }
9652
9653 public static function _getTestDefaults($test_defaults_id)
9654 {
9655 global $DIC;
9656 $ilDB = $DIC['ilDB'];
9657
9658 $result = $ilDB->queryF(
9659 "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9660 array('integer'),
9661 array($test_defaults_id)
9662 );
9663 if ($result->numRows() == 1) {
9664 $row = $ilDB->fetchAssoc($result);
9665 return $row;
9666 } else {
9667 return null;
9668 }
9669 }
9670
9677 public function deleteDefaults($test_default_id)
9678 {
9679 global $DIC;
9680 $ilDB = $DIC['ilDB'];
9681 $affectedRows = $ilDB->manipulateF(
9682 "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9683 array('integer'),
9684 array($test_default_id)
9685 );
9686 }
9687
9694 public function addDefaults($a_name)
9695 {
9696 global $DIC;
9697 $ilDB = $DIC['ilDB'];
9698 $ilUser = $DIC['ilUser'];
9699 $testsettings = array(
9700 "TitleOutput" => $this->getTitleOutput(),
9701 "PassScoring" => $this->getPassScoring(),
9702 "IntroEnabled" => $this->isIntroductionEnabled(),
9703 "Introduction" => $this->getIntroduction(),
9704 "FinalStatement" => $this->getFinalStatement(),
9705 "ShowInfo" => $this->getShowInfo(),
9706 "ForceJS" => $this->getForceJS(),
9707 "CustomStyle" => $this->getCustomStyle(),
9708 "ShowFinalStatement" => $this->getShowFinalStatement(),
9709 "SequenceSettings" => $this->getSequenceSettings(),
9710 "ScoreReporting" => $this->getScoreReporting(),
9711 "ScoreCutting" => $this->getScoreCutting(),
9712 'SpecificAnswerFeedback' => $this->getSpecificAnswerFeedback(),
9713 'PrintBsWithRes' => (int) $this->isBestSolutionPrintedWithResult(),
9714 "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9715 "AnswerFeedback" => $this->getAnswerFeedback(),
9716 "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9717 "ResultsPresentation" => $this->getResultsPresentation(),
9718 "Anonymity" => $this->getAnonymity(),
9719 "ShowCancel" => $this->getShowCancel(),
9720 "ShowMarker" => $this->getShowMarker(),
9721 "ReportingDate" => $this->getReportingDate(),
9722 "NrOfTries" => $this->getNrOfTries(),
9723 'BlockAfterPassed' => (int) $this->isBlockPassesAfterPassedEnabled(),
9724 "Shuffle" => $this->getShuffleQuestions(),
9725 "Kiosk" => $this->getKiosk(),
9726 "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9727 "ProcessingTime" => $this->getProcessingTime(),
9728 "EnableProcessingTime" => $this->getEnableProcessingTime(),
9729 "ResetProcessingTime" => $this->getResetProcessingTime(),
9730 "StartingTimeEnabled" => $this->isStartingTimeEnabled(),
9731 "StartingTime" => $this->getStartingTime(),
9732 "EndingTimeEnabled" => $this->isEndingTimeEnabled(),
9733 "EndingTime" => $this->getEndingTime(),
9734 "ECTSOutput" => $this->getECTSOutput(),
9735 "ECTSFX" => $this->getECTSFX(),
9736 "ECTSGrades" => $this->getECTSGrades(),
9737 "questionSetType" => $this->getQuestionSetType(),
9738 "CountSystem" => $this->getCountSystem(),
9739 "MCScoring" => $this->getMCScoring(),
9740 "mailnotification" => $this->getMailNotification(),
9741 "mailnottype" => $this->getMailNotificationType(),
9742 "exportsettings" => $this->getExportSettings(),
9743 "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings(),
9744 'obligations_enabled' => (int) $this->areObligationsEnabled(),
9745 'offer_question_hints' => (int) $this->isOfferingQuestionHintsEnabled(),
9746 'pass_deletion_allowed' => (int) $this->isPassDeletionAllowed(),
9747 'enable_examview' => $this->getEnableExamview(),
9748 'show_examview_html' => $this->getShowExamviewHtml(),
9749 'show_examview_pdf' => $this->getShowExamviewPdf(),
9750 'char_selector_availability' => $this->getCharSelectorAvailability(),
9751 'char_selector_definition' => $this->getCharSelectorDefinition(),
9752 'skill_service' => (int) $this->isSkillServiceEnabled(),
9753 'result_tax_filters' => (array) $this->getResultFilterTaxIds(),
9754 'show_grading_status' => (int) $this->isShowGradingStatusEnabled(),
9755 'show_grading_mark' => (int) $this->isShowGradingMarkEnabled(),
9756
9757 'follow_qst_answer_fixation' => $this->isFollowupQuestionAnswerFixationEnabled(),
9758 'inst_fb_answer_fixation' => $this->isInstantFeedbackAnswerFixationEnabled(),
9759 'force_inst_fb' => $this->isForceInstantFeedbackEnabled(),
9760 'redirection_mode' => $this->getRedirectionMode(),
9761 'redirection_url' => $this->getRedirectionUrl(),
9762 'sign_submission' => $this->getSignSubmission(),
9763 'autosave' => (int) $this->getAutosave(),
9764 'autosave_ival' => (int) $this->getAutosaveIval(),
9765 'examid_in_test_pass' => (int) $this->isShowExamIdInTestPassEnabled(),
9766 'examid_in_test_res' => (int) $this->isShowExamIdInTestResultsEnabled(),
9767
9768 'enable_archiving' => (int) $this->getEnableArchiving(),
9769 'password_enabled' => (int) $this->isPasswordEnabled(),
9770 'password' => (string) $this->getPassword(),
9771 'fixed_participants' => $this->getFixedParticipants(),
9772 'limit_users_enabled' => $this->isLimitUsersEnabled(),
9773 'allowedusers' => $this->getAllowedUsers(),
9774 'alloweduserstimegap' => $this->getAllowedUsersTimeGap(),
9775 'pool_usage' => $this->getPoolUsage(),
9776 'activation_limited' => $this->isActivationLimited(),
9777 'activation_start_time' => $this->getActivationStartingTime(),
9778 'activation_end_time' => $this->getActivationEndingTime(),
9779 'activation_visibility' => $this->getActivationVisibility(),
9780 'highscore_enabled' => $this->getHighscoreEnabled(),
9781 'highscore_anon' => $this->getHighscoreAnon(),
9782 'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
9783 'highscore_score' => $this->getHighscoreScore(),
9784 'highscore_percentage' => $this->getHighscorePercentage(),
9785 'highscore_hints' => $this->getHighscoreHints(),
9786 'highscore_wtime' => $this->getHighscoreWTime(),
9787 'highscore_own_table' => $this->getHighscoreOwnTable(),
9788 'highscore_top_table' => $this->getHighscoreTopTable(),
9789 'highscore_top_num' => $this->getHighscoreTopNum(),
9790 'use_previous_answers' => (string) $this->getUsePreviousAnswers(),
9791 'pass_waiting' => $this->getPassWaiting()
9792 );
9793
9794 $next_id = $ilDB->nextId('tst_test_defaults');
9795 $ilDB->insert(
9796 'tst_test_defaults',
9797 array(
9798 'test_defaults_id' => array('integer', $next_id),
9799 'name' => array('text', $a_name),
9800 'user_fi' => array('integer', $ilUser->getId()),
9801 'defaults' => array('clob', serialize($testsettings)),
9802 'marks' => array('clob', serialize($this->mark_schema)),
9803 'tstamp' => array('integer', time())
9804 )
9805 );
9806 }
9807
9815 public function applyDefaults($test_defaults)
9816 {
9817 $testsettings = unserialize($test_defaults["defaults"]);
9818 include_once "./Modules/Test/classes/class.assMarkSchema.php";
9819 $this->mark_schema = unserialize($test_defaults["marks"]);
9820
9821 $this->setTitleOutput($testsettings["TitleOutput"]);
9822 $this->setPassScoring($testsettings["PassScoring"]);
9823 $this->setIntroductionEnabled($testsettings["IntroEnabled"]);
9824 $this->setIntroduction($testsettings["Introduction"]);
9825 $this->setFinalStatement($testsettings["FinalStatement"]);
9826 $this->setShowInfo($testsettings["ShowInfo"]);
9827 $this->setForceJS($testsettings["ForceJS"]);
9828 $this->setCustomStyle($testsettings["CustomStyle"]);
9829 $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
9830 $this->setSequenceSettings($testsettings["SequenceSettings"]);
9831 $this->setScoreReporting($testsettings["ScoreReporting"]);
9832 $this->setScoreCutting($testsettings['ScoreCutting']);
9833 $this->setSpecificAnswerFeedback($testsettings['SpecificAnswerFeedback']);
9834 $this->setPrintBestSolutionWithResult((bool) $testsettings['PrintBsWithRes']);
9835 $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
9836 $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
9837 $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
9838 $this->setResultsPresentation($testsettings["ResultsPresentation"]);
9839 $this->setAnonymity($testsettings["Anonymity"]);
9840 $this->setShowCancel($testsettings["ShowCancel"]);
9841 $this->setShuffleQuestions($testsettings["Shuffle"]);
9842 $this->setShowMarker($testsettings["ShowMarker"]);
9843 $this->setReportingDate($testsettings["ReportingDate"]);
9844 $this->setNrOfTries($testsettings["NrOfTries"]);
9845 $this->setBlockPassesAfterPassedEnabled((bool) $testsettings['BlockAfterPassed']);
9846 $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
9847 $this->setRedirectionMode($testsettings['redirection_mode']);
9848 $this->setRedirectionUrl($testsettings['redirection_url']);
9849 $this->setProcessingTime($testsettings["ProcessingTime"]);
9850 $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
9851 $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
9852 $this->setStartingTimeEnabled($testsettings["StartingTimeEnabled"]);
9853 $this->setStartingTime($testsettings["StartingTime"]);
9854 $this->setKiosk($testsettings["Kiosk"]);
9855 $this->setEndingTimeEnabled($testsettings["EndingTimeEnabled"]);
9856 $this->setEndingTime($testsettings["EndingTime"]);
9857 $this->setECTSOutput($testsettings["ECTSOutput"]);
9858 $this->setECTSFX($testsettings["ECTSFX"]);
9859 $this->setECTSGrades($testsettings["ECTSGrades"]);
9860 if (isset($testsettings["isRandomTest"])) {
9861 if ($testsettings["isRandomTest"]) {
9862 $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
9863 } else {
9864 $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
9865 }
9866 } elseif (isset($testsettings["questionSetType"])) {
9867 $this->setQuestionSetType($testsettings["questionSetType"]);
9868 }
9869 $this->setCountSystem($testsettings["CountSystem"]);
9870 $this->setMCScoring($testsettings["MCScoring"]);
9871 $this->setMailNotification($testsettings["mailnotification"]);
9872 $this->setMailNotificationType($testsettings["mailnottype"]);
9873 $this->setExportSettings($testsettings['exportsettings']);
9874 $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
9875 $this->setObligationsEnabled($testsettings["obligations_enabled"]);
9876 $this->setOfferingQuestionHintsEnabled($testsettings["offer_question_hints"]);
9877 $this->setHighscoreEnabled($testsettings['highscore_enabled']);
9878 $this->setHighscoreAnon($testsettings['highscore_anon']);
9879 $this->setHighscoreAchievedTS($testsettings['highscore_achieved_ts']);
9880 $this->setHighscoreScore($testsettings['highscore_score']);
9881 $this->setHighscorePercentage($testsettings['highscore_percentage']);
9882 $this->setHighscoreHints($testsettings['highscore_hints']);
9883 $this->setHighscoreWTime($testsettings['highscore_wtime']);
9884 $this->setHighscoreOwnTable($testsettings['highscore_own_table']);
9885 $this->setHighscoreTopTable($testsettings['highscore_top_table']);
9886 $this->setHighscoreTopNum($testsettings['highscore_top_num']);
9887 $this->setPassDeletionAllowed($testsettings['pass_deletion_allowed']);
9888 if (isset($testsettings['examid_in_kiosk'])) {
9889 $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_kiosk']);
9890 } else {
9891 $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_test_pass']);
9892 }
9893 if (isset($testsettings['show_exam_id'])) {
9894 $this->setShowExamIdInTestResultsEnabled($testsettings['show_exam_id']);
9895 } else {
9896 $this->setShowExamIdInTestResultsEnabled($testsettings['examid_in_test_res']);
9897 }
9898 $this->setEnableExamview($testsettings['enable_examview']);
9899 $this->setShowExamviewHtml($testsettings['show_examview_html']);
9900 $this->setShowExamviewPdf($testsettings['show_examview_pdf']);
9901 $this->setEnableArchiving($testsettings['enable_archiving']);
9902 $this->setSignSubmission($testsettings['sign_submission']);
9903 $this->setCharSelectorAvailability($testsettings['char_selector_availability']);
9904 $this->setCharSelectorDefinition($testsettings['char_selector_definition']);
9905 $this->setSkillServiceEnabled((bool) $testsettings['skill_service']);
9906 $this->setResultFilterTaxIds((array) $testsettings['result_tax_filters']);
9907 $this->setShowGradingStatusEnabled((bool) $testsettings['show_grading_status']);
9908 $this->setShowGradingMarkEnabled((bool) $testsettings['show_grading_mark']);
9909
9910 $this->setFollowupQuestionAnswerFixationEnabled($testsettings['follow_qst_answer_fixation']);
9911 $this->setInstantFeedbackAnswerFixationEnabled($testsettings['inst_fb_answer_fixation']);
9912 $this->setForceInstantFeedbackEnabled($testsettings['force_inst_fb']);
9913 $this->setRedirectionMode($testsettings['redirection_mode']);
9914 $this->setRedirectionUrl($testsettings['redirection_url']);
9915
9916 $this->setAutosave($testsettings['autosave']);
9917 $this->setAutosaveIval($testsettings['autosave_ival']);
9918 $this->setShowExamIdInTestResultsEnabled((int) $testsettings['examid_in_test_res']);
9919 $this->setPasswordEnabled($testsettings['password_enabled']);
9920 $this->setPassword($testsettings['password']);
9921 $this->setFixedParticipants($testsettings['fixed_participants']);
9922 $this->setLimitUsersEnabled($testsettings['limit_users_enabled']);
9923 $this->setAllowedUsers($testsettings['allowedusers']);
9924 $this->setAllowedUsersTimeGap($testsettings['alloweduserstimegap']);
9925 $this->setUsePreviousAnswers($testsettings['use_previous_answers']);
9926 $this->setPoolUsage($testsettings['pool_usage']);
9927 $this->setActivationLimited($testsettings['activation_limited']);
9928 $this->setActivationStartingTime($testsettings['activation_start_time']);
9929 $this->setActivationEndingTime($testsettings['activation_end_time']);
9930 $this->setActivationVisibility($testsettings['activation_visibility']);
9931 $this->setPassWaiting($testsettings['pass_waiting']);
9932
9933 $this->saveToDb();
9934
9935 return true;
9936 }
9937
9945 public function processPrintoutput2FO($print_output)
9946 {
9947 if (extension_loaded("tidy")) {
9948 $config = array(
9949 "indent" => false,
9950 "output-xml" => true,
9951 "numeric-entities" => true
9952 );
9953 $tidy = new tidy();
9954 $tidy->parseString($print_output, $config, 'utf8');
9955 $tidy->cleanRepair();
9956 $print_output = tidy_get_output($tidy);
9957 $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
9958 } else {
9959 $print_output = str_replace("&nbsp;", "&#160;", $print_output);
9960 $print_output = str_replace("&otimes;", "X", $print_output);
9961 }
9962 $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
9963
9964 // additional font support
9965 global $DIC;
9966 $xsl = str_replace(
9967 'font-family="Helvetica, unifont"',
9968 'font-family="' . $DIC['ilSetting']->get('rpc_pdf_font', 'Helvetica, unifont') . '"',
9969 $xsl
9970 );
9971
9972 $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
9973 $xh = xslt_create();
9974 $params = array();
9975 $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", null, $args, $params);
9976 xslt_error($xh);
9977 xslt_free($xh);
9978 return $output;
9979 }
9980
9987 public function deliverPDFfromHTML($content, $title = null)
9988 {
9989 $content = preg_replace("/href=\".*?\"/", "", $content);
9990 $printbody = new ilTemplate("tpl.il_as_tst_print_body.html", true, true, "Modules/Test");
9991 $printbody->setVariable("TITLE", ilUtil::prepareFormOutput($this->getTitle()));
9992 $printbody->setVariable("ADM_CONTENT", $content);
9993 $printbody->setCurrentBlock("css_file");
9994 $printbody->setVariable("CSS_FILE", ilUtil::getStyleSheetLocation("filesystem", "delos.css"));
9995 $printbody->parseCurrentBlock();
9996 $printoutput = $printbody->get();
9997 $html = str_replace("href=\"./", "href=\"" . ILIAS_HTTP_PATH . "/", $printoutput);
9998 $html = preg_replace("/<div id=\"dontprint\">.*?<\\/div>/ims", "", $html);
9999 if (extension_loaded("tidy")) {
10000 $config = array(
10001 "indent" => false,
10002 "output-xml" => true,
10003 "numeric-entities" => true
10004 );
10005 $tidy = new tidy();
10006 $tidy->parseString($html, $config, 'utf8');
10007 $tidy->cleanRepair();
10008 $html = tidy_get_output($tidy);
10009 $html = preg_replace("/^.*?(<html)/", "\\1", $html);
10010 } else {
10011 $html = str_replace("&nbsp;", "&#160;", $html);
10012 $html = str_replace("&otimes;", "X", $html);
10013 }
10014 $html = preg_replace("/src=\".\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
10015 $this->deliverPDFfromFO($this->processPrintoutput2FO($html), $title);
10016 }
10017
10024 public function deliverPDFfromFO($fo, $title = null)
10025 {
10026 global $DIC;
10027 $ilLog = $DIC['ilLog'];
10028
10029 include_once "./Services/Utilities/classes/class.ilUtil.php";
10030 $fo_file = ilUtil::ilTempnam() . ".fo";
10031 $fp = fopen($fo_file, "w");
10032 fwrite($fp, $fo);
10033 fclose($fp);
10034
10035 include_once './Services/WebServices/RPC/classes/class.ilRpcClientFactory.php';
10036 try {
10037 $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo);
10038 $filename = (strlen($title)) ? $title : $this->getTitle();
10039 ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
10040 return true;
10041 } catch (Exception $e) {
10042 $ilLog->write(__METHOD__ . ': ' . $e->getMessage());
10043 return false;
10044 }
10045 }
10046
10056 public static function getManualFeedback($active_id, $question_id, $pass)
10057 {
10058 $feedback = "";
10059 $row = self::getSingleManualFeedback($active_id, $question_id, $pass);
10060
10061 if (count($row) > 0 && ($row['finalized_evaluation'] || \ilTestService::isManScoringDone($active_id))) {
10062 $feedback = $row['feedback'];
10063 }
10064
10065 return $feedback;
10066 }
10067
10077 public static function getSingleManualFeedback($active_id, $question_id, $pass)
10078 {
10079 global $DIC;
10080
10081 $ilDB = $DIC->database();
10082 $row = array();
10083 $result = $ilDB->queryF(
10084 "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10085 array('integer', 'integer', 'integer'),
10086 array($active_id, $question_id, $pass)
10087 );
10088
10089 if ($result->numRows() === 1) {
10090 $row = $ilDB->fetchAssoc($result);
10091 $row['feedback'] = ilRTE::_replaceMediaObjectImageSrc($row['feedback'], 1);
10092 } else {
10093 $DIC->logger()->root()->warning("WARNING: Multiple feedback entries on tst_manual_fb for " .
10094 "active_fi = $active_id , question_fi = $question_id and pass = $pass");
10095 }
10096
10097 return $row;
10098 }
10099
10107 public static function getCompleteManualFeedback(int $question_id)
10108 {
10109 global $DIC;
10110
10111 $ilDB = $DIC->database();
10112 $feedback = array();
10113 $result = $ilDB->queryF(
10114 "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
10115 array('integer'),
10116 array($question_id)
10117 );
10118
10119 while ($row = $ilDB->fetchAssoc($result)) {
10120 $active = $row['active_fi'];
10121 $pass = $row['pass'];
10122 $question = $row['question_fi'];
10123
10124 $row['feedback'] = ilRTE::_replaceMediaObjectImageSrc($row['feedback'], 1);
10125
10126 $feedback[$active][$pass][$question] = $row;
10127 }
10128
10129 return $feedback;
10130 }
10131
10143 public function saveManualFeedback($active_id, $question_id, $pass, $feedback, $finalized = false, $is_single_feedback = false)
10144 {
10145 global $DIC;
10146
10147 $feedback_old = $this->getSingleManualFeedback($active_id, $question_id, $pass);
10148
10149 $finalized_record = (int) $feedback_old['finalized_evaluation'];
10150 if ($finalized_record === 0 || ($is_single_feedback && $finalized_record === 1)) {
10151 $DIC->database()->manipulateF(
10152 "DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10153 array('integer', 'integer', 'integer'),
10154 array($active_id, $question_id, $pass)
10155 );
10156
10157 $this->insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
10158
10160 $this->logManualFeedback($active_id, $question_id, $feedback);
10161 }
10162 }
10163
10164 return true;
10165 }
10166
10177 private function insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old)
10178 {
10179 global $DIC;
10180
10181 $ilDB = $DIC->database();
10182 $ilUser = $DIC->user();
10183 $next_id = $ilDB->nextId('tst_manual_fb');
10184 $user = $ilUser->getId();
10185 $finalized_time = time();
10186
10187 $update_default = [
10188 'manual_feedback_id' => [ 'integer', $next_id],
10189 'active_fi' => [ 'integer', $active_id],
10190 'question_fi' => [ 'integer', $question_id],
10191 'pass' => [ 'integer', $pass],
10192 'feedback' => [ 'clob', ilRTE::_replaceMediaObjectImageSrc($feedback, 0)],
10193 'tstamp' => [ 'integer', time()]
10194 ];
10195
10196 if ($feedback_old['finalized_evaluation'] == 1) {
10197 $user = $feedback_old['finalized_by_usr_id'];
10198 $finalized_time = $feedback_old['finalized_tstamp'];
10199 }
10200
10201 if ($finalized === false) {
10202 $update_default['finalized_evaluation'] = ['integer', 0];
10203 $update_default['finalized_by_usr_id'] = ['integer', 0];
10204 $update_default['finalized_tstamp'] = ['integer', 0];
10205 } elseif ($finalized === true) {
10206 $update_default['finalized_evaluation'] = ['integer', 1];
10207 $update_default['finalized_by_usr_id'] = ['integer', $user];
10208 $update_default['finalized_tstamp'] = ['integer', $finalized_time];
10209 }
10210
10211 $ilDB->insert('tst_manual_fb', $update_default);
10212 }
10213
10221 private function logManualFeedback($active_id, $question_id, $feedback)
10222 {
10223 global $DIC;
10224
10225 $ilUser = $DIC->user();
10226 $lng = $DIC->language();
10227 $username = ilObjTestAccess::_getParticipantData($active_id);
10228
10229 $this->logAction(
10230 sprintf(
10231 $lng->txtlng('assessment', 'log_manual_feedback', ilObjAssessmentFolder::_getLogLanguage()),
10232 $ilUser->getFullname() . ' (' . $ilUser->getLogin() . ')',
10233 $username,
10234 assQuestion::_getQuestionTitle($question_id),
10235 $feedback
10236 )
10237 );
10238 }
10239
10247 public function getJavaScriptOutput()
10248 {
10249 return true;
10250
10251 // global $DIC;
10252// $ilUser = $DIC['ilUser'];
10253// if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
10254// if ($this->getForceJS()) return TRUE;
10255// $assessmentSetting = new ilSetting("assessment");
10256// return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
10257 }
10258
10259 public function &createTestSequence($active_id, $pass, $shuffle)
10260 {
10261 include_once "./Modules/Test/classes/class.ilTestSequence.php";
10262 $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10263 }
10264
10270 public function setTestId($a_id)
10271 {
10272 $this->test_id = $a_id;
10273 }
10274
10283 public function getDetailedTestResults($participants)
10284 {
10285 $results = array();
10286 if (count($participants)) {
10287 foreach ($participants as $active_id => $user_rec) {
10288 $row = array();
10289 $reached_points = 0;
10290 $max_points = 0;
10291 foreach ($this->questions as $value) {
10292 $question = &ilObjTest::_instanciateQuestion($value);
10293 if (is_object($question)) {
10294 $max_points += $question->getMaximumPoints();
10295 $reached_points += $question->getReachedPoints($active_id);
10296 if ($max_points > 0) {
10297 $percentvalue = $reached_points / $max_points;
10298 if ($percentvalue < 0) {
10299 $percentvalue = 0.0;
10300 }
10301 } else {
10302 $percentvalue = 0;
10303 }
10304 if ($this->getAnonymity()) {
10305 $user_rec['firstname'] = "";
10306 $user_rec['lastname'] = $this->lng->txt("anonymous");
10307 }
10308 $row = array(
10309 "user_id" => $user_rec['usr_id'],
10310 "matriculation" => $user_rec['matriculation'],
10311 "lastname" => $user_rec['lastname'],
10312 "firstname" => $user_rec['firstname'],
10313 "login" => $user_rec['login'],
10314 "question_id" => $question->getId(),
10315 "question_title" => $question->getTitle(),
10316 "reached_points" => $reached_points,
10317 "max_points" => $max_points,
10318 "passed" => $user_rec['passed'] ? '1' : '0',
10319 );
10320 $results[] = $row;
10321 }
10322 }
10323 }
10324 }
10325 return $results;
10326 }
10327
10331 public static function _lookupTestObjIdForQuestionId($a_q_id)
10332 {
10333 global $DIC;
10334 $ilDB = $DIC['ilDB'];
10335
10336 $result = $ilDB->queryF(
10337 "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",
10338 array('integer'),
10339 array($a_q_id)
10340 );
10341 $rec = $ilDB->fetchAssoc($result);
10342 return $rec["obj_id"];
10343 }
10344
10351 public function isPluginActive($a_pname)
10352 {
10353 global $DIC;
10354 $ilPluginAdmin = $DIC['ilPluginAdmin'];
10355 if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname)) {
10356 return true;
10357 } else {
10358 return false;
10359 }
10360 }
10361
10362 public function getPassed($active_id)
10363 {
10364 global $DIC;
10365 $ilDB = $DIC['ilDB'];
10366
10367 $result = $ilDB->queryF(
10368 "SELECT passed FROM tst_result_cache WHERE active_fi = %s",
10369 array('integer'),
10370 array($active_id)
10371 );
10372 if ($result->numRows()) {
10373 $row = $ilDB->fetchAssoc($result);
10374 return $row['passed'];
10375 } else {
10376 $counted_pass = ilObjTest::_getResultPass($active_id);
10377 $result_array = &$this->getTestResult($active_id, $counted_pass);
10378 return $result_array["test"]["passed"];
10379 }
10380 }
10381
10387 public function canShowCertificate($testSession, $user_id, $active_id)
10388 {
10389 if ($this->canShowTestResults($testSession)) {
10390 $isComplete = false;
10391 $userCertificateRepository = new ilUserCertificateRepository($this->db, $this->log);
10392 try {
10393 $userCertificateRepository->fetchActiveCertificate($user_id, $this->getId());
10394 $isComplete = true;
10395 } catch (ilException $e) {
10396 }
10397
10398 if ($isComplete) {
10399 $vis = $this->getCertificateVisibility();
10400 $showcert = false;
10401 switch ($vis) {
10402 case 0:
10403 $showcert = true;
10404 break;
10405 case 1:
10406 if ($this->getPassed($active_id)) {
10407 $showcert = true;
10408 }
10409 break;
10410 case 2:
10411 $showcert = false;
10412 break;
10413 }
10414 if ($showcert) {
10415 return true;
10416 } else {
10417 return false;
10418 }
10419 } else {
10420 return false;
10421 }
10422 } else {
10423 return false;
10424 }
10425 }
10426
10430 public function getParticipantsForTestAndQuestion($test_id, $question_id)
10431 {
10433 global $DIC;
10434 $ilDB = $DIC['ilDB'];
10435
10436 $query = "
10437 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
10438 FROM tst_test_result
10439 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s
10440 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi
10441 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi
10442 WHERE tst_test_result.question_fi = %s
10443 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC
10444 ";
10445
10446 $result = $ilDB->queryF(
10447 $query,
10448 array('integer', 'integer'),
10449 array($test_id, $question_id)
10450 );
10451 $foundusers = array();
10453 while ($row = $ilDB->fetchAssoc($result)) {
10454 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row["active_fi"])) {
10455 continue;
10456 }
10457
10458 if (!array_key_exists($row["active_fi"], $foundusers)) {
10459 $foundusers[$row["active_fi"]] = array();
10460 }
10461 array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10462 }
10463 return $foundusers;
10464 }
10465
10472 {
10473 $data = &$this->getCompleteEvaluationData();
10474 $foundParticipants = &$data->getParticipants();
10475 $results = array("overview" => array(), "questions" => array());
10476 if (count($foundParticipants)) {
10477 $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10478 $total_finished = $data->getTotalFinishedParticipants();
10479 $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10480 $average_time = $this->evalTotalStartedAverageTime($data->getParticipantIds());
10481 $diff_seconds = $average_time;
10482 $diff_hours = floor($diff_seconds / 3600);
10483 $diff_seconds -= $diff_hours * 3600;
10484 $diff_minutes = floor($diff_seconds / 60);
10485 $diff_seconds -= $diff_minutes * 60;
10486 $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10487 $total_passed = 0;
10488 $total_passed_reached = 0;
10489 $total_passed_max = 0;
10490 $total_passed_time = 0;
10491 foreach ($foundParticipants as $userdata) {
10492 if ($userdata->getPassed()) {
10493 $total_passed++;
10494 $total_passed_reached += $userdata->getReached();
10495 $total_passed_max += $userdata->getMaxpoints();
10496 $total_passed_time += $userdata->getTimeOfWork();
10497 }
10498 }
10499 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10500 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10501 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10502 $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10503 $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);
10504 $average_time = $average_passed_time;
10505 $diff_seconds = $average_time;
10506 $diff_hours = floor($diff_seconds / 3600);
10507 $diff_seconds -= $diff_hours * 3600;
10508 $diff_minutes = floor($diff_seconds / 60);
10509 $diff_seconds -= $diff_minutes * 60;
10510 $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10511 }
10512
10513 foreach ($data->getQuestionTitles() as $question_id => $question_title) {
10514 $answered = 0;
10515 $reached = 0;
10516 $max = 0;
10517 foreach ($foundParticipants as $userdata) {
10518 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
10519 if (is_object($userdata->getPass($i))) {
10520 $question = &$userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10521 if (is_array($question)) {
10522 $answered++;
10523 $reached += $question["reached"];
10524 $max += $question["points"];
10525 }
10526 }
10527 }
10528 }
10529 $percent = $max ? $reached / $max * 100.0 : 0;
10530 $results["questions"][$question_id] = array(
10531 $question_title,
10532 sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10533 sprintf("%.2f", $percent) . "%",
10534 $answered,
10535 sprintf("%.2f", $answered ? $reached / $answered : 0),
10536 sprintf("%.2f", $answered ? $max / $answered : 0),
10537 $percent / 100.0
10538 );
10539 }
10540 return $results;
10541 }
10542
10546 public function getXMLZip()
10547 {
10548 require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10549 $expFactory = new ilTestExportFactory($this);
10550 $test_exp = $expFactory->getExporter('xml');
10551 return $test_exp->buildExportFile();
10552 }
10553
10557 public function getMailNotification()
10558 {
10560 }
10561
10567 public function setMailNotification($a_notification)
10568 {
10569 $this->mailnotification = $a_notification;
10570 }
10571
10572 public function sendSimpleNotification($active_id)
10573 {
10574 include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10575
10576 $mail = new ilTestMailNotification();
10577 $owner_id = $this->getOwner();
10578 $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10579 $mail->sendSimpleNotification($owner_id, $this->getTitle(), $usr_data);
10580 }
10581
10588 {
10589 include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
10590 include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
10591 $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI($this->getRefId()), 'outEvaluation', $this->getAnonymity());
10592 return $table_gui->getSelectedColumns();
10593 }
10594
10595 public function sendAdvancedNotification($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
10603 $participantList = new ilTestParticipantList($this);
10604 $participantList->initializeFromDbRows($this->getTestParticipants());
10605
10606 require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10607 $expFactory = new ilTestExportFactory($this);
10608 $exportObj = $expFactory->getExporter('results');
10609 $exportObj->setForcedAccessFilteredParticipantList($participantList);
10610 $file = $exportObj->exportToExcel($deliver = false, 'active_id', $active_id, $passedonly = false);
10611 include_once "./Services/Mail/classes/class.ilFileDataMail.php";
10613 $fd->copyAttachmentFile($file, "result_" . $active_id . ".xls");
10614 $file_names[] = "result_" . $active_id . ".xls";
10615
10616 $mail->sendAdvancedNotification($owner_id, $this->getTitle(), $usr_data, $file_names);
10617
10618 if (count($file_names)) {
10619 $fd->unlinkFiles($file_names);
10620 unset($fd);
10621 @unlink($file);
10622 }
10623 }
10624
10625 public function getResultsForActiveId($active_id)
10626 {
10627 global $DIC;
10628 $ilDB = $DIC['ilDB'];
10629
10630 $query = "
10631 SELECT *
10632 FROM tst_result_cache
10633 WHERE active_fi = %s
10634 ";
10635
10636 $result = $ilDB->queryF(
10637 $query,
10638 array('integer'),
10639 array($active_id)
10640 );
10641
10642 $row = $ilDB->fetchAssoc($result);
10643
10644 if (!$result->numRows()
10645 || $row['pass'] !== ilObjTest::_getResultPass($active_id)) {
10646 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10647
10649
10650 $query = "
10651 SELECT *
10652 FROM tst_result_cache
10653 WHERE active_fi = %s
10654 ";
10655
10656 $result = $ilDB->queryF(
10657 $query,
10658 array('integer'),
10659 array($active_id)
10660 );
10661
10662 $row = $ilDB->fetchAssoc($result);
10663 }
10664
10665 return $row;
10666 }
10667
10668 public function getMailNotificationType()
10669 {
10670 if ($this->mailnottype == 1) {
10671 return $this->mailnottype;
10672 } else {
10673 return 0;
10674 }
10675 }
10676
10677 public function setMailNotificationType($a_type)
10678 {
10679 if ($a_type == 1) {
10680 $this->mailnottype = 1;
10681 } else {
10682 $this->mailnottype = 0;
10683 }
10684 }
10685
10686 public function getExportSettings()
10687 {
10688 if ($this->exportsettings) {
10689 return $this->exportsettings;
10690 } else {
10691 return 0;
10692 }
10693 }
10694
10695 public function setExportSettings($a_settings)
10696 {
10697 if ($a_settings) {
10698 $this->exportsettings = $a_settings;
10699 } else {
10700 $this->exportsettings = 0;
10701 }
10702 }
10703
10705 {
10706 if (($this->exportsettings & 1) > 0) {
10707 return true;
10708 } else {
10709 return false;
10710 }
10711 }
10712
10713 public function setExportSettingsSingleChoiceShort($a_settings)
10714 {
10715 if ($a_settings) {
10716 $this->exportsettings = $this->exportsettings | 1;
10717 } else {
10719 $this->exportsettings = $this->exportsettings ^ 1;
10720 }
10721 }
10722 }
10723
10724 public function getEnabledViewMode()
10725 {
10726 return $this->enabled_view_mode;
10727 }
10728
10729 public function setEnabledViewMode($mode)
10730 {
10731 $this->enabled_view_mode = $mode;
10732 }
10733
10734 public function setTemplate($template_id)
10735 {
10736 $this->template_id = (int) $template_id;
10737 }
10738
10739 public function getTemplate()
10740 {
10741 return $this->template_id;
10742 }
10743
10744 public function moveQuestionAfterOLD($previous_question_id, $new_question_id)
10745 {
10746 $new_array = array();
10747 $position = 1;
10748
10749 $query = 'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
10750 $types = array('integer');
10751 $values = array($this->getTestId());
10752
10753 $new_question_id += 1;
10754
10755 global $DIC;
10756 $ilDB = $DIC['ilDB'];
10757 $inserted = false;
10758 $res = $ilDB->queryF($query, $types, $values);
10759 while ($row = $ilDB->fetchAssoc($res)) {
10760 $qid = $row['question_fi'];
10761
10762 if ($qid == $new_question_id) {
10763 continue;
10764 } elseif ($qid == $previous_question_id) {
10765 $new_array[$position++] = $qid;
10766 $new_array[$position++] = $new_question_id;
10767 $inserted = true;
10768 } else {
10769 $new_array[$position++] = $qid;
10770 }
10771 }
10772
10773 $update_query = 'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
10774 $update_types = array('integer', 'integer', 'integer');
10775
10776 foreach ($new_array as $position => $qid) {
10777 $ilDB->manipulateF(
10778 $update_query,
10779 $update_types,
10780 $vals = array(
10781 $position,
10782 $this->getTestId(),
10783 $qid
10784 )
10785 );
10786 }
10787 }
10788
10790 {
10791 return (
10794 );
10795 }
10796
10798 {
10799 $values = array();
10800
10801 if ($this->getSpecificAnswerFeedback()) {
10802 $values[] = 'instant_feedback_specific';
10803 }
10804 if ($this->getGenericAnswerFeedback()) {
10805 $values[] = 'instant_feedback_generic';
10806 }
10807 if ($this->getAnswerFeedbackPoints()) {
10808 $values[] = 'instant_feedback_points';
10809 }
10810 if ($this->getInstantFeedbackSolution()) {
10811 $values[] = 'instant_feedback_solution';
10812 }
10813
10814 return $values;
10815 }
10816
10817 public function setInstantFeedbackOptionsByArray($options)
10818 {
10819 if (is_array($options)) {
10820 $this->setGenericAnswerFeedback(in_array('instant_feedback_generic', $options) ? 1 : 0);
10821 $this->setSpecificAnswerFeedback(in_array('instant_feedback_specific', $options) ? 1 : 0);
10822 $this->setAnswerFeedbackPoints(in_array('instant_feedback_points', $options) ? 1 : 0);
10823 $this->setInstantFeedbackSolution(in_array('instant_feedback_solution', $options) ? 1 : 0);
10824 } else {
10825 $this->setGenericAnswerFeedback(0);
10826 $this->setSpecificAnswerFeedback(0);
10827 $this->setAnswerFeedbackPoints(0);
10829 }
10830 }
10831
10833 {
10834 $setter = array(
10835 'pass_details' => 'setShowPassDetails',
10836 'solution_details' => 'setShowSolutionDetails',
10837 'solution_printview' => 'setShowSolutionPrintview',
10838 'solution_feedback' => 'setShowSolutionFeedback',
10839 'solution_answers_only' => 'setShowSolutionAnswersOnly',
10840 'solution_signature' => 'setShowSolutionSignature',
10841 'solution_suggested' => 'setShowSolutionSuggested',
10842 );
10843 foreach ($setter as $key => $setter) {
10844 if (in_array($key, $options)) {
10845 $this->$setter(1);
10846 } else {
10847 $this->$setter(0);
10848 }
10849 }
10850 }
10851
10852 public function getPoolUsage()
10853 {
10854 return (boolean) $this->poolUsage;
10855 }
10856
10857 public function setPoolUsage($usage)
10858 {
10859 $this->poolUsage = (boolean) $usage;
10860 }
10861
10866 {
10867 global $DIC;
10868 $tree = $DIC['tree'];
10869 $db = $DIC['ilDB'];
10870 $pluginAdmin = $DIC['ilPluginAdmin'];
10871
10872 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
10873 $qscFactory = new ilTestQuestionSetConfigFactory($tree, $db, $pluginAdmin, $this);
10874 $questionSetConfig = $qscFactory->getQuestionSetConfig();
10875
10876 /* @var ilTestFixedQuestionSetConfig $questionSetConfig */
10877 $reindexedSequencePositionMap = $questionSetConfig->reindexQuestionOrdering();
10878
10879 $this->loadQuestions();
10880
10881 return $reindexedSequencePositionMap;
10882 }
10883
10884 public function setQuestionOrderAndObligations($orders, $obligations)
10885 {
10886 global $DIC;
10887 $ilDB = $DIC['ilDB'];
10888
10889 asort($orders);
10890
10891 $i = 0;
10892
10893 foreach ($orders as $id => $position) {
10894 $i++;
10895
10896 $obligatory = (
10897 isset($obligations[$id]) && $obligations[$id] ? 1 : 0
10898 );
10899
10900 $query = "
10901 UPDATE tst_test_question
10902 SET sequence = %s,
10903 obligatory = %s
10904 WHERE question_fi = %s
10905 ";
10906
10907 $ilDB->manipulateF(
10908 $query,
10909 array('integer', 'integer', 'integer'),
10910 array($i, $obligatory, $id)
10911 );
10912 }
10913
10914 $this->loadQuestions();
10915 }
10916
10917 public function moveQuestionAfter($question_to_move, $question_before)
10918 {
10919 global $DIC;
10920 $ilDB = $DIC['ilDB'];
10921 //var_dump(func_get_args());
10922 if ($question_before) {
10923 $query = 'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
10924 $types = array('integer');
10925 $values = array($question_before);
10926 $rset = $ilDB->queryF($query, $types, $values);
10927 }
10928
10929 if (!$question_before || ($rset && !($row = $ilDB->fetchAssoc($rset)))) {
10930 $row = array(
10931 'sequence' => 0,
10932 'test_fi' => $this->getTestId(),
10933 );
10934 }
10935
10936 $update = 'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
10937 $types = array('integer', 'integer');
10938 $values = array($row['sequence'], $row['test_fi']);
10939 $ilDB->manipulateF($update, $types, $values);
10940
10941 $update = 'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
10942 $types = array('integer', 'integer');
10943 $values = array($row['sequence'] + 1, $question_to_move);
10944 $ilDB->manipulateF($update, $types, $values);
10945
10947 }
10948
10950 {
10951 global $DIC;
10952 $ilDB = $DIC['ilDB'];
10953
10955
10956 $IN_questions = $ilDB->in('q1.question_id', array_keys($questions), false, 'integer');
10957
10958 $query = "
10959 SELECT count(q1.question_id) cnt
10960
10961 FROM qpl_questions q1
10962
10963 INNER JOIN qpl_questions q2
10964 ON q2.question_id = q1.original_id
10965
10966 WHERE $IN_questions
10967 AND q1.obj_fi = q2.obj_fi
10968 ";
10969
10970 $rset = $ilDB->query($query);
10971
10972 $row = $ilDB->fetchAssoc($rset);
10973
10974 return $row['cnt'] > 0;
10975 }
10976
10983 public static function _lookupFinishedUserTests($a_user_id)
10984 {
10985 global $DIC;
10986 $ilDB = $DIC['ilDB'];
10987
10988 $result = $ilDB->queryF(
10989 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
10990 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
10991 " WHERE user_fi=%s" .
10992 " GROUP BY test_fi",
10993 array('integer', 'integer'),
10994 array($a_user_id, 1)
10995 );
10996 $all = array();
10997 while ($row = $ilDB->fetchAssoc($result)) {
10998 $obj_id = self::_getObjectIDFromTestID($row["test_fi"]);
10999 $all[$obj_id] = (bool) $row["pass"];
11000 }
11001 return $all;
11002 }
11003 public function getQuestions()
11004 {
11005 return $this->questions;
11006 }
11007
11008 public function isOnline()
11009 {
11010 return $this->online;
11011 }
11012
11013 public function setOnline($a_online = true)
11014 {
11015 $this->online = (bool) $a_online;
11016 }
11017
11021 public function getOldOnlineStatus()
11022 {
11024 }
11025
11030 {
11031 $this->oldOnlineStatus = $oldOnlineStatus;
11032 }
11033
11034 public function setPrintBestSolutionWithResult($status)
11035 {
11036 $this->print_best_solution_with_result = (bool) $status;
11037 }
11038
11040 {
11042 }
11043
11050 {
11052 }
11053
11060 {
11061 $this->offeringQuestionHintsEnabled = (bool) $offeringQuestionHintsEnabled;
11062 }
11063
11064 public function setActivationVisibility($a_value)
11065 {
11066 $this->activation_visibility = (bool) $a_value;
11067 }
11068
11069 public function getActivationVisibility()
11070 {
11072 }
11073
11074 public function isActivationLimited()
11075 {
11076 return (bool) $this->activation_limited;
11077 }
11078
11079 public function setActivationLimited($a_value)
11080 {
11081 $this->activation_limited = (bool) $a_value;
11082 }
11083
11084 /* GET/SET for highscore feature */
11085
11091 public function setHighscoreEnabled($a_enabled)
11092 {
11093 $this->_highscore_enabled = (bool) $a_enabled;
11094 }
11095
11101 public function getHighscoreEnabled()
11102 {
11103 return (bool) $this->_highscore_enabled;
11104 }
11105
11113 public function setHighscoreAnon($a_anon)
11114 {
11115 $this->_highscore_anon = (bool) $a_anon;
11116 }
11117
11127 public function getHighscoreAnon()
11128 {
11129 return (bool) $this->_highscore_anon;
11130 }
11131
11140 public function isHighscoreAnon()
11141 {
11142 if ($this->getAnonymity() == 1) {
11143 return true;
11144 } else {
11145 return (bool) $this->getHighscoreAnon();
11146 }
11147 }
11148
11154 public function setHighscoreAchievedTS($a_achieved_ts)
11155 {
11156 $this->_highscore_achieved_ts = (bool) $a_achieved_ts;
11157 }
11158
11164 public function getHighscoreAchievedTS()
11165 {
11166 return (bool) $this->_highscore_achieved_ts;
11167 }
11168
11174 public function setHighscoreScore($a_score)
11175 {
11176 $this->_highscore_score = (bool) $a_score;
11177 }
11178
11184 public function getHighscoreScore()
11185 {
11186 return (bool) $this->_highscore_score;
11187 }
11188
11194 public function setHighscorePercentage($a_percentage)
11195 {
11196 $this->_highscore_percentage = (bool) $a_percentage;
11197 }
11198
11204 public function getHighscorePercentage()
11205 {
11206 return (bool) $this->_highscore_percentage;
11207 }
11208
11214 public function setHighscoreHints($a_hints)
11215 {
11216 $this->_highscore_hints = (bool) $a_hints;
11217 }
11218
11224 public function getHighscoreHints()
11225 {
11226 return (bool) $this->_highscore_hints;
11227 }
11228
11234 public function setHighscoreWTime($a_wtime)
11235 {
11236 $this->_highscore_wtime = (bool) $a_wtime;
11237 }
11238
11244 public function getHighscoreWTime()
11245 {
11246 return (bool) $this->_highscore_wtime;
11247 }
11248
11254 public function setHighscoreOwnTable($a_own_table)
11255 {
11256 $this->_highscore_own_table = (bool) $a_own_table;
11257 }
11258
11264 public function getHighscoreOwnTable()
11265 {
11266 return (bool) $this->_highscore_own_table;
11267 }
11268
11274 public function setHighscoreTopTable($a_top_table)
11275 {
11276 $this->_highscore_top_table = (bool) $a_top_table;
11277 }
11278
11284 public function getHighscoreTopTable()
11285 {
11286 return (bool) $this->_highscore_top_table;
11287 }
11288
11295 public function setHighscoreTopNum($a_top_num)
11296 {
11297 $this->_highscore_top_num = (int) $a_top_num;
11298 }
11299
11308 public function getHighscoreTopNum($a_retval = 10)
11309 {
11310 $retval = $a_retval;
11311 if ((int) $this->_highscore_top_num != 0) {
11312 $retval = $this->_highscore_top_num;
11313 }
11314
11315 return $retval;
11316 }
11317
11321 public function getHighscoreMode()
11322 {
11323 switch (true) {
11324 case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
11326 break;
11327
11328 case $this->getHighscoreTopTable():
11330 break;
11331
11332 case $this->getHighscoreOwnTable():
11333 default:
11335 break;
11336 }
11337 }
11338
11342 public function setHighscoreMode($mode)
11343 {
11344 switch ($mode) {
11346 $this->setHighscoreTopTable(1);
11347 $this->setHighscoreOwnTable(1);
11348 break;
11349
11351 $this->setHighscoreTopTable(1);
11352 $this->setHighscoreOwnTable(0);
11353 break;
11354
11356 default:
11357 $this->setHighscoreTopTable(0);
11358 $this->setHighscoreOwnTable(1);
11359 break;
11360 }
11361 }
11362 /* End GET/SET for highscore feature*/
11363
11364 public function setSpecificAnswerFeedback($specific_answer_feedback)
11365 {
11366 switch ($specific_answer_feedback) {
11367 case 1:
11368 $this->specific_answer_feedback = 1;
11369 break;
11370 default:
11371 $this->specific_answer_feedback = 0;
11372 break;
11373 }
11374 }
11375
11377 {
11378 switch ($this->specific_answer_feedback) {
11379 case 1:
11380 return 1;
11381 default:
11382 return 0;
11383 }
11384 }
11385
11392 {
11393 $this->obligationsEnabled = (bool) $obligationsEnabled;
11394 }
11395
11401 public function areObligationsEnabled()
11402 {
11403 return (bool) $this->obligationsEnabled;
11404 }
11405
11412 public static function isQuestionObligationPossible($questionId)
11413 {
11414 require_once('Modules/TestQuestionPool/classes/class.assQuestion.php');
11415
11416 $classConcreteQuestion = assQuestion::_getQuestionType($questionId);
11417
11418 assQuestion::_includeClass($classConcreteQuestion, 0);
11419
11420 // static binder is not at work yet (in PHP < 5.3)
11421 //$obligationPossible = $classConcreteQuestion::isObligationPossible();
11422 $obligationPossible = call_user_func(array($classConcreteQuestion, 'isObligationPossible'), $questionId);
11423
11424 return $obligationPossible;
11425 }
11426
11433 public static function isQuestionObligatory($question_id)
11434 {
11435 global $DIC;
11436 $ilDB = $DIC['ilDB'];
11437
11438 $rset = $ilDB->queryF('SELECT obligatory FROM tst_test_question WHERE question_fi = %s', array('integer'), array($question_id));
11439
11440 if ($row = $ilDB->fetchAssoc($rset)) {
11441 return (bool) $row['obligatory'];
11442 }
11443
11444 return false;
11445 }
11446
11459 public static function allObligationsAnswered($test_id, $active_id, $pass)
11460 {
11461 global $DIC;
11462 $ilDB = $DIC['ilDB'];
11463
11464 $rset = $ilDB->queryF(
11465 'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
11466 array('integer', 'integer'),
11467 array($active_id, $pass)
11468 );
11469
11470 if ($row = $ilDB->fetchAssoc($rset)) {
11471 return (bool) $row['obligations_answered'];
11472 }
11473
11475 }
11476
11485 public static function hasObligations($test_id)
11486 {
11487 global $DIC;
11488 $ilDB = $DIC['ilDB'];
11489
11490 $rset = $ilDB->queryF(
11491 'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
11492 array('integer'),
11493 array($test_id)
11494 );
11495
11496 $row = $ilDB->fetchAssoc($rset);
11497
11498 return (bool) $row['cnt'] > 0;
11499 }
11500
11501 public function setAutosave($autosave)
11502 {
11503 $this->autosave = $autosave;
11504 }
11505
11506 public function getAutosave()
11507 {
11508 return $this->autosave;
11509 }
11510
11512 {
11513 $this->autosave_ival = $autosave_ival;
11514 }
11515
11516 public function getAutosaveIval()
11517 {
11518 return $this->autosave_ival;
11519 }
11520
11526 public function isPassDeletionAllowed()
11527 {
11529 }
11530
11537 {
11538 $this->passDeletionAllowed = (bool) $passDeletionAllowed;
11539 }
11540
11541 #region Examview / PDF Examview
11546 {
11547 $this->show_examview_html = $show_examview_html;
11548 }
11549
11553 public function getShowExamviewHtml()
11554 {
11556 }
11557
11562 {
11563 $this->show_examview_pdf = $show_examview_pdf;
11564 }
11565
11569 public function getShowExamviewPdf()
11570 {
11572 }
11573
11578 {
11579 $this->enable_examview = $enable_examview;
11580 }
11581
11585 public function getEnableExamview()
11586 {
11588 }
11589
11590 #endregion
11591
11593 {
11594 $this->activation_starting_time = $starting_time;
11595 }
11596
11598 {
11599 $this->activation_ending_time = $ending_time;
11600 }
11601
11603 {
11604 return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : null;
11605 }
11606
11607 public function getActivationEndingTime()
11608 {
11609 return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : null;
11610 }
11611
11619 {
11620 global $DIC;
11621 $ilDB = $DIC['ilDB'];
11622
11623 $times = array();
11624 $result = $ilDB->queryF(
11625 "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",
11626 array('integer'),
11627 array($this->getTestId())
11628 );
11629 while ($row = $ilDB->fetchAssoc($result)) {
11630 $times[$row['active_fi']] = $row['started'];
11631 }
11632 return $times;
11633 }
11634
11636 {
11637 global $DIC;
11638 $ilDB = $DIC['ilDB'];
11639
11640 $times = array();
11641 $result = $ilDB->queryF(
11642 "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",
11643 array('integer'),
11644 array($this->getTestId())
11645 );
11646 while ($row = $ilDB->fetchAssoc($result)) {
11647 $times[$row['active_fi']] = $row['additionaltime'];
11648 }
11649 return $times;
11650 }
11651
11652 public function getExtraTime($active_id)
11653 {
11654 global $DIC;
11655 $ilDB = $DIC['ilDB'];
11656
11657 $result = $ilDB->queryF(
11658 "SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
11659 array('integer'),
11660 array($active_id)
11661 );
11662 if ($result->numRows() > 0) {
11663 $row = $ilDB->fetchAssoc($result);
11664 return $row['additionaltime'];
11665 }
11666 return 0;
11667 }
11668
11669 public function addExtraTime($active_id, $minutes)
11670 {
11671 global $DIC; /* @var ILIAS\DI\Container $DIC */
11672
11673 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
11674 $participantData = new ilTestParticipantData($DIC->database(), $DIC->language());
11675
11676 $participantData->setParticipantAccessFilter(
11678 );
11679
11680 if ($active_id) {
11681 $participantData->setActiveIdsFilter(array($active_id));
11682 }
11683
11684 $participantData->load($this->getTestId());
11685
11686 foreach ($participantData->getActiveIds() as $active_id) {
11687 $result = $DIC->database()->queryF(
11688 "SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
11689 array('integer'),
11690 array($active_id)
11691 );
11692
11693 if ($result->numRows() > 0) {
11694 $DIC->database()->manipulateF(
11695 "DELETE FROM tst_addtime WHERE active_fi = %s",
11696 array('integer'),
11697 array($active_id)
11698 );
11699 }
11700
11701 $DIC->database()->manipulateF(
11702 "UPDATE tst_active SET tries = %s, submitted = %s, submittimestamp = %s WHERE active_id = %s",
11703 array('integer','integer','timestamp','integer'),
11704 array(0, 0, null, $active_id)
11705 );
11706
11707 $DIC->database()->manipulateF(
11708 "INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
11709 array('integer','integer','integer'),
11710 array($active_id, $minutes, time())
11711 );
11712
11713 require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
11715 $this->logAction(sprintf($this->lng->txtlng("assessment", "log_added_extratime", ilObjAssessmentFolder::_getLogLanguage()), $minutes, $active_id));
11716 }
11717 }
11718 }
11719
11726 {
11727 $this->enable_archiving = $enable_archiving;
11728 return $this;
11729 }
11730
11734 public function getEnableArchiving()
11735 {
11737 }
11738
11739 public function getMaxPassOfTest()
11740 {
11744 global $DIC;
11745 $ilDB = $DIC['ilDB'];
11746
11747 $query = '
11748 SELECT MAX(tst_pass_result.pass) + 1 max_res
11749 FROM tst_pass_result
11750 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
11751 WHERE test_fi = ' . $ilDB->quote($this->getTestId(), 'integer') . '
11752 ';
11753 $res = $ilDB->query($query);
11754 $data = $ilDB->fetchAssoc($res);
11755 return (int) $data['max_res'];
11756 }
11757
11763 public static function lookupExamId($active_id, $pass)
11764 {
11765 global $DIC;
11766 $ilDB = $DIC['ilDB'];
11767
11768 $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
11769 $exam_id_result = $ilDB->queryF($exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ));
11770 if ($ilDB->numRows($exam_id_result) == 1) {
11771 $exam_id_row = $ilDB->fetchAssoc($exam_id_result);
11772
11773 if ($exam_id_row['exam_id'] != null) {
11774 return $exam_id_row['exam_id'];
11775 }
11776 }
11777
11778 return null;
11779 }
11780
11787 public static function buildExamId($active_id, $pass, $test_obj_id = null)
11788 {
11789 global $DIC;
11790 $ilSetting = $DIC['ilSetting'];
11791
11792 $inst_id = $ilSetting->get('inst_id', null);
11793
11794 if ($test_obj_id === null) {
11795 $obj_id = self::_getObjectIDFromActiveID($active_id);
11796 } else {
11797 $obj_id = $test_obj_id;
11798 }
11799
11800 $examId = 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
11801
11802 return $examId;
11803 }
11804
11806 {
11807 $this->show_exam_id_in_test_pass_enabled = $show_exam_id_in_test_pass_enabled;
11808 }
11809
11811 {
11813 }
11814
11819 {
11820 $this->show_exam_id_in_test_results_enabled = $show_exam_id_in_test_results_enabled;
11821 }
11822
11827 {
11829 }
11830
11835 {
11836 $this->sign_submission = $sign_submission;
11837 }
11838
11842 public function getSignSubmission()
11843 {
11845 }
11846
11850 public function setCharSelectorAvailability($availability)
11851 {
11852 $this->char_selector_availability = (int) $availability;
11853 }
11854
11859 {
11861 }
11862
11866 public function setCharSelectorDefinition($definition = '')
11867 {
11868 $this->char_selector_definition = $definition;
11869 }
11870
11875 {
11877 }
11878
11879
11886 {
11887 $this->questionSetType = $questionSetType;
11888 }
11889
11895 public function getQuestionSetType()
11896 {
11898 }
11899
11907 public static function lookupQuestionSetType($objId)
11908 {
11909 global $DIC;
11910 $ilDB = $DIC['ilDB'];
11911
11912 $query = "SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
11913
11914 $res = $ilDB->queryF($query, array('integer'), array($objId));
11915
11916 $questionSetType = null;
11917
11918 while ($row = $ilDB->fetchAssoc($res)) {
11919 $questionSetType = $row['question_set_type'];
11920 }
11921
11922 return $questionSetType;
11923 }
11924
11930 public function isFixedTest()
11931 {
11933 }
11934
11940 public function isRandomTest()
11941 {
11943 }
11944
11950 public function isDynamicTest()
11951 {
11953 }
11954
11962 public static function _lookupRandomTest($a_obj_id)
11963 {
11965 }
11966
11968 {
11969 switch ($questionSetType) {
11971 return $lng->txt('tst_question_set_type_fixed');
11972
11974 return $lng->txt('tst_question_set_type_random');
11975
11977 return $lng->txt('tst_question_set_type_dynamic');
11978 }
11979
11980 throw new ilTestException('invalid question set type value given: ' . $questionSetType);
11981 }
11982
11983 public function participantDataExist()
11984 {
11985 if ($this->participantDataExist === null) {
11986 $this->participantDataExist = (bool) $this->evalTotalPersons();
11987 }
11988
11990 }
11991
11992 public function recalculateScores($preserve_manscoring = false)
11993 {
11994 require_once 'class.ilTestScoring.php';
11995 $scoring = new ilTestScoring($this);
11996 $scoring->setPreserveManualScores($preserve_manscoring);
11997 $scoring->recalculateSolutions();
11998 }
11999
12000 public static function getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
12001 {
12002 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
12003
12004 $questionChangeListeners = array(
12006 );
12007
12008 return $questionChangeListeners;
12009 }
12010
12011 public static function getTestObjIdsWithActiveForUserId($userId)
12012 {
12013 global $DIC;
12014 $ilDB = $DIC['ilDB'];
12015
12016 $query = "
12017 SELECT obj_fi
12018 FROM tst_active
12019 INNER JOIN tst_tests
12020 ON test_id = test_fi
12021 WHERE user_fi = %s
12022 ";
12023
12024 $res = $ilDB->queryF($query, array('integer'), array($userId));
12025
12026 $objIds = array();
12027
12028 while ($row = $ilDB->fetchAssoc($res)) {
12029 $objIds[] = (int) $row['obj_fi'];
12030 }
12031
12032 return $objIds;
12033 }
12034
12036 {
12037 $this->skillServiceEnabled = $skillServiceEnabled;
12038 }
12039
12040 public function isSkillServiceEnabled()
12041 {
12043 }
12044
12046 {
12047 $this->resultFilterTaxIds = $resultFilterTaxIds;
12048 }
12049
12050 public function getResultFilterTaxIds()
12051 {
12053 }
12054
12056 {
12057 if (!$this->isSkillServiceEnabled()) {
12058 return false;
12059 }
12060
12061 if (!self::isSkillManagementGloballyActivated()) {
12062 return false;
12063 }
12064
12065 return true;
12066 }
12067
12069
12070 public static function isSkillManagementGloballyActivated()
12071 {
12072 if (self::$isSkillManagementGloballyActivated === null) {
12073 $skmgSet = new ilSkillManagementSettings();
12074
12075 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
12076 }
12077
12079 }
12080
12082 {
12083 $this->showGradingStatusEnabled = $showGradingStatusEnabled;
12084 }
12085
12087 {
12089 }
12090
12092 {
12093 $this->showGradingMarkEnabled = $showGradingMarkEnabled;
12094 }
12095
12096
12098 {
12100 }
12101
12103 {
12104 $this->followupQuestionAnswerFixationEnabled = $followupQuestionAnswerFixationEnabled;
12105 }
12106
12108 {
12110 }
12111
12113 {
12114 $this->instantFeedbackAnswerFixationEnabled = $instantFeedbackAnswerFixationEnabled;
12115 }
12116
12118 {
12120 }
12121
12126 {
12128 }
12129
12134 {
12135 $this->forceInstantFeedbackEnabled = $forceInstantFeedbackEnabled;
12136 }
12137
12138 public static function ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run = false)
12139 {
12140 global $DIC;
12141 $ilDB = $DIC['ilDB'];
12142 $lng = $DIC['lng'];
12143 $refinery = $DIC['refinery'];
12144 $ilPluginAdmin = $DIC['ilPluginAdmin'];
12145
12146 /* @var ilObjTest $testOBJ */
12147
12148 $testOBJ = ilObjectFactory::getInstanceByRefId($testObjId, false);
12149
12150 $activeId = $testOBJ->getActiveIdOfUser($userId);
12151
12152 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12153 $testSessionFactory = new ilTestSessionFactory($testOBJ);
12154
12155 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12156 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $refinery, $ilPluginAdmin, $testOBJ);
12157
12158 $testSession = $testSessionFactory->getSession($activeId);
12159 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12160 $testSequence->loadFromDb();
12161
12162 // begin-patch lok changed smeyer
12163 if ($a_force_new_run) {
12164 if ($testSequence->hasSequence()) {
12165 $testSession->increasePass();
12166 }
12167 $testSession->setLastSequence(0);
12168 $testSession->saveToDb();
12169 }
12170 // end-patch lok
12171 }
12172
12173 public static function isParticipantsLastPassActive($testRefId, $userId)
12174 {
12175 global $DIC;
12176 $ilDB = $DIC['ilDB'];
12177 $lng = $DIC['lng'];
12178 $refinery = $DIC['refinery'];
12179 $ilPluginAdmin = $DIC['ilPluginAdmin'];
12180
12181 /* @var ilObjTest $testOBJ */
12182
12183 $testOBJ = ilObjectFactory::getInstanceByRefId($testRefId, false);
12184
12185
12186 $activeId = $testOBJ->getActiveIdOfUser($userId);
12187
12188 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12189 $testSessionFactory = new ilTestSessionFactory($testOBJ);
12190 // Added temporarily bugfix smeyer
12191 $testSessionFactory->reset();
12192
12193 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12194 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $refinery, $ilPluginAdmin, $testOBJ);
12195
12196 $testSession = $testSessionFactory->getSession($activeId);
12197 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12198 $testSequence->loadFromDb();
12199
12200 return $testSequence->hasSequence();
12201 }
12202
12206 public function isTestFinalBroken()
12207 {
12209 }
12210
12215 {
12216 $this->testFinalBroken = $testFinalBroken;
12217 }
12218
12219 public function adjustTestSequence()
12220 {
12224 global $DIC;
12225 $ilDB = $DIC['ilDB'];
12226
12227 $query = "
12228 SELECT COUNT(test_question_id) cnt
12229 FROM tst_test_question
12230 WHERE test_fi = %s
12231 ORDER BY sequence
12232 ";
12233
12234 $questRes = $ilDB->queryF($query, array('integer'), array($this->getTestId()));
12235
12236 $row = $ilDB->fetchAssoc($questRes);
12237 $questCount = $row['cnt'];
12238
12239 if ($this->getShuffleQuestions()) {
12240 $query = "
12241 SELECT tseq.*
12242 FROM tst_active tac
12243 INNER JOIN tst_sequence tseq
12244 ON tseq.active_fi = tac.active_id
12245 WHERE tac.test_fi = %s
12246 ";
12247
12248 $partRes = $ilDB->queryF(
12249 $query,
12250 array('integer'),
12251 array($this->getTestId())
12252 );
12253
12254 while ($row = $ilDB->fetchAssoc($partRes)) {
12255 $sequence = @unserialize($row['sequence']);
12256
12257 if (!$sequence) {
12258 $sequence = array();
12259 }
12260
12261 $sequence = array_filter($sequence, function ($value) use ($questCount) {
12262 return $value <= $questCount;
12263 });
12264
12265 $num_seq = count($sequence);
12266 if ($questCount > $num_seq) {
12267 $diff = $questCount - $num_seq;
12268 for ($i = 1; $i <= $diff; $i++) {
12269 $sequence[$num_seq + $i - 1] = $num_seq + $i;
12270 }
12271 }
12272
12273 $new_sequence = serialize($sequence);
12274
12275 $ilDB->update('tst_sequence', array(
12276 'sequence' => array('clob', $new_sequence)
12277 ), array(
12278 'active_fi' => array('integer', $row['active_fi']),
12279 'pass' => array('integer', $row['pass'])
12280 ));
12281 }
12282 } else {
12283 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : array());
12284
12285 $query = "
12286 SELECT tseq.*
12287 FROM tst_active tac
12288 INNER JOIN tst_sequence tseq
12289 ON tseq.active_fi = tac.active_id
12290 WHERE tac.test_fi = %s
12291 ";
12292
12293 $part_rest = $ilDB->queryF(
12294 $query,
12295 array('integer'),
12296 array($this->getTestId())
12297 );
12298
12299 while ($row = $ilDB->fetchAssoc($part_rest)) {
12300 $ilDB->update('tst_sequence', array(
12301 'sequence' => array('clob', $new_sequence)
12302 ), array(
12303 'active_fi' => array('integer', $row['active_fi']),
12304 'pass' => array('integer', $row['pass'])
12305 ));
12306 }
12307 }
12308 }
12309
12311 {
12312 return ilHtmlPurifierFactory::_getInstanceByType('qpl_usersolution');
12313 }
12314
12320 public static function getDataWebPath(string $relative_path = '') : string
12321 {
12322 $webdir = implode('/', [
12323 ILIAS_HTTP_PATH,
12325 CLIENT_ID,
12326 $relative_path
12327 ]);
12328 $parts = array_filter(explode('/', $webdir), function ($p) {
12329 return trim($p) != '' && trim($p) != '.';
12330 });
12331 return array_shift($parts) . '//' . implode('/', $parts) . '/';
12332 }
12333}
$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
$_SESSION["AccountId"]
A class defining mark schemas for assessment test objects.
An exception for terminatinating execution or to throw for unit testing.
Builds data types.
Definition: Factory.php:20
const IL_COMP_MODULE
const IL_CAL_UNIX
const IL_CAL_DATETIME
return true
Flag indicating whether or not HTTP headers will be sent when outputting captcha image/audio.
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 _getInstance($a_copy_id)
Get instance of copy wizard options.
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.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilFileDataMail.
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)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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.
static getDataWebPath(string $relative_path='')
This is originally a fix for https://mantis.ilias.de/view.php?id=35707; in general,...
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.
exportFileItems($target_dir, &$expLog)
export files of file itmes
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.
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...
addQTIMaterial(&$a_xml_writer, $a_material='')
Creates a QTI material tag from a plain text or xhtml text.
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}
& 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.
$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)
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 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.
$c
Definition: cli.php:37
const CLIENT_ID
Definition: constants.php:39
const ILIAS_WEB_DIR
Definition: constants.php:43
const CLIENT_WEB_DIR
Definition: constants.php:45
const IL_INST_ID
Definition: constants.php:38
const ANONYMOUS_USER_ID
Definition: constants.php:25
$login
Definition: cron.php:13
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
$txt
Definition: error.php:13
global $DIC
Definition: goto.php:24
global $ilBench
Definition: ilias.php:21
$mobs
Definition: imgupload.php:54
$ilUser
Definition: imgupload.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()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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
$objId
Definition: xapitoken.php:39
$rows
Definition: xhr_table.php:10