ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilObjTest.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Services/Object/classes/class.ilObject.php';
5require_once 'Modules/Test/classes/inc.AssessmentConstants.php';
6require_once 'Modules/Test/interfaces/interface.ilMarkSchemaAware.php';
7require_once 'Modules/Test/interfaces/interface.ilEctsGradesEnabled.php';
8require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionType.php';
9
21{
23
24 #region Properties
25
29 const QUESTION_SET_TYPE_FIXED = 'FIXED_QUEST_SET';
30
34 const QUESTION_SET_TYPE_RANDOM = 'RANDOM_QUEST_SET';
35
39 const QUESTION_SET_TYPE_DYNAMIC = 'DYNAMIC_QUEST_SET';
40
45
50
55
62
66 private $skillServiceEnabled = false;
67
71 private $resultFilterTaxIds = array();
72
80 protected $_kiosk;
81
87 public $test_id;
88
95
102 public $author;
103
109 public $metadata;
110
117
122
129 protected $introduction;
130
137
146
157
166
173
183
190
198
206
216
223
230
237
242
248 protected $starting_time;
249
254
260 protected $ending_time;
261
266 protected $ects_output = false;
267
272 protected $ects_fx = null;
273
278 protected $ects_grades = array();
279
280
288
295
302
310
317
324
331
336
342 protected $password;
343
348
354 protected $allowedUsers;
355
362
369
376
383
390
397
404
411
418
425
432
438 private $_showinfo;
439
445 private $_forcejs = true;
446
453
455
456 protected $mailnottype;
457
459
460 protected $poolUsage;
461
463
464 protected $oldOnlineStatus = null;
465
470
477
483 private $obligationsEnabled = null;
484
486
488
490
491 protected $autosave;
492
493 protected $autosave_ival;
494
501 private $passDeletionAllowed = null;
502
508 private $participantDataExist = null;
509
512
515
518
521
525 private $redirection_mode = 0;
526
530 private $redirection_url = null;
531
534
537
540
543
546
551
556
561
566
571
576
581
585 protected $pass_waiting = "00:000:00:00:00";
586 #endregion
587
596 public function __construct($a_id = 0, $a_call_by_reference = true)
597 {
598 global $DIC;
599 $ilUser = $DIC['ilUser'];
600 $lng = $DIC['lng'];
601 $this->type = "tst";
602
603 $lng->loadLanguageModule("assessment");
604 // Defaults:
605 include_once "./Modules/Test/classes/class.assMarkSchema.php";
606 $this->mark_schema = new ASS_MarkSchema();
607 $this->mark_schema->createSimpleSchema(
608 $lng->txt("failed_short"),
609 $lng->txt("failed_official"),
610 0,
611 0,
612 $lng->txt("passed_short"),
613 $lng->txt("passed_official"),
614 50,
615 1
616 );
617
618 $this->test_id = -1;
619 $this->author = $ilUser->fullname;
620 $this->introductionEnabled = false;
621 $this->introduction = "";
622 $this->questions = array();
623 $this->sequence_settings = TEST_FIXED_SEQUENCE;
624 $this->score_reporting = self::SCORE_REPORTING_FINISHED;
625 $this->instant_verification = 0;
626 $this->answer_feedback_points = 0;
627 $this->reporting_date = "";
628 $this->nr_of_tries = 0;
629 $this->_kiosk = 0;
630 $this->use_previous_answers = 1;
631 $this->title_output = 0;
632 $this->starting_time = "";
633 $this->ending_time = "";
634 $this->processing_time = "";
635 $this->enable_processing_time = "0";
636 $this->reset_processing_time = 0;
637 $this->ects_output = false;
638 $this->ects_fx = null;
639 $this->shuffle_questions = false;
640 $this->mailnottype = 0;
641 $this->exportsettings = 0;
642 $this->show_summary = 8;
643 $this->count_system = COUNT_PARTIAL_SOLUTIONS;
644 $this->mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED;
645 $this->score_cutting = SCORE_CUT_QUESTION;
646 $this->pass_scoring = SCORE_LAST_PASS;
647 $this->answer_feedback = 0;
648 $this->password = "";
649 $this->certificate_visibility = 0;
650 $this->allowedUsers = "";
651 $this->_showfinalstatement = false;
652 $this->_finalstatement = "";
653 $this->_showinfo = true;
654 $this->_forcejs = true;
655 $this->_customStyle = "";
656 $this->allowedUsersTimeGap = "";
657 $this->anonymity = 0;
658 $this->show_cancel = 0;
659 $this->show_marker = 0;
660 $this->fixed_participants = 0;
661 $this->setShowPassDetails(true);
662 $this->setShowSolutionDetails(true);
663 $this->setShowSolutionAnswersOnly(false);
664 $this->setShowSolutionSignature(false);
665 $this->testSession = false;
666 $this->testSequence = false;
667 $this->mailnotification = 0;
668 $this->poolUsage = 1;
669
670 $this->ects_grades = array(
671 'A' => 90,
672 'B' => 65,
673 'C' => 35,
674 'D' => 10,
675 'E' => 0
676 );
677
678 $this->autosave = false;
679 $this->autosave_ival = 30000;
680
681 $this->enable_examview = false;
682 $this->show_examview_html = false;
683 $this->show_examview_pdf = false;
684 $this->enable_archiving = false;
685
686 $this->express_mode = false;
687 $this->template_id = '';
688 $this->redirection_mode = 0;
689 $this->redirection_url = null;
690 $this->show_exam_id_in_test_pass_enabled = false;
691 $this->show_exam_id_in_test_results_enabled = false;
692 $this->sign_submission = false;
693 $this->char_selector_availability = 0;
694 $this->char_selector_definition = null;
695
696 $this->showGradingStatusEnabled = true;
697 $this->showGradingMarkEnabled = true;
698
699 $this->followupQuestionAnswerFixationEnabled = false;
700 $this->instantFeedbackAnswerFixationEnabled = false;
701
702 $this->testFinalBroken = false;
703
704 $this->tmpCopyWizardCopyId = null;
705
706 parent::__construct($a_id, $a_call_by_reference);
707 }
708
715 {
716 require_once 'Services/Utilities/classes/class.ilUtil.php';
717 return ilUtil::getASCIIFilename($this->getTitle());
718 }
719
723 public function getTmpCopyWizardCopyId()
724 {
726 }
727
732 {
733 $this->tmpCopyWizardCopyId = $tmpCopyWizardCopyId;
734 }
735
739 public function create()
740 {
741 $this->setOfflineStatus(true);
742 parent::create();
743
744 // meta data will be created by
745 // import parser
746 if (!$a_upload) {
747 $this->createMetaData();
748 }
749 }
750
757 public function update()
758 {
759 if (!parent::update()) {
760 return false;
761 }
762
763 // put here object specific stuff
764 $this->updateMetaData();
765 return true;
766 }
767
773 public function read()
774 {
775 parent::read();
776 $this->loadFromDb();
777 }
778
779
786 public function delete()
787 {
788 // always call parent delete function first!!
789 if (!parent::delete()) {
790 return false;
791 }
792
793 // delet meta data
794 $this->deleteMetaData();
795
796 //put here your module specific stuff
797 $this->deleteTest();
798
799 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentImportFails.php';
800 $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($this->getId());
801 $qsaImportFails->deleteRegisteredImportFails();
802 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdImportFails.php';
803 $sltImportFails = new ilTestSkillLevelThresholdImportFails($this->getId());
804 $sltImportFails->deleteRegisteredImportFails();
805
806 return true;
807 }
808
814 public function deleteTest()
815 {
816 global $DIC;
817 $tree = $DIC['tree'];
818 $ilDB = $DIC['ilDB'];
819 $ilPluginAdmin = $DIC['ilPluginAdmin'];
820 $lng = $DIC['lng'];
821
822 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
823 $participantData = new ilTestParticipantData($ilDB, $lng);
824 $participantData->load($this->getTestId());
825 $this->removeTestResults($participantData);
826
827 $affectedRows = $ilDB->manipulateF(
828 "DELETE FROM tst_mark WHERE test_fi = %s",
829 array('integer'),
830 array($this->getTestId())
831 );
832
833 $affectedRows = $ilDB->manipulateF(
834 "DELETE FROM tst_tests WHERE test_id = %s",
835 array('integer'),
836 array($this->getTestId())
837 );
838
839 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
840 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
841 $testQuestionSetConfigFactory->getQuestionSetConfig()->removeQuestionSetRelatedData();
842
843 // delete export files
844 include_once "./Services/Utilities/classes/class.ilUtil.php";
845 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
846 $directory = $tst_data_dir . "/tst_" . $this->getId();
847 if (is_dir($directory)) {
848 include_once "./Services/Utilities/classes/class.ilUtil.php";
849 ilUtil::delDir($directory);
850 }
851 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
852 $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
853 // remaining usages are not in text anymore -> delete them
854 // and media objects (note: delete method of ilObjMediaObject
855 // checks whether object is used in another context; if yes,
856 // the object is not deleted!)
857 foreach ($mobs as $mob) {
858 ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
859 if (ilObjMediaObject::_exists($mob)) {
860 $mob_obj = new ilObjMediaObject($mob);
861 $mob_obj->delete();
862 }
863 }
864 }
865
871 public function createExportDirectory()
872 {
873 include_once "./Services/Utilities/classes/class.ilUtil.php";
874 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
875 ilUtil::makeDir($tst_data_dir);
876 if (!is_writable($tst_data_dir)) {
877 $this->ilias->raiseError("Test Data Directory (" . $tst_data_dir
878 . ") not writeable.", $this->ilias->error_obj->MESSAGE);
879 }
880
881 // create learning module directory (data_dir/lm_data/lm_<id>)
882 $tst_dir = $tst_data_dir . "/tst_" . $this->getId();
883 ilUtil::makeDir($tst_dir);
884 if (!@is_dir($tst_dir)) {
885 $this->ilias->raiseError("Creation of Test Directory failed.", $this->ilias->error_obj->MESSAGE);
886 }
887 // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
888 $export_dir = $tst_dir . "/export";
889 ilUtil::makeDir($export_dir);
890 if (!@is_dir($export_dir)) {
891 $this->ilias->raiseError("Creation of Export Directory failed.", $this->ilias->error_obj->MESSAGE);
892 }
893 }
894
900 public function getExportDirectory()
901 {
902 include_once "./Services/Utilities/classes/class.ilUtil.php";
903 $export_dir = ilUtil::getDataDir() . "/tst_data" . "/tst_" . $this->getId() . "/export";
904 return $export_dir;
905 }
906
913 public function getExportFiles($dir)
914 {
915 // quit if import dir not available
916 if (!@is_dir($dir) || !is_writeable($dir)) {
917 return array();
918 }
919
920 $files = array();
921 foreach (new DirectoryIterator($dir) as $file) {
925 if ($file->isDir()) {
926 continue;
927 }
928
929 $files[] = $file->getBasename();
930 }
931
932 sort($files);
933
934 return $files;
935 }
936
940 public static function _setImportDirectory($a_import_dir = null)
941 {
942 if (strlen($a_import_dir)) {
943 $_SESSION["tst_import_dir"] = $a_import_dir;
944 } else {
945 unset($_SESSION["tst_import_dir"]);
946 }
947 }
948
955 public static function _getImportDirectory()
956 {
957 if (strlen($_SESSION["tst_import_dir"])) {
958 return $_SESSION["tst_import_dir"];
959 }
960 return null;
961 }
962
963 public function getImportDirectory()
964 {
966 }
967
973 public static function _createImportDirectory()
974 {
975 global $DIC;
976 $ilias = $DIC['ilias'];
977 include_once "./Services/Utilities/classes/class.ilUtil.php";
978 $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
979 ilUtil::makeDir($tst_data_dir);
980
981 if (!is_writable($tst_data_dir)) {
982 $ilias->raiseError("Test Data Directory (" . $tst_data_dir
983 . ") not writeable.", $ilias->error_obj->FATAL);
984 }
985
986 // create test directory (data_dir/tst_data/tst_import)
987 $tst_dir = $tst_data_dir . "/tst_import";
988 ilUtil::makeDir($tst_dir);
989 if (!@is_dir($tst_dir)) {
990 $ilias->raiseError("Creation of test import directory failed.", $ilias->error_obj->FATAL);
991 }
992
993 // assert that this is empty and does not contain old data
994 ilUtil::delDir($tst_dir, true);
995
996 return $tst_dir;
997 }
998
1006 {
1007 global $DIC;
1008 $ilDB = $DIC['ilDB'];
1009
1010 $result = $ilDB->queryF(
1011 "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",
1012 array('integer'),
1013 array($this->getTestId())
1014 );
1015 $hasSC = false;
1016 while ($row = $ilDB->fetchAssoc($result)) {
1017 if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1018 $hasSC = true;
1019 }
1020 }
1021 return $hasSC;
1022 }
1023
1030 public function isSingleChoiceTest()
1031 {
1032 global $DIC;
1033 $ilDB = $DIC['ilDB'];
1034
1035 $result = $ilDB->queryF(
1036 "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",
1037 array('integer'),
1038 array($this->getTestId())
1039 );
1040 if ($result->numRows() == 1) {
1041 $row = $ilDB->fetchAssoc($result);
1042 if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1043 return true;
1044 } else {
1045 return false;
1046 }
1047 }
1048 return false;
1049 }
1050
1058 {
1059 global $DIC;
1060 $ilDB = $DIC['ilDB'];
1061
1062 if (!$this->hasSingleChoiceQuestions()) {
1063 return false;
1064 }
1065
1066 $result = $ilDB->queryF(
1067 "
1068 SELECT DISTINCT(qpl_qst_sc.shuffle) foundshuffles
1069 FROM qpl_questions,
1070 qpl_qst_sc,
1071 tst_test_result,
1072 qpl_qst_type,
1073 tst_active
1074 WHERE tst_test_result.question_fi = qpl_questions.question_id
1075 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
1076 AND tst_test_result.active_fi = tst_active.active_id
1077 AND qpl_questions.question_id = qpl_qst_sc.question_fi
1078 AND tst_active.test_fi = %s
1079 AND qpl_qst_type.type_tag = %s
1080 ",
1081 array('integer', 'text'),
1082 array($this->getTestId(), 'assSingleChoice')
1083 );
1084 if ($result->numRows() == 1) {
1085 $row = $ilDB->fetchAssoc($result);
1086 return ($row['foundshuffles'] == 0);
1087 }
1088 return false;
1089 }
1090
1097 final public function isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
1098 {
1099 if (!count($this->mark_schema->mark_steps)) {
1100 return false;
1101 }
1102
1103 if (!$testQuestionSetConfig->isQuestionSetConfigured()) {
1104 return false;
1105 }
1106
1107 return true;
1108 }
1109
1116 public function _isComplete($obj_id)
1117 {
1118 global $DIC;
1119 $tree = $DIC['tree'];
1120 $ilDB = $DIC['ilDB'];
1121 $ilPluginAdmin = $DIC['ilPluginAdmin'];
1122
1123 $test = new ilObjTest($obj_id, false);
1124 $test->loadFromDb();
1125
1126 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1127 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
1128
1129 return $test->isComplete($testQuestionSetConfigFactory->getQuestionSetConfig());
1130 }
1131
1135 public function saveECTSStatus()
1136 {
1140 global $DIC;
1141 $ilDB = $DIC['ilDB'];
1142
1143 if ($this->getTestId() > 0) {
1144 $this->setECTSFX(preg_replace('/,/', '.', $this->getECTSFX()));
1145 if (!preg_match('/\d+/', $this->getECTSFX())) {
1146 $this->setECTSFX(null);
1147 }
1148
1149 $grades = $this->getECTSGrades();
1150 $ilDB->manipulateF(
1151 "UPDATE tst_tests
1152 SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s
1153 WHERE test_id = %s",
1154 array('text', 'float', 'float', 'float', 'float', 'float', 'float', 'integer'),
1155 array(
1156 (int) $this->getECTSOutput(),
1157 $grades['A'], $grades['B'], $grades['C'], $grades['D'], $grades['E'],
1158 $this->getECTSFX(),
1159 $this->getTestId()
1160 )
1161 );
1162 }
1163 }
1164
1169 public function saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
1170 {
1171 global $DIC;
1172 $ilDB = $DIC['ilDB'];
1173
1174 $complete = 0;
1175 if ($this->isComplete($testQuestionSetConfig)) {
1176 $complete = 1;
1177 }
1178 if ($this->getTestId() > 0) {
1179 $ilDB->manipulateF(
1180 "UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1181 array('text', 'integer'),
1182 array($complete, $this->test_id)
1183 );
1184 }
1185 }
1186
1192 public function getAllRTEContent()
1193 {
1194 $result = array();
1195 array_push($result, $this->getIntroduction());
1196 array_push($result, $this->getFinalStatement());
1197 return $result;
1198 }
1199
1205 public function cleanupMediaobjectUsage()
1206 {
1207 include_once("./Services/RTE/classes/class.ilRTE.php");
1208 $completecontent = "";
1209 foreach ($this->getAllRTEContent() as $content) {
1210 $completecontent .= $content;
1211 }
1213 $completecontent,
1214 $this->getType() . ":html",
1215 $this->getId()
1216 );
1217 }
1218
1224 public function saveToDb($properties_only = false)
1225 {
1226 global $DIC;
1227 $tree = $DIC['tree'];
1228 $ilDB = $DIC['ilDB'];
1229 $ilPluginAdmin = $DIC['ilPluginAdmin'];
1230
1231 // moved online_status to ilObjectActivation (see below)
1232
1233 // cleanup RTE images
1234 $this->cleanupMediaobjectUsage();
1235
1236 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1237 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
1238 $testQuestionSetConfig = $testQuestionSetConfigFactory->getQuestionSetConfig();
1239
1240 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1241 if ($this->test_id == -1) {
1242 // Create new dataset
1243 $next_id = $ilDB->nextId('tst_tests');
1244
1245 $ilDB->insert('tst_tests', array(
1246 'test_id' => array('integer', $next_id),
1247 'obj_fi' => array('integer', $this->getId()),
1248 'author' => array('text', $this->getAuthor()),
1249 'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1250 'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1251 'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1252 'showinfo' => array('integer', $this->getShowInfo()),
1253 'forcejs' => array('integer', $this->getForceJS()),
1254 'customstyle' => array('text', $this->getCustomStyle()),
1255 'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1256 'sequence_settings' => array('integer', $this->getSequenceSettings()),
1257 'score_reporting' => array('integer', $this->getScoreReporting()),
1258 'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1259 'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1260 'answer_feedback' => array('text', $this->getAnswerFeedback()),
1261 'anonymity' => array('text', $this->getAnonymity()),
1262 'show_cancel' => array('text', $this->getShowCancel()),
1263 'show_marker' => array('integer', $this->getShowMarker()),
1264 'fixed_participants' => array('text', $this->getFixedParticipants()),
1265 'nr_of_tries' => array('integer', $this->getNrOfTries()),
1266 'kiosk' => array('integer', $this->getKiosk()),
1267 'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1268 'title_output' => array('text', $this->getTitleOutput()),
1269 'processing_time' => array('text', $this->getProcessingTime()),
1270 'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1271 'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1272 'reporting_date' => array('text', $this->getReportingDate()),
1273 'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1274 'starting_time' => array('integer', $this->getStartingTime()),
1275 'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1276 'ending_time' => array('integer', $this->getEndingTime()),
1277 'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1278 'ects_output' => array('text', $this->getECTSOutput()),
1279 'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1280 'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1281 'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1282 'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1283 'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1284 'ects_fx' => array('float', $this->getECTSFX()),
1285 'count_system' => array('text', $this->getCountSystem()),
1286 'mc_scoring' => array('text', $this->getMCScoring()),
1287 'score_cutting' => array('text', $this->getScoreCutting()),
1288 'pass_scoring' => array('text', $this->getPassScoring()),
1289 'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1290 'results_presentation' => array('integer', $this->getResultsPresentation()),
1291 'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1292 'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1293 'password' => array('text', $this->getPassword()),
1294 'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1295 'allowedusers' => array('integer', $this->getAllowedUsers()),
1296 'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1297 'mailnottype' => array('integer', $this->getMailNotificationType()),
1298 'exportsettings' => array('integer', $this->getExportSettings()),
1299 'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1300 'mailnotification' => array('integer', $this->getMailNotification()),
1301 'created' => array('integer', time()),
1302 'tstamp' => array('integer', time()),
1303 'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1304 'template_id' => array('integer', $this->getTemplate()),
1305 'pool_usage' => array('integer', $this->getPoolUsage()),
1306 'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1307 'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1308 'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1309 'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1310 'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1311 'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1312 'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1313 'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1314 'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1315 'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1316 'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1317 'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1318 'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1319 'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1320 'autosave' => array('integer', (int) $this->getAutosave()),
1321 'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1322 'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1323 'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1324 'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1325 'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1326 'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1327 'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1328 'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1329 'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1330 'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1331 'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1332 'question_set_type' => array('text', $this->getQuestionSetType()),
1333 'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1334 'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1335 'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1336 'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1337 'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1338 'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1339 'follow_qst_answer_fixation' => array('integer', (int) $this->isFollowupQuestionAnswerFixationEnabled()),
1340 'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1341 'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1342 'broken' => array('integer', (int) $this->isTestFinalBroken()),
1343 'pass_waiting' => array('text', (string) $this->getPassWaiting())
1344 ));
1345
1346 $this->test_id = $next_id;
1347
1349 $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1350 }
1351 } else {
1352 // Modify existing dataset
1353 $oldrow = array();
1355 $result = $ilDB->queryF(
1356 "SELECT * FROM tst_tests WHERE test_id = %s",
1357 array('integer'),
1358 array($this->test_id)
1359 );
1360 if ($result->numRows() == 1) {
1361 $oldrow = $ilDB->fetchAssoc($result);
1362 }
1363 }
1364
1365 $ilDB->update(
1366 'tst_tests',
1367 array(
1368 'author' => array('text', $this->getAuthor()),
1369 'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1370 'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1371 'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1372 'showinfo' => array('integer', $this->getShowInfo()),
1373 'forcejs' => array('integer', $this->getForceJS()),
1374 'customstyle' => array('text', $this->getCustomStyle()),
1375 'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1376 'sequence_settings' => array('integer', $this->getSequenceSettings()),
1377 'score_reporting' => array('integer', $this->getScoreReporting()),
1378 'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1379 'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1380 'answer_feedback' => array('text', $this->getGenericAnswerFeedback()),
1381 'anonymity' => array('text', $this->getAnonymity()),
1382 'show_cancel' => array('text', $this->getShowCancel()),
1383 'show_marker' => array('integer', $this->getShowMarker()),
1384 'fixed_participants' => array('text', $this->getFixedParticipants()),
1385 'nr_of_tries' => array('integer', $this->getNrOfTries()),
1386 'kiosk' => array('integer', $this->getKiosk()),
1387 'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1388 'title_output' => array('text', $this->getTitleOutput()),
1389 'processing_time' => array('text', $this->getProcessingTime()),
1390 'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1391 'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1392 'reporting_date' => array('text', $this->getReportingDate()),
1393 'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1394 'starting_time' => array('integer', $this->getStartingTime()),
1395 'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1396 'ending_time' => array('integer', $this->getEndingTime()),
1397 'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1398 'ects_output' => array('text', $this->getECTSOutput()),
1399 'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1400 'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1401 'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1402 'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1403 'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1404 'ects_fx' => array('float', $this->getECTSFX()),
1405 'count_system' => array('text', $this->getCountSystem()),
1406 'mc_scoring' => array('text', $this->getMCScoring()),
1407 'score_cutting' => array('text', $this->getScoreCutting()),
1408 'pass_scoring' => array('text', $this->getPassScoring()),
1409 'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1410 'results_presentation' => array('integer', $this->getResultsPresentation()),
1411 'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1412 'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1413 'password' => array('text', $this->getPassword()),
1414 'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1415 'allowedusers' => array('integer', $this->getAllowedUsers()),
1416 'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1417 'mailnottype' => array('integer', $this->getMailNotificationType()),
1418 'exportsettings' => array('integer', $this->getExportSettings()),
1419 'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1420 'mailnotification' => array('integer', $this->getMailNotification()),
1421 'tstamp' => array('integer', time()),
1422 'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1423 'template_id' => array('integer', $this->getTemplate()),
1424 'pool_usage' => array('integer', $this->getPoolUsage()),
1425 'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1426 'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1427 'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1428 'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1429 'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1430 'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1431 'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1432 'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1433 'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1434 'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1435 'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1436 'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1437 'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1438 'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1439 'autosave' => array('integer', (int) $this->getAutosave()),
1440 'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1441 'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1442 'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1443 'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1444 'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1445 'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1446 'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1447 'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1448 'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1449 'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1450 'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1451 'question_set_type' => array('text', $this->getQuestionSetType()),
1452 'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1453 'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1454 'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1455 'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1456 'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1457 'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1458 'follow_qst_answer_fixation' => array('integer', (int) $this->isFollowupQuestionAnswerFixationEnabled()),
1459 'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1460 'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1461 'broken' => array('integer', (int) $this->isTestFinalBroken()),
1462 'pass_waiting' => array('text', (string) $this->getPassWaiting())
1463 ),
1464 array(
1465 'test_id' => array('integer', (int) $this->getTestId())
1466 )
1467 );
1468
1469 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1471 $logresult = $ilDB->queryF(
1472 "SELECT * FROM tst_tests WHERE test_id = %s",
1473 array('integer'),
1474 array($this->getTestId())
1475 );
1476 $newrow = array();
1477 if ($logresult->numRows() == 1) {
1478 $newrow = $ilDB->fetchAssoc($logresult);
1479 }
1480 $changed_fields = array();
1481 foreach ($oldrow as $key => $value) {
1482 if (strcmp($oldrow[$key], $newrow[$key]) != 0) {
1483 array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1484 }
1485 }
1486 $changes = join(", ", $changed_fields);
1487 if (count($changed_fields) > 0) {
1488 $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [" . $changes . "]");
1489 }
1490 }
1491 if ($this->evalTotalPersons() > 0) {
1492 // reset the finished status of participants if the nr of test passes did change
1493 if ($this->getNrOfTries() > 0) {
1494 // set all unfinished tests with nr of passes >= allowed passes finished
1495 $aresult = $ilDB->queryF(
1496 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
1497 array('integer', 'integer', 'integer'),
1498 array($this->getTestId(), $this->getNrOfTries(), 0)
1499 );
1500 while ($row = $ilDB->fetchAssoc($aresult)) {
1501 $ilDB->manipulateF(
1502 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1503 array('integer', 'timestamp', 'integer'),
1504 array(1, date('Y-m-d H:i:s'), $row["active_id"])
1505 );
1506 }
1507
1508 // set all finished tests with nr of passes < allowed passes not finished
1509 $aresult = $ilDB->queryF(
1510 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
1511 array('integer', 'integer', 'integer'),
1512 array($this->getTestId(), $this->getNrOfTries() - 1, 1)
1513 );
1514 while ($row = $ilDB->fetchAssoc($aresult)) {
1515 $ilDB->manipulateF(
1516 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1517 array('integer', 'timestamp', 'integer'),
1518 array(0, null, $row["active_id"])
1519 );
1520 }
1521 } else {
1522 // set all finished tests with nr of passes >= allowed passes not finished
1523 $aresult = $ilDB->queryF(
1524 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
1525 array('integer', 'integer'),
1526 array($this->getTestId(), 1)
1527 );
1528 while ($row = $ilDB->fetchAssoc($aresult)) {
1529 $ilDB->manipulateF(
1530 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1531 array('integer', 'timestamp', 'integer'),
1532 array(0, null, $row["active_id"])
1533 );
1534 }
1535 }
1536 }
1537 }
1538
1539 // news item creation/update/deletion
1540 include_once 'Services/News/classes/class.ilNewsItem.php';
1541 if (!$this->getOldOnlineStatus() && !$this->getOfflineStatus()) {
1542 global $DIC;
1543 $ilUser = $DIC['ilUser'];
1544 $newsItem = new ilNewsItem();
1545 $newsItem->setContext($this->getId(), 'tst');
1546 $newsItem->setPriority(NEWS_NOTICE);
1547 $newsItem->setTitle('new_test_online');
1548 $newsItem->setContentIsLangVar(true);
1549 $newsItem->setContent('');
1550 $newsItem->setUserId($ilUser->getId());
1551 $newsItem->setVisibility(NEWS_USERS);
1552 $newsItem->create();
1553 } elseif ($this->getOldOnlineStatus() && !$this->getOfflineStatus()) {
1554 ilNewsItem::deleteNewsOfContext($this->getId(), 'tst');
1555 } elseif (!$this->getOfflineStatus()) {
1556 $newsId = ilNewsItem::getFirstNewsIdForContext($this->getId(), 'tst');
1557 if ($newsId > 0) {
1558 $newsItem = new ilNewsItem($newsId);
1559 $newsItem->setTitle('new_test_online');
1560 $newsItem->setContentIsLangVar(true);
1561 $newsItem->setContent('');
1562 $newsItem->update();
1563 }
1564 }
1565
1566 // moved activation to ilObjectActivation
1567 if ($this->ref_id) {
1568 include_once "./Services/Object/classes/class.ilObjectActivation.php";
1569 ilObjectActivation::getItem($this->ref_id);
1570
1571 $item = new ilObjectActivation;
1572 if (!$this->isActivationLimited()) {
1574 } else {
1575 $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
1576 $item->setTimingStart($this->getActivationStartingTime());
1577 $item->setTimingEnd($this->getActivationEndingTime());
1578 $item->toggleVisible($this->getActivationVisibility());
1579 }
1580
1581 $item->update($this->ref_id);
1582 }
1583
1584 if (!$properties_only) {
1585 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
1586 $this->saveQuestionsToDb();
1587 }
1588
1589 $this->mark_schema->saveToDb($this->test_id);
1590 }
1591 }
1592
1599 public function saveQuestionsToDb()
1600 {
1601 global $DIC;
1602 $ilDB = $DIC['ilDB'];
1603
1604 $oldquestions = array();
1605 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1607 $result = $ilDB->queryF(
1608 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1609 array('integer'),
1610 array($this->getTestId())
1611 );
1612 if ($result->numRows() > 0) {
1613 while ($row = $ilDB->fetchAssoc($result)) {
1614 array_push($oldquestions, $row["question_fi"]);
1615 }
1616 }
1617 }
1618 // workaround for lost obligations
1619 // this method is called if a question is removed
1620 $currentQuestionsObligationsQuery = 'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
1621 $rset = $ilDB->queryF($currentQuestionsObligationsQuery, array('integer'), array($this->getTestId()));
1622 while ($row = $ilDB->fetchAssoc($rset)) {
1623 $obligatoryQuestionState[$row['question_fi']] = $row['obligatory'];
1624 }
1625 // delete existing category relations
1626 $affectedRows = $ilDB->manipulateF(
1627 "DELETE FROM tst_test_question WHERE test_fi = %s",
1628 array('integer'),
1629 array($this->getTestId())
1630 );
1631 // create new category relations
1632 foreach ($this->questions as $key => $value) {
1633 // workaround for import witout obligations information
1634 if (!isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value])) {
1635 $obligatoryQuestionState[$value] = 0;
1636 }
1637
1638 // insert question
1639 $next_id = $ilDB->nextId('tst_test_question');
1640 $ilDB->insert('tst_test_question', array(
1641 'test_question_id' => array('integer', $next_id),
1642 'test_fi' => array('integer', $this->getTestId()),
1643 'question_fi' => array('integer', $value),
1644 'sequence' => array('integer', $key),
1645 'obligatory' => array('integer', $obligatoryQuestionState[$value]),
1646 'tstamp' => array('integer', time())
1647 ));
1648 }
1649 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1651 $result = $ilDB->queryF(
1652 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1653 array('integer'),
1654 array($this->getTestId())
1655 );
1656 $newquestions = array();
1657 if ($result->numRows() > 0) {
1658 while ($row = $ilDB->fetchAssoc($result)) {
1659 array_push($newquestions, $row["question_fi"]);
1660 }
1661 }
1662 foreach ($oldquestions as $index => $question_id) {
1663 if (strcmp($newquestions[$index], $question_id) != 0) {
1664 $pos = array_search($question_id, $newquestions);
1665 if ($pos === false) {
1666 $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1667 } else {
1668 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index + 1) . " => " . ($pos + 1), $question_id);
1669 }
1670 }
1671 }
1672 foreach ($newquestions as $index => $question_id) {
1673 if (array_search($question_id, $oldquestions) === false) {
1674 $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index + 1), $question_id);
1675 }
1676 }
1677 }
1678 }
1679
1685 protected function isNewRandomTest()
1686 {
1687 global $DIC;
1688 $ilDB = $DIC['ilDB'];
1689 $result = $ilDB->queryF(
1690 'SELECT copy_id FROM tst_rnd_cpy WHERE tst_fi = %s',
1691 array('integer'),
1692 array($this->getTestId())
1693 );
1694 return $result->numRows() > 0;
1695 }
1696
1709 public function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = null)
1710 {
1711 global $DIC;
1712 $rbacsystem = $DIC['rbacsystem'];
1713 $ilDB = $DIC['ilDB'];
1714
1715 // retrieve object id instead of ref id if necessary
1716 if (($questionpool != 0) && (!$use_obj_id)) {
1717 $questionpool = ilObject::_lookupObjId($questionpool);
1718 }
1719
1720 // get original ids of all existing questions in the test
1721 $result = $ilDB->queryF(
1722 "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",
1723 array("integer"),
1724 array($this->getTestId())
1725 );
1726 $original_ids = array();
1727 $paramtypes = array();
1728 $paramvalues = array();
1729 while ($row = $ilDB->fetchAssoc($result)) {
1730 array_push($original_ids, $row['original_id']);
1731 }
1732
1733 $available = "";
1734 // get a list of all available questionpools
1735 if (($questionpool == 0) && (!is_array($qpls))) {
1736 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1737 $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())));
1738 if (count($available_pools)) {
1739 $available = " AND " . $ilDB->in('obj_fi', $available_pools, false, 'integer');
1740 } else {
1741 return array();
1742 }
1743 }
1744
1745 $constraint_qpls = "";
1746 $result_array = array();
1747 if ($questionpool == 0) {
1748 if (is_array($qpls)) {
1749 if (count($qpls) > 0) {
1750 $constraint_qpls = " AND " . $ilDB->in('obj_fi', $qpls, false, 'integer');
1751 }
1752 }
1753 }
1754
1755 $original_clause = "";
1756 if (count($original_ids)) {
1757 $original_clause = " AND " . $ilDB->in('question_id', $original_ids, true, 'integer');
1758 }
1759
1760 if ($questionpool == 0) {
1761 $result = $ilDB->queryF(
1762 "SELECT question_id FROM qpl_questions WHERE original_id IS NULL $available $constraint_qpls AND owner > %s AND complete = %s $original_clause",
1763 array('integer', 'text'),
1764 array(0, "1")
1765 );
1766 } else {
1767 $result = $ilDB->queryF(
1768 "SELECT question_id FROM qpl_questions WHERE original_id IS NULL AND obj_fi = %s AND owner > %s AND complete = %s $original_clause",
1769 array('integer','integer', 'text'),
1770 array($questionpool, 0, "1")
1771 );
1772 }
1773 $found_ids = array();
1774 while ($row = $ilDB->fetchAssoc($result)) {
1775 array_push($found_ids, $row['question_id']);
1776 }
1777 $nr_of_questions = ($nr_of_questions > count($found_ids)) ? count($found_ids) : $nr_of_questions;
1778 if ($nr_of_questions == 0) {
1779 return array();
1780 }
1781 $rand_keys = array_rand($found_ids, $nr_of_questions);
1782 $result = array();
1783 if (is_array($rand_keys)) {
1784 foreach ($rand_keys as $key) {
1785 $result[$found_ids[$key]] = $found_ids[$key];
1786 }
1787 } else {
1788 $result[$found_ids[$rand_keys]] = $found_ids[$rand_keys];
1789 }
1790 return $result;
1791 }
1792
1800 public function getNrOfResultsForPass($active_id, $pass)
1801 {
1802 global $DIC;
1803 $ilDB = $DIC['ilDB'];
1804
1805 $result = $ilDB->queryF(
1806 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1807 array('integer','integer'),
1808 array($active_id, $pass)
1809 );
1810 return $result->numRows();
1811 }
1812
1823 public function hasRandomQuestionsForPass($active_id, $pass)
1824 {
1825 global $DIC;
1826 $ilDB = $DIC['ilDB'];
1827 $result = $ilDB->queryF(
1828 "SELECT test_random_question_id FROM tst_test_rnd_qst WHERE active_fi = %s AND pass = %s",
1829 array('integer','integer'),
1830 array($active_id, $pass)
1831 );
1832 return ($result->numRows() > 0) ? true : false;
1833 }
1834
1838 public function loadFromDb()
1839 {
1840 global $DIC;
1841 $ilDB = $DIC['ilDB'];
1842
1843 $result = $ilDB->queryF(
1844 "SELECT * FROM tst_tests WHERE obj_fi = %s",
1845 array('integer'),
1846 array($this->getId())
1847 );
1848 if ($result->numRows() == 1) {
1849 $data = $ilDB->fetchObject($result);
1850 $this->setTestId($data->test_id);
1851 if (strlen($this->getAuthor()) == 0) {
1852 $this->saveAuthorToMetadata($data->author);
1853 }
1854 $this->setAuthor($data->author);
1855 include_once("./Services/RTE/classes/class.ilRTE.php");
1856 $this->setIntroductionEnabled($data->intro_enabled);
1858 $this->setShowInfo($data->showinfo);
1860 $this->setForceJS($data->forcejs);
1861 $this->setCustomStyle($data->customstyle);
1862 $this->setShowFinalStatement($data->showfinalstatement);
1863 $this->setSequenceSettings($data->sequence_settings);
1864 $this->setScoreReporting($data->score_reporting);
1865 $this->setInstantFeedbackSolution($data->instant_verification);
1866 $this->setAnswerFeedbackPoints($data->answer_feedback_points);
1867 $this->setAnswerFeedback($data->answer_feedback);
1868 $this->setAnonymity($data->anonymity);
1869 $this->setShowCancel($data->show_cancel);
1870 $this->setShowMarker($data->show_marker);
1871 $this->setFixedParticipants($data->fixed_participants);
1872 $this->setNrOfTries($data->nr_of_tries);
1873 $this->setKiosk($data->kiosk);
1874 $this->setUsePreviousAnswers($data->use_previous_answers);
1875 $this->setRedirectionMode($data->redirection_mode);
1876 $this->setRedirectionUrl($data->redirection_url);
1877 $this->setTitleOutput($data->title_output);
1878 $this->setProcessingTime($data->processing_time);
1879 $this->setEnableProcessingTime($data->enable_processing_time);
1880 $this->setResetProcessingTime($data->reset_processing_time);
1881 $this->setReportingDate($data->reporting_date);
1882 $this->setShuffleQuestions($data->shuffle_questions);
1883 $this->setResultsPresentation($data->results_presentation);
1884 $this->setStartingTimeEnabled($data->starting_time_enabled);
1885 $this->setStartingTime($data->starting_time);
1886 $this->setEndingTimeEnabled($data->ending_time_enabled);
1887 $this->setEndingTime($data->ending_time);
1888 $this->setListOfQuestionsSettings($data->show_summary);
1889 $this->setECTSOutput($data->ects_output);
1890 $this->setECTSGrades(
1891 array(
1892 "A" => $data->ects_a,
1893 "B" => $data->ects_b,
1894 "C" => $data->ects_c,
1895 "D" => $data->ects_d,
1896 "E" => $data->ects_e
1897 )
1898 );
1899 $this->setECTSFX($data->ects_fx);
1900 $this->mark_schema->flush();
1901 $this->mark_schema->loadFromDb($this->getTestId());
1902 $this->setCountSystem($data->count_system);
1903 $this->setMCScoring($data->mc_scoring);
1904 $this->setMailNotification($data->mailnotification);
1905 $this->setMailNotificationType($data->mailnottype);
1906 $this->setExportSettings($data->exportsettings);
1907 $this->setScoreCutting($data->score_cutting);
1908 $this->setPasswordEnabled($data->password_enabled);
1909 $this->setPassword($data->password);
1910 $this->setLimitUsersEnabled($data->limit_users_enabled);
1911 $this->setAllowedUsers($data->allowedusers);
1912 $this->setAllowedUsersTimeGap($data->alloweduserstimegap);
1913 $this->setPassScoring($data->pass_scoring);
1914 $this->setObligationsEnabled($data->obligations_enabled);
1915 $this->setOfferingQuestionHintsEnabled($data->offer_question_hints);
1916 $this->setCertificateVisibility($data->certificate_visibility);
1917 $this->setEnabledViewMode($data->enabled_view_mode);
1918 $this->setTemplate($data->template_id);
1919 $this->setPoolUsage($data->pool_usage);
1920 $this->setPrintBestSolutionWithResult((bool) $data->print_bs_with_res);
1921 $this->setHighscoreEnabled((bool) $data->highscore_enabled);
1922 $this->setHighscoreAnon((bool) $data->highscore_anon);
1923 $this->setHighscoreAchievedTS((bool) $data->highscore_achieved_ts);
1924 $this->setHighscoreScore((bool) $data->highscore_score);
1925 $this->setHighscorePercentage((bool) $data->highscore_percentage);
1926 $this->setHighscoreHints((bool) $data->highscore_hints);
1927 $this->setHighscoreWTime((bool) $data->highscore_wtime);
1928 $this->setHighscoreOwnTable((bool) $data->highscore_own_table);
1929 $this->setHighscoreTopTable((bool) $data->highscore_top_table);
1930 $this->setHighscoreTopNum((int) $data->highscore_top_num);
1931 $this->setOldOnlineStatus((bool) !$this->getOfflineStatus());
1932 $this->setSpecificAnswerFeedback((int) $data->specific_feedback);
1933 $this->setAutosave((bool) $data->autosave);
1934 $this->setAutosaveIval((int) $data->autosave_ival);
1935 $this->setPassDeletionAllowed($data->pass_deletion_allowed);
1936 $this->setEnableExamview((bool) $data->enable_examview);
1937 $this->setShowExamviewHtml((bool) $data->show_examview_html);
1938 $this->setShowExamviewPdf((bool) $data->show_examview_pdf);
1939 $this->setEnableArchiving((bool) $data->enable_archiving);
1940 $this->setShowExamIdInTestPassEnabled((bool) $data->examid_in_test_pass);
1941 $this->setShowExamIdInTestResultsEnabled((bool) $data->examid_in_test_res);
1942 $this->setSignSubmission((bool) $data->sign_submission);
1943 $this->setQuestionSetType($data->question_set_type);
1944 $this->setCharSelectorAvailability((int) $data->char_selector_availability);
1945 $this->setCharSelectorDefinition($data->char_selector_definition);
1946 $this->setSkillServiceEnabled((bool) $data->skill_service);
1947 $this->setResultFilterTaxIds(strlen($data->result_tax_filters) ? unserialize($data->result_tax_filters) : array());
1948 $this->setShowGradingStatusEnabled((bool) $data->show_grading_status);
1949 $this->setShowGradingMarkEnabled((bool) $data->show_grading_mark);
1950 $this->setFollowupQuestionAnswerFixationEnabled((bool) $data->follow_qst_answer_fixation);
1951 $this->setInstantFeedbackAnswerFixationEnabled((bool) $data->inst_fb_answer_fixation);
1952 $this->setForceInstantFeedbackEnabled((bool) $data->force_inst_fb);
1953 $this->setTestFinalBroken((bool) $data->broken);
1954 $this->setPassWaiting($data->pass_waiting);
1955 $this->loadQuestions();
1956 }
1957
1958 // moved activation to ilObjectActivation
1959 if ($this->ref_id) {
1960 include_once "./Services/Object/classes/class.ilObjectActivation.php";
1961 $activation = ilObjectActivation::getItem($this->ref_id);
1962 switch ($activation["timing_type"]) {
1964 $this->setActivationLimited(true);
1965 $this->setActivationStartingTime($activation["timing_start"]);
1966 $this->setActivationEndingTime($activation["timing_end"]);
1967 $this->setActivationVisibility($activation["visible"]);
1968 break;
1969
1970 default:
1971 $this->setActivationLimited(false);
1972 break;
1973 }
1974 }
1975 }
1976
1983 public function loadQuestions($active_id = "", $pass = null)
1984 {
1985 global $DIC;
1986 $ilUser = $DIC['ilUser'];
1987 $ilDB = $DIC['ilDB'];
1988
1989 $this->questions = array();
1990 if ($this->isRandomTest()) {
1991 if (strcmp($active_id, "") == 0) {
1992 $active_id = $this->getActiveIdOfUser($ilUser->getId());
1993 }
1994 if (is_null($pass)) {
1995 $pass = self::_getPass($active_id);
1996 }
1997 $result = $ilDB->queryF(
1998 "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",
1999 array('integer', 'integer'),
2000 array($active_id, $pass)
2001 );
2002 // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
2003 // is only one test pass (pass = 0) in tst_test_rnd_qst while with ILIAS 3.8 there are questions for every test pass.
2004 // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
2005 // no questions are present for a newer pass.
2006 if ($result->numRows() == 0) {
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 = 0 ORDER BY sequence",
2009 array('integer'),
2010 array($active_id)
2011 );
2012 }
2013 } else {
2014 $result = $ilDB->queryF(
2015 "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",
2016 array('integer'),
2017 array($this->test_id)
2018 );
2019 }
2020 $index = 1;
2021 while ($data = $ilDB->fetchAssoc($result)) {
2022 $this->questions[$index++] = $data["question_fi"];
2023 }
2024 }
2025
2029 public function isIntroductionEnabled()
2030 {
2032 }
2033
2038 {
2039 $this->introductionEnabled = $introductionEnabled;
2040 }
2041
2048 public function getIntroduction()
2049 {
2050 return (strlen($this->introduction)) ? $this->introduction : null;
2051 }
2052
2060 public function setIntroduction($introduction = "")
2061 {
2062 $this->introduction = $introduction;
2063 }
2064
2065
2073 public function setFinalStatement($a_statement = "")
2074 {
2075 $this->_finalstatement = $a_statement;
2076 }
2077
2085 public function setShowInfo($a_info = 1)
2086 {
2087 $this->_showinfo = ($a_info) ? 1 : 0;
2088 }
2089
2097 public function setForceJS($a_js = 1)
2098 {
2099 $this->_forcejs = ($a_js) ? 1 : 0;
2100 }
2101
2109 public function setCustomStyle($a_customStyle = null)
2110 {
2111 $this->_customStyle = $a_customStyle;
2112 }
2113
2121 public function getCustomStyle()
2122 {
2123 return (strlen($this->_customStyle)) ? $this->_customStyle : null;
2124 }
2125
2133 public function getCustomStyles()
2134 {
2135 $css_path = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2136 $css_path = str_replace("ta.css", "customstyles", $css_path) . "/";
2137 $customstyles = array();
2138 if (is_dir($css_path)) {
2139 $results = array();
2140 include_once "./Services/Utilities/classes/class.ilFileUtils.php";
2142 if (is_array($results["file"])) {
2143 foreach ($results["file"] as $filename) {
2144 if (strpos($filename, ".css")) {
2145 array_push($customstyles, $filename);
2146 }
2147 }
2148 }
2149 }
2150 return $customstyles;
2151 }
2152
2160 public function getTestStyleLocation($mode = "output")
2161 {
2162 if (strlen($this->getCustomStyle())) {
2163 $default = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2164 $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $default);
2165 if (file_exists($custom)) {
2166 $custom = ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2167 $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $custom);
2168 return $custom;
2169 } else {
2170 return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2171 }
2172 } else {
2173 return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2174 }
2175 }
2176
2184 public function setShowFinalStatement($show = 0)
2185 {
2186 $this->_showfinalstatement = ($show) ? 1 : 0;
2187 }
2188
2195 public function getFinalStatement()
2196 {
2197 return (strlen($this->_finalstatement)) ? $this->_finalstatement : null;
2198 }
2199
2207 public function getShowInfo()
2208 {
2209 return ($this->_showinfo) ? 1 : 0;
2210 }
2211
2219 public function getForceJS()
2220 {
2221 return ($this->_forcejs) ? 1 : 0;
2222 }
2223
2231 public function getShowFinalStatement()
2232 {
2233 return ($this->_showfinalstatement) ? 1 : 0;
2234 }
2235
2243 public function getTestId()
2244 {
2245 return $this->test_id;
2246 }
2247
2251 public function getECTSOutput()
2252 {
2253 return ($this->ects_output) ? 1 : 0;
2254 }
2255
2259 public function setECTSOutput($a_ects_output)
2260 {
2261 $this->ects_output = $a_ects_output ? 1 : 0;
2262 }
2263
2267 public function getECTSFX()
2268 {
2269 return (strlen($this->ects_fx)) ? $this->ects_fx : null;
2270 }
2271
2275 public function setECTSFX($a_ects_fx)
2276 {
2277 $this->ects_fx = $a_ects_fx;
2278 }
2279
2283 public function getECTSGrades()
2284 {
2285 return $this->ects_grades;
2286 }
2287
2291 public function setECTSGrades(array $a_ects_grades)
2292 {
2293 $this->ects_grades = $a_ects_grades;
2294 }
2295
2301 public function getSequenceSettings()
2302 {
2303 return ($this->sequence_settings) ? $this->sequence_settings : 0;
2304 }
2305
2312 {
2313 $this->sequence_settings = $sequence_settings;
2314 }
2315
2319 public function isPostponingEnabled()
2320 {
2321 return (bool) $this->getSequenceSettings();
2322 }
2323
2327 public function setPostponingEnabled($postponingEnabled)
2328 {
2329 $this->setSequenceSettings((int) $postponingEnabled);
2330 }
2331
2340 {
2341 $this->score_reporting = $score_reporting;
2342 }
2343
2351 public function setInstantFeedbackSolution($instant_feedback = 0)
2352 {
2353 switch ($instant_feedback) {
2354 case 1:
2355 $this->instant_verification = 1;
2356 break;
2357 default:
2358 $this->instant_verification = 0;
2359 break;
2360 }
2361 }
2362
2371 {
2372 switch ($answer_feedback) {
2373 case 1:
2374 $this->answer_feedback = 1;
2375 break;
2376 default:
2377 $this->answer_feedback = 0;
2378 break;
2379 }
2380 }
2381
2387 public function setGenericAnswerFeedback($generic_answer_feedback = 0)
2388 {
2389 switch ($generic_answer_feedback) {
2390 case 1:
2391 $this->answer_feedback = 1;
2392 break;
2393 default:
2394 $this->answer_feedback = 0;
2395 break;
2396 }
2397 }
2398
2407 {
2408 switch ($answer_feedback_points) {
2409 case 1:
2410 $this->answer_feedback_points = 1;
2411 break;
2412 default:
2413 $this->answer_feedback_points = 0;
2414 break;
2415 }
2416 }
2417
2423 {
2424 if (!$reporting_date) {
2425 $this->reporting_date = '';
2426 $this->setECTSOutput(false);
2427 } else {
2428 $this->reporting_date = $reporting_date;
2429 }
2430 }
2431
2437
2445 public function getScoreReporting()
2446 {
2447 return ($this->score_reporting) ? $this->score_reporting : 0;
2448 }
2449
2450 public function isScoreReportingEnabled()
2451 {
2452 switch ($this->getScoreReporting()) {
2457
2458 return true;
2459
2461 default:
2462
2463 return false;
2464 }
2465 }
2466
2475 {
2476 return ($this->instant_verification) ? $this->instant_verification : 0;
2477 }
2478
2487 public function getAnswerFeedback()
2488 {
2489 return ($this->answer_feedback) ? $this->answer_feedback : 0;
2490 }
2491
2499 {
2500 return ($this->answer_feedback) ? $this->answer_feedback : 0;
2501 }
2502
2510 public function getAnswerFeedbackPoints()
2511 {
2512 return ($this->answer_feedback_points) ? $this->answer_feedback_points : 0;
2513 }
2514
2522 public function getCountSystem()
2523 {
2524 return ($this->count_system) ? $this->count_system : 0;
2525 }
2526
2534 public static function _getCountSystem($active_id)
2535 {
2536 global $DIC;
2537 $ilDB = $DIC['ilDB'];
2538 $result = $ilDB->queryF(
2539 "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",
2540 array('integer'),
2541 array($active_id)
2542 );
2543 if ($result->numRows()) {
2544 $row = $ilDB->fetchAssoc($result);
2545 return $row["count_system"];
2546 }
2547 return false;
2548 }
2549
2557 public function getMCScoring()
2558 {
2559 return ($this->mc_scoring) ? $this->mc_scoring : 0;
2560 }
2561
2569 public function getScoreCutting()
2570 {
2571 return ($this->score_cutting) ? $this->score_cutting : 0;
2572 }
2573
2581 public function getPassScoring()
2582 {
2583 return ($this->pass_scoring) ? $this->pass_scoring : 0;
2584 }
2585
2593 public static function _getPassScoring($active_id)
2594 {
2595 global $DIC;
2596 $ilDB = $DIC['ilDB'];
2597 $result = $ilDB->queryF(
2598 "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",
2599 array('integer'),
2600 array($active_id)
2601 );
2602 if ($result->numRows()) {
2603 $row = $ilDB->fetchAssoc($result);
2604 return $row["pass_scoring"];
2605 }
2606 return 0;
2607 }
2608
2616 public static function _getMCScoring($active_id)
2617 {
2618 global $DIC;
2619 $ilDB = $DIC['ilDB'];
2620 $result = $ilDB->queryF(
2621 "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",
2622 array('integer'),
2623 array($active_id)
2624 );
2625 if ($result->numRows()) {
2626 $row = $ilDB->fetchAssoc($result);
2627 return $row["mc_scoring"];
2628 }
2629 return false;
2630 }
2631
2639 public static function _getScoreCutting($active_id)
2640 {
2641 global $DIC;
2642 $ilDB = $DIC['ilDB'];
2643 $result = $ilDB->queryF(
2644 "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",
2645 array('integer'),
2646 array($active_id)
2647 );
2648 if ($result->numRows()) {
2649 $row = $ilDB->fetchAssoc($result);
2650 return $row["score_cutting"];
2651 }
2652 return false;
2653 }
2654
2662 public function getReportingDate()
2663 {
2664 return (strlen($this->reporting_date)) ? $this->reporting_date : null;
2665 }
2666
2674 public function getNrOfTries()
2675 {
2676 return ($this->nr_of_tries) ? $this->nr_of_tries : 0;
2677 }
2678
2686 public function getKiosk()
2687 {
2688 return ($this->_kiosk) ? $this->_kiosk : 0;
2689 }
2690
2691
2699 public function setKiosk($kiosk = 0)
2700 {
2701 $this->_kiosk = $kiosk;
2702 }
2703
2711 public function getKioskMode()
2712 {
2713 if (($this->_kiosk & 1) > 0) {
2714 return true;
2715 } else {
2716 return false;
2717 }
2718 }
2719
2727 public function setKioskMode($a_kiosk = false)
2728 {
2729 if ($a_kiosk) {
2730 $this->_kiosk = $this->_kiosk | 1;
2731 } else {
2732 if ($this->getKioskMode()) {
2733 $this->_kiosk = $this->_kiosk ^ 1;
2734 }
2735 }
2736 }
2737
2745 public function getShowKioskModeTitle()
2746 {
2747 if (($this->_kiosk & 2) > 0) {
2748 return true;
2749 } else {
2750 return false;
2751 }
2752 }
2753
2760 public function setShowKioskModeTitle($a_title = false)
2761 {
2762 if ($a_title) {
2763 $this->_kiosk = $this->_kiosk | 2;
2764 } else {
2765 if ($this->getShowKioskModeTitle()) {
2766 $this->_kiosk = $this->_kiosk ^ 2;
2767 }
2768 }
2769 }
2770
2779 {
2780 if (($this->_kiosk & 4) > 0) {
2781 return true;
2782 } else {
2783 return false;
2784 }
2785 }
2786
2793 public function setShowKioskModeParticipant($a_participant = false)
2794 {
2795 if ($a_participant) {
2796 $this->_kiosk = $this->_kiosk | 4;
2797 } else {
2798 if ($this->getShowKioskModeParticipant()) {
2799 $this->_kiosk = $this->_kiosk ^ 4;
2800 }
2801 }
2802 }
2803
2811 public function getUsePreviousAnswers()
2812 {
2813 return ($this->use_previous_answers) ? $this->use_previous_answers : 0;
2814 }
2815
2823 public function getTitleOutput()
2824 {
2825 return ($this->title_output) ? $this->title_output : 0;
2826 }
2827
2836 public function _getTitleOutput($active_id)
2837 {
2838 global $DIC;
2839 $ilDB = $DIC['ilDB'];
2840
2841 $result = $ilDB->queryF(
2842 "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",
2843 array('integer'),
2844 array($active_id)
2845 );
2846 if ($result->numRows()) {
2847 $row = $ilDB->fetchAssoc($result);
2848 return $row["title_output"];
2849 }
2850 return 0;
2851 }
2852
2853 // hey: prevPassSolutions - serious (nonstatic) identifier, for use in high level controller gui
2854 public function isPreviousSolutionReuseEnabled($activeId)
2855 {
2856 // checks if allowed in general and if enabled by participant
2857 return self::_getUsePreviousAnswers($activeId, true);
2858 }
2859 // hey.
2860
2870 public static function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
2871 {
2872 global $DIC;
2873 $ilDB = $DIC['ilDB'];
2874 $ilUser = $DIC['ilUser'];
2875
2877
2878 $result = $ilDB->queryF(
2879 "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",
2880 array("integer"),
2881 array($active_id)
2882 );
2883 if ($result->numRows()) {
2884 $row = $ilDB->fetchAssoc($result);
2885 $use_previous_answers = $row["use_previous_answers"];
2886 }
2887
2888 if ($use_previous_answers == 1) {
2889 if ($user_active_user_setting) {
2890 $res = $ilUser->getPref("tst_use_previous_answers");
2891 if ($res !== false) {
2893 }
2894 }
2895 }
2896 return $use_previous_answers;
2897 }
2898
2906 public function getProcessingTime()
2907 {
2908 return (strlen($this->processing_time)) ? $this->processing_time : null;
2909 }
2910
2918 {
2919 if (strlen($this->processing_time)) {
2920 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2921 if ((int) $matches[1] + (int) $matches[2] + (int) $matches[3] == 0) {
2922 return $this->getEstimatedWorkingTime();
2923 } else {
2924 return array(
2925 'hh' => $matches[1],
2926 'mm' => $matches[2],
2927 'ss' => $matches[3],
2928 );
2929 }
2930 }
2931 }
2932 return $this->getEstimatedWorkingTime();
2933 }
2934
2936 {
2937 if (strlen($this->processing_time)) {
2938 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2939 return ($matches[1] * 60) + $matches[2];
2940 }
2941 }
2942
2944 }
2945
2953 public function getProcessingTimeInSeconds($active_id = "")
2954 {
2955 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches)) {
2956 $extratime = $this->getExtraTime($active_id) * 60;
2957 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
2958 } else {
2959 return 0;
2960 }
2961 }
2962
2971 {
2972 if ($this->getEndingTime() != 0) {
2973 $ending = $this->getEndingTime();
2974 $now = time();
2975 return $ending - $now;
2976 } else {
2977 return 0;
2978 }
2979 }
2980
2988 public function getEnableProcessingTime()
2989 {
2990 return ($this->enable_processing_time) ? $this->enable_processing_time : 0;
2991 }
2992
3000 public function getResetProcessingTime()
3001 {
3002 return ($this->reset_processing_time) ? $this->reset_processing_time : 0;
3003 }
3004
3008 public function isStartingTimeEnabled()
3009 {
3011 }
3012
3017 {
3018 $this->starting_time_enabled = $starting_time_enabled;
3019 }
3020
3028 public function getStartingTime()
3029 {
3030 return ($this->starting_time != 0) ? $this->starting_time : 0;
3031 }
3032
3040 public function setStartingTime($starting_time = null)
3041 {
3042 $this->starting_time = $starting_time;
3043 }
3044
3048 public function isEndingTimeEnabled()
3049 {
3051 }
3052
3057 {
3058 $this->ending_time_enabled = $ending_time_enabled;
3059 }
3060
3068 public function getEndingTime()
3069 {
3070 return ($this->ending_time != 0) ? $this->ending_time : 0;
3071 }
3072
3080 public function setEndingTime($ending_time = null)
3081 {
3082 $this->ending_time = $ending_time;
3083 }
3084
3092 public function setNrOfTries($nr_of_tries = 0)
3093 {
3094 $this->nr_of_tries = $nr_of_tries;
3095 }
3096
3105 {
3107 $this->use_previous_answers = 1;
3108 } else {
3109 $this->use_previous_answers = 0;
3110 }
3111 }
3112
3114 {
3115 $this->redirection_mode = $redirection_mode;
3116 }
3117 public function getRedirectionMode()
3118 {
3120 }
3121 public function setRedirectionUrl($redirection_url = null)
3122 {
3123 $this->redirection_url = $redirection_url;
3124 }
3125 public function getRedirectionUrl()
3126 {
3128 }
3129
3137 public function setTitleOutput($title_output = 0)
3138 {
3139 switch ($title_output) {
3140 case 1:
3141 $this->title_output = 1;
3142 break;
3143 case 2:
3144 $this->title_output = 2;
3145 break;
3146 default:
3147 $this->title_output = 0;
3148 break;
3149 }
3150 }
3151
3159 public function setProcessingTime($processing_time = "00:00:00")
3160 {
3161 $this->processing_time = $processing_time;
3162 }
3163
3164 public function setProcessingTimeByMinutes($minutes)
3165 {
3166 $this->processing_time = sprintf("%02d:%02d:00", floor($minutes / 60), $minutes % 60);
3167 }
3168
3176 public function setEnableProcessingTime($enable = 0)
3177 {
3178 if ($enable) {
3179 $this->enable_processing_time = "1";
3180 } else {
3181 $this->enable_processing_time = "0";
3182 }
3183 }
3184
3192 public function setResetProcessingTime($reset = 0)
3193 {
3194 if ($reset) {
3195 $this->reset_processing_time = 1;
3196 } else {
3197 $this->reset_processing_time = 0;
3198 }
3199 }
3200
3208 public function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3209 {
3210 $this->count_system = $a_count_system;
3211 }
3212
3216 public function isPasswordEnabled()
3217 {
3219 }
3220
3225 {
3226 $this->passwordEnabled = $passwordEnabled;
3227 }
3228
3236 public function getPassword()
3237 {
3238 return (strlen($this->password)) ? $this->password : null;
3239 }
3240
3248 public function setPassword($a_password = null)
3249 {
3250 $this->password = $a_password;
3251 }
3252
3260 public function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3261 {
3262 $this->score_cutting = $a_score_cutting;
3263 }
3264
3272 public function setMCScoring($a_mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED)
3273 {
3274 $this->mc_scoring = $a_mc_scoring;
3275 }
3276
3284 public function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3285 {
3286 switch ($a_pass_scoring) {
3287 case SCORE_BEST_PASS:
3288 $this->pass_scoring = SCORE_BEST_PASS;
3289 break;
3290 default:
3291 $this->pass_scoring = SCORE_LAST_PASS;
3292 break;
3293 }
3294 }
3295
3299 public function getPassWaiting()
3300 {
3301 return $this->pass_waiting;
3302 }
3303
3308 {
3309 $this->pass_waiting = $pass_waiting;
3310 }
3314 public function isPassWaitingEnabled()
3315 {
3316 if (array_sum(explode(':', $this->getPassWaiting())) > 0) {
3317 return true;
3318 }
3319 return false;
3320 }
3321
3327 public function removeQuestionFromSequences($questionId, $activeIds, ilTestReindexedSequencePositionMap $reindexedSequencePositionMap)
3328 {
3329 global $DIC; /* @var ILIAS\DI\Container $DIC */
3330
3331 $testSequenceFactory = new ilTestSequenceFactory(
3332 $DIC->database(),
3333 $DIC->language(),
3334 $DIC['ilPluginAdmin'],
3335 $this
3336 );
3337
3338 foreach ($activeIds as $activeId) {
3339 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
3340 $passSelector->setActiveId($activeId);
3341
3342 foreach ($passSelector->getExistingPasses() as $pass) {
3343 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $pass);
3344 $testSequence->loadFromDb();
3345
3346 $testSequence->removeQuestion($questionId, $reindexedSequencePositionMap);
3347 $testSequence->saveToDb();
3348 }
3349 }
3350 }
3351
3355 public function removeQuestions($removeQuestionIds)
3356 {
3357 foreach ($removeQuestionIds as $value) {
3358 $this->removeQuestion($value);
3359 }
3360
3362 }
3363
3371 public function removeQuestion($question_id)
3372 {
3373 $question = &ilObjTest::_instanciateQuestion($question_id);
3374 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3376 $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3377 }
3378 $question->delete($question_id);
3379 }
3380
3390 {
3391 $this->removeTestResultsByUserIds($userIds);
3392
3393 global $DIC;
3394 $ilDB = $DIC['ilDB'];
3395 $lng = $DIC['lng'];
3396
3397 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3398 $participantData = new ilTestParticipantData($ilDB, $lng);
3399 $participantData->setUserIdsFilter($userIds);
3400 $participantData->load($this->getTestId());
3401
3402 $this->removeTestActives($participantData->getActiveIds());
3403 }
3404
3405 public function removeTestResults(ilTestParticipantData $participantData)
3406 {
3407 if (count($participantData->getAnonymousActiveIds())) {
3408 $this->removeTestResultsByActiveIds($participantData->getAnonymousActiveIds());
3409 }
3410
3411 if (count($participantData->getUserIds())) {
3412 /* @var ilTestLP $testLP */
3413 require_once 'Services/Object/classes/class.ilObjectLP.php';
3414 $testLP = ilObjectLP::getInstance($this->getId());
3415 $testLP->setTestObject($this);
3416 $testLP->resetLPDataForUserIds($participantData->getUserIds(), false);
3417 }
3418
3419 if (count($participantData->getActiveIds())) {
3420 $this->removeTestActives($participantData->getActiveIds());
3421 }
3422 }
3423
3424 public function removeTestResultsByUserIds($userIds)
3425 {
3426 global $DIC;
3427 $ilDB = $DIC['ilDB'];
3428 $lng = $DIC['lng'];
3429
3430 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3431 $participantData = new ilTestParticipantData($ilDB, $lng);
3432 $participantData->setUserIdsFilter($userIds);
3433 $participantData->load($this->getTestId());
3434
3435 $IN_userIds = $ilDB->in('usr_id', $participantData->getUserIds(), false, 'integer');
3436 $ilDB->manipulateF(
3437 "DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
3438 array('text'),
3439 array("tst_password_" . $this->getTestId())
3440 );
3441
3442 if (count($participantData->getActiveIds())) {
3443 $this->removeTestResultsByActiveIds($participantData->getActiveIds());
3444 }
3445 }
3446
3447 public function removeTestResultsByActiveIds($activeIds)
3448 {
3449 global $DIC;
3450 $ilDB = $DIC['ilDB'];
3451
3452 $IN_activeIds = $ilDB->in('active_fi', $activeIds, false, 'integer');
3453
3454 $ilDB->manipulate("DELETE FROM tst_solutions WHERE $IN_activeIds");
3455 $ilDB->manipulate("DELETE FROM tst_qst_solved WHERE $IN_activeIds");
3456 $ilDB->manipulate("DELETE FROM tst_test_result WHERE $IN_activeIds");
3457 $ilDB->manipulate("DELETE FROM tst_pass_result WHERE $IN_activeIds");
3458 $ilDB->manipulate("DELETE FROM tst_result_cache WHERE $IN_activeIds");
3459 $ilDB->manipulate("DELETE FROM tst_sequence WHERE $IN_activeIds");
3460 $ilDB->manipulate("DELETE FROM tst_times WHERE $IN_activeIds");
3461
3462 if ($this->isRandomTest()) {
3463 $ilDB->manipulate("DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
3464 } elseif ($this->isDynamicTest()) {
3465 $ilDB->manipulate("DELETE FROM tst_seq_qst_tracking WHERE $IN_activeIds");
3466 $ilDB->manipulate("DELETE FROM tst_seq_qst_answstatus WHERE $IN_activeIds");
3467 $ilDB->manipulate("DELETE FROM tst_seq_qst_postponed WHERE $IN_activeIds");
3468 $ilDB->manipulate("DELETE FROM tst_seq_qst_checked WHERE $IN_activeIds");
3469 }
3470
3471 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3472
3473 foreach ($activeIds as $active_id) {
3474 // remove file uploads
3475 if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id")) {
3476 ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3477 }
3478
3480 $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3481 }
3482 }
3483
3484 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3486 }
3487
3488 public function removeTestActives($activeIds)
3489 {
3490 global $DIC;
3491 $ilDB = $DIC['ilDB'];
3492
3493 $IN_activeIds = $ilDB->in('active_id', $activeIds, false, 'integer');
3494 $ilDB->manipulate("DELETE FROM tst_active WHERE $IN_activeIds");
3495 }
3496
3504 public function questionMoveUp($question_id)
3505 {
3506 global $DIC;
3507 $ilDB = $DIC['ilDB'];
3508
3509 // Move a question up in sequence
3510 $result = $ilDB->queryF(
3511 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3512 array('integer', 'integer'),
3513 array($this->getTestId(), $question_id)
3514 );
3515 $data = $ilDB->fetchObject($result);
3516 if ($data->sequence > 1) {
3517 // OK, it's not the top question, so move it up
3518 $result = $ilDB->queryF(
3519 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3520 array('integer','integer'),
3521 array($this->getTestId(), $data->sequence - 1)
3522 );
3523 $data_previous = $ilDB->fetchObject($result);
3524 // change previous dataset
3525 $affectedRows = $ilDB->manipulateF(
3526 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3527 array('integer','integer'),
3528 array($data->sequence, $data_previous->test_question_id)
3529 );
3530 // move actual dataset up
3531 $affectedRows = $ilDB->manipulateF(
3532 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3533 array('integer','integer'),
3534 array($data->sequence - 1, $data->test_question_id)
3535 );
3536 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3538 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence - 1), $question_id);
3539 }
3540 }
3541 $this->loadQuestions();
3542 }
3543
3551 public function questionMoveDown($question_id)
3552 {
3553 global $DIC;
3554 $ilDB = $DIC['ilDB'];
3555
3556 // Move a question down in sequence
3557 $result = $ilDB->queryF(
3558 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3559 array('integer','integer'),
3560 array($this->getTestId(), $question_id)
3561 );
3562 $data = $ilDB->fetchObject($result);
3563 $result = $ilDB->queryF(
3564 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3565 array('integer','integer'),
3566 array($this->getTestId(), $data->sequence + 1)
3567 );
3568 if ($result->numRows() == 1) {
3569 // OK, it's not the last question, so move it down
3570 $data_next = $ilDB->fetchObject($result);
3571 // change next dataset
3572 $affectedRows = $ilDB->manipulateF(
3573 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3574 array('integer','integer'),
3575 array($data->sequence, $data_next->test_question_id)
3576 );
3577 // move actual dataset down
3578 $affectedRows = $ilDB->manipulateF(
3579 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3580 array('integer','integer'),
3581 array($data->sequence + 1, $data->test_question_id)
3582 );
3583 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3585 $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence + 1), $question_id);
3586 }
3587 }
3588 $this->loadQuestions();
3589 }
3590
3598 public function duplicateQuestionForTest($question_id)
3599 {
3600 global $DIC;
3601 $ilUser = $DIC['ilUser'];
3602 $question = &ilObjTest::_instanciateQuestion($question_id);
3603 $duplicate_id = $question->duplicate(true, null, null, null, $this->getId());
3604
3605 return $duplicate_id;
3606 }
3607
3616 public function insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly = false)
3617 {
3618 global $DIC;
3619 $ilDB = $DIC['ilDB'];
3620 #var_dump($question_id);
3621 if ($linkOnly) {
3622 $duplicate_id = $question_id;
3623 } else {
3624 $duplicate_id = $this->duplicateQuestionForTest($question_id);
3625 }
3626
3627 // get maximum sequence index in test
3628 $result = $ilDB->queryF(
3629 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
3630 array('integer'),
3631 array($this->getTestId())
3632 );
3633 $sequence = 1;
3634
3635 if ($result->numRows() == 1) {
3636 $data = $ilDB->fetchObject($result);
3637 $sequence = $data->seq + 1;
3638 }
3639
3640 $next_id = $ilDB->nextId('tst_test_question');
3641 $affectedRows = $ilDB->manipulateF(
3642 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
3643 array('integer', 'integer','integer','integer','integer'),
3644 array($next_id, $this->getTestId(), $duplicate_id, $sequence, time())
3645 );
3646 if ($affectedRows == 1) {
3647 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3649 $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3650 }
3651 }
3652 // remove test_active entries, because test has changed
3653 $affectedRows = $ilDB->manipulateF(
3654 "DELETE FROM tst_active WHERE test_fi = %s",
3655 array('integer'),
3656 array($this->getTestId())
3657 );
3658 $this->loadQuestions();
3659 $this->saveCompleteStatus($testQuestionSetConfig);
3660 return $duplicate_id;
3661 }
3662
3670 public function &getQuestionTitles()
3671 {
3672 $titles = array();
3673 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3674 global $DIC;
3675 $ilDB = $DIC['ilDB'];
3676 $result = $ilDB->queryF(
3677 "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",
3678 array('integer'),
3679 array($this->getTestId())
3680 );
3681 while ($row = $ilDB->fetchAssoc($result)) {
3682 array_push($titles, $row["title"]);
3683 }
3684 }
3685 return $titles;
3686 }
3687
3696 {
3697 $titles = array();
3698 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3699 global $DIC;
3700 $ilDB = $DIC['ilDB'];
3701 $result = $ilDB->queryF(
3702 "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",
3703 array('integer'),
3704 array($this->getTestId())
3705 );
3706 while ($row = $ilDB->fetchAssoc($result)) {
3707 $titles[$row['question_id']] = $row["title"];
3708 }
3709 }
3710 return $titles;
3711 }
3712
3713 // fau: testNav - add number parameter (to show if title should not be shown)
3723 public function getQuestionTitle($title, $nr = null)
3724 {
3725 if ($this->getTitleOutput() == 2) {
3726 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC) {
3727 // avoid legacy setting combination: ctm without question titles
3728 return $title;
3729 } elseif (isset($nr)) {
3730 return $this->lng->txt("ass_question") . ' ' . $nr;
3731 } else {
3732 return $this->lng->txt("ass_question");
3733 }
3734 } else {
3735 return $title;
3736 }
3737 }
3738 // fau.
3739
3748 public function getQuestionDataset($question_id)
3749 {
3750 global $DIC;
3751 $ilDB = $DIC['ilDB'];
3752
3753 $result = $ilDB->queryF(
3754 "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",
3755 array('integer'),
3756 array($question_id)
3757 );
3758 $row = $ilDB->fetchObject($result);
3759 return $row;
3760 }
3761
3768 public function &getExistingQuestions($pass = null)
3769 {
3770 global $DIC;
3771 $ilUser = $DIC['ilUser'];
3772 $ilDB = $DIC['ilDB'];
3773
3774 $existing_questions = array();
3775 $active_id = $this->getActiveIdOfUser($ilUser->getId());
3776 if ($this->isRandomTest()) {
3777 if (is_null($pass)) {
3778 $pass = 0;
3779 }
3780 $result = $ilDB->queryF(
3781 "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",
3782 array('integer','integer'),
3783 array($active_id, $pass)
3784 );
3785 } else {
3786 $result = $ilDB->queryF(
3787 "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",
3788 array('integer'),
3789 array($this->getTestId())
3790 );
3791 }
3792 while ($data = $ilDB->fetchObject($result)) {
3793 if ($data->original_id === null) {
3794 continue;
3795 }
3796
3797 array_push($existing_questions, $data->original_id);
3798 }
3799 return $existing_questions;
3800 }
3801
3809 public function getQuestionType($question_id)
3810 {
3811 global $DIC;
3812 $ilDB = $DIC['ilDB'];
3813
3814 if ($question_id < 1) {
3815 return -1;
3816 }
3817 $result = $ilDB->queryF(
3818 "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",
3819 array('integer'),
3820 array($question_id)
3821 );
3822 if ($result->numRows() == 1) {
3823 $data = $ilDB->fetchObject($result);
3824 return $data->type_tag;
3825 } else {
3826 return "";
3827 }
3828 }
3829
3836 public function startWorkingTime($active_id, $pass)
3837 {
3838 global $DIC;
3839 $ilDB = $DIC['ilDB'];
3840
3841 $next_id = $ilDB->nextId('tst_times');
3842 $affectedRows = $ilDB->manipulateF(
3843 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
3844 array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'),
3845 array($next_id, $active_id, strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"), $pass, time())
3846 );
3847 return $next_id;
3848 }
3849
3856 public function updateWorkingTime($times_id)
3857 {
3858 global $DIC;
3859 $ilDB = $DIC['ilDB'];
3860
3861 $affectedRows = $ilDB->manipulateF(
3862 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
3863 array('timestamp', 'integer', 'integer'),
3864 array(strftime("%Y-%m-%d %H:%M:%S"), time(), $times_id)
3865 );
3866 }
3867
3874 public function &getWorkedQuestions($active_id, $pass = null)
3875 {
3876 global $DIC;
3877 $ilUser = $DIC['ilUser'];
3878 $ilDB = $DIC['ilDB'];
3879
3880 if (is_null($pass)) {
3881 $result = $ilDB->queryF(
3882 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3883 array('integer','integer'),
3884 array($active_id, 0)
3885 );
3886 } else {
3887 $result = $ilDB->queryF(
3888 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3889 array('integer','integer'),
3890 array($active_id, $pass)
3891 );
3892 }
3893 $result_array = array();
3894 while ($row = $ilDB->fetchAssoc($result)) {
3895 array_push($result_array, $row["question_fi"]);
3896 }
3897 return $result_array;
3898 }
3899
3908 public function isTestFinishedToViewResults($active_id, $currentpass)
3909 {
3910 $num = ilObjTest::lookupPassResultsUpdateTimestamp($active_id, $currentpass);
3911 return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ? true : false;
3912 }
3913
3920 public function &getAllQuestions($pass = null)
3921 {
3922 global $DIC;
3923 $ilUser = $DIC['ilUser'];
3924 $ilDB = $DIC['ilDB'];
3925
3926 $result_array = array();
3927 if ($this->isRandomTest()) {
3928 $active_id = $this->getActiveIdOfUser($ilUser->getId());
3929 $this->loadQuestions($active_id, $pass);
3930 if (count($this->questions) == 0) {
3931 return $result_array;
3932 }
3933 if (is_null($pass)) {
3934 $pass = self::_getPass($active_id);
3935 }
3936 $result = $ilDB->queryF(
3937 "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'),
3938 array('integer','integer'),
3939 array($active_id, $pass)
3940 );
3941 } else {
3942 if (count($this->questions) == 0) {
3943 return $result_array;
3944 }
3945 $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'));
3946 }
3947 while ($row = $ilDB->fetchAssoc($result)) {
3948 $result_array[$row["question_id"]] = $row;
3949 }
3950 return $result_array;
3951 }
3952
3961 public function getActiveIdOfUser($user_id = "", $anonymous_id = "")
3962 {
3963 global $DIC;
3964 $ilDB = $DIC['ilDB'];
3965 $ilUser = $DIC['ilUser'];
3966
3967 if (!$user_id) {
3968 $user_id = $ilUser->getId();
3969 }
3970 if (($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()]))) {
3971 $result = $ilDB->queryF(
3972 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3973 array('integer','integer','text'),
3974 array($user_id, $this->test_id, $_SESSION["tst_access_code"][$this->getTestId()])
3975 );
3976 } elseif (strlen($anonymous_id)) {
3977 $result = $ilDB->queryF(
3978 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3979 array('integer','integer','text'),
3980 array($user_id, $this->test_id, $anonymous_id)
3981 );
3982 } else {
3983 if ($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) {
3984 return null;
3985 }
3986 $result = $ilDB->queryF(
3987 "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
3988 array('integer','integer'),
3989 array($user_id, $this->test_id)
3990 );
3991 }
3992 if ($result->numRows()) {
3993 $row = $ilDB->fetchAssoc($result);
3994 return $row["active_id"];
3995 } else {
3996 return 0;
3997 }
3998 }
3999
4008 public static function _getActiveIdOfUser($user_id = "", $test_id = "")
4009 {
4010 global $DIC;
4011 $ilDB = $DIC['ilDB'];
4012 $ilUser = $DIC['ilUser'];
4013
4014 if (!$user_id) {
4015 $user_id = $ilUser->id;
4016 }
4017 if (!$test_id) {
4018 return "";
4019 }
4020 $result = $ilDB->queryF(
4021 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4022 array('integer', 'integer'),
4023 array($user_id, $test_id)
4024 );
4025 if ($result->numRows()) {
4026 $row = $ilDB->fetchAssoc($result);
4027 return $row["active_id"];
4028 } else {
4029 return "";
4030 }
4031 }
4032
4039 public function pcArrayShuffle($array)
4040 {
4041 $keys = array_keys($array);
4042 shuffle($keys);
4043 $result = array();
4044 foreach ($keys as $key) {
4045 $result[$key] = $array[$key];
4046 }
4047 return $result;
4048 }
4049
4057 public function &getTestResult($active_id, $pass = null, $ordered_sequence = false, $considerHiddenQuestions = true, $considerOptionalQuestions = true)
4058 {
4059 global $DIC;
4060 $tree = $DIC['tree'];
4061 $ilDB = $DIC['ilDB'];
4062 $lng = $DIC['lng'];
4063 $ilPluginAdmin = $DIC['ilPluginAdmin'];
4064
4065 $results = $this->getResultsForActiveId($active_id);
4066
4067 if (is_null($pass)) {
4068 $pass = $results['pass'];
4069 }
4070
4071 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
4072 $testSessionFactory = new ilTestSessionFactory($this);
4073 $testSession = $testSessionFactory->getSession($active_id);
4074
4075 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4076 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
4077 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $pass);
4078
4079 if ($this->isDynamicTest()) {
4080 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4081 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
4082 $dynamicQuestionSetConfig->loadFromDb();
4083
4084 $testSequence->loadFromDb($dynamicQuestionSetConfig);
4085 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4086
4087 $sequence = $testSequence->getUserSequenceQuestions();
4088 } else {
4089 $testSequence->setConsiderHiddenQuestionsEnabled($considerHiddenQuestions);
4090 $testSequence->setConsiderOptionalQuestionsEnabled($considerOptionalQuestions);
4091
4092 $testSequence->loadFromDb();
4093 $testSequence->loadQuestions();
4094
4095 if ($ordered_sequence) {
4096 $sequence = $testSequence->getOrderedSequenceQuestions();
4097 } else {
4098 $sequence = $testSequence->getUserSequenceQuestions();
4099 }
4100 }
4101
4102 $arrResults = array();
4103
4104 $query = "
4105 SELECT tst_test_result.question_fi,
4106 tst_test_result.points reached,
4107 tst_test_result.hint_count requested_hints,
4108 tst_test_result.hint_points hint_points,
4109 tst_test_result.answered answered
4110
4111 FROM tst_test_result
4112
4113 LEFT JOIN tst_solutions
4114 ON tst_solutions.active_fi = tst_test_result.active_fi
4115 AND tst_solutions.question_fi = tst_test_result.question_fi
4116
4117 WHERE tst_test_result.active_fi = %s
4118 AND tst_test_result.pass = %s
4119 ";
4120
4121 $solutionresult = $ilDB->queryF(
4122 $query,
4123 array('integer', 'integer'),
4124 array($active_id, $pass)
4125 );
4126
4127 while ($row = $ilDB->fetchAssoc($solutionresult)) {
4128 $arrResults[ $row['question_fi'] ] = $row;
4129 }
4130
4131 $numWorkedThrough = count($arrResults);
4132
4133 require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4134
4135 $IN_question_ids = $ilDB->in('qpl_questions.question_id', $sequence, false, 'integer');
4136
4137 $query = "
4138 SELECT qpl_questions.*,
4139 qpl_qst_type.type_tag,
4140 qpl_sol_sug.question_fi has_sug_sol
4141
4142 FROM qpl_qst_type,
4143 qpl_questions
4144
4145 LEFT JOIN qpl_sol_sug
4146 ON qpl_sol_sug.question_fi = qpl_questions.question_id
4147
4148 WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi
4149 AND $IN_question_ids
4150 ";
4151
4152 $result = $ilDB->query($query);
4153
4154 $unordered = array();
4155
4156 $key = 1;
4157
4158 $obligationsAnswered = true;
4159
4160 while ($row = $ilDB->fetchAssoc($result)) {
4161 $percentvalue = (
4162 $row['points'] ? $arrResults[ $row['question_id'] ]['reached'] / $row['points'] : 0
4163 );
4164
4165 if ($percentvalue < 0) {
4166 $percentvalue = 0.0;
4167 }
4168
4169 $data = array(
4170 "nr" => "$key",
4171 "title" => ilUtil::prepareFormOutput($row['title']),
4172 "max" => round($row['points'], 2),
4173 "reached" => round($arrResults[$row['question_id']]['reached'], 2),
4174 'requested_hints' => $arrResults[$row['question_id']]['requested_hints'],
4175 'hint_points' => $arrResults[$row['question_id']]['hint_points'],
4176 "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4177 "solution" => ($row['has_sug_sol']) ? assQuestion::_getSuggestedSolutionOutput($row['question_id']) : '',
4178 "type" => $row["type_tag"],
4179 "qid" => $row['question_id'],
4180 "original_id" => $row["original_id"],
4181 "workedthrough" => isset($arrResults[$row['question_id']]) ? 1 : 0,
4182 'answered' => $arrResults[$row['question_id']]['answered']
4183 );
4184
4185 if (!$arrResults[ $row['question_id'] ]['answered']) {
4186 $obligationsAnswered = false;
4187 }
4188
4189 $unordered[ $row['question_id'] ] = $data;
4190
4191 $key++;
4192 }
4193
4194 $numQuestionsTotal = count($unordered);
4195
4196 $pass_max = 0;
4197 $pass_reached = 0;
4198 $pass_requested_hints = 0;
4199 $pass_hint_points = 0;
4200 $key = 1;
4201
4202 $found = array();
4203
4204 foreach ($sequence as $qid) {
4205 // building pass point sums based on prepared data
4206 // for question that exists in users qst sequence
4207 $pass_max += round($unordered[$qid]['max'], 2);
4208 $pass_reached += round($unordered[$qid]['reached'], 2);
4209 $pass_requested_hints += $unordered[$qid]['requested_hints'];
4210 $pass_hint_points += $unordered[$qid]['hint_points'];
4211
4212 // pickup prepared data for question
4213 // that exists in users qst sequence
4214 $unordered[$qid]['nr'] = $key;
4215 array_push($found, $unordered[$qid]);
4216
4217 // increment key counter
4218 $key++;
4219 }
4220
4221 $unordered = null;
4222
4223 if ($this->getScoreCutting() == 1) {
4224 if ($results['reached_points'] < 0) {
4225 $results['reached_points'] = 0;
4226 }
4227
4228 if ($pass_reached < 0) {
4229 $pass_reached = 0;
4230 }
4231 }
4232
4233 $found['pass']['total_max_points'] = $pass_max;
4234 $found['pass']['total_reached_points'] = $pass_reached;
4235 $found['pass']['total_requested_hints'] = $pass_requested_hints;
4236 $found['pass']['total_hint_points'] = $pass_hint_points;
4237 $found['pass']['percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
4238 $found['pass']['obligationsAnswered'] = $obligationsAnswered;
4239 $found['pass']['num_workedthrough'] = $numWorkedThrough;
4240 $found['pass']['num_questions_total'] = $numQuestionsTotal;
4241
4242 $found["test"]["total_max_points"] = $results['max_points'];
4243 $found["test"]["total_reached_points"] = $results['reached_points'];
4244 $found["test"]["total_requested_hints"] = $results['hint_count'];
4245 $found["test"]["total_hint_points"] = $results['hint_points'];
4246 $found["test"]["result_pass"] = $results['pass'];
4247 $found['test']['result_tstamp'] = $results['tstamp'];
4248 $found['test']['obligations_answered'] = $results['obligations_answered'];
4249
4250 if ((!$total_reached_points) or (!$total_max_points)) {
4251 $percentage = 0.0;
4252 } else {
4253 $percentage = ($total_reached_points / $total_max_points) * 100.0;
4254
4255 if ($percentage < 0) {
4256 $percentage = 0.0;
4257 }
4258 }
4259
4260 $found["test"]["passed"] = $results['passed'];
4261
4262 return $found;
4263 }
4264
4271 public function evalTotalPersons()
4272 {
4273 global $DIC;
4274 $ilDB = $DIC['ilDB'];
4275
4276 $result = $ilDB->queryF(
4277 "SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
4278 array('integer'),
4279 array($this->getTestId())
4280 );
4281 $row = $ilDB->fetchAssoc($result);
4282 return $row["total"];
4283 }
4284
4291 public function getCompleteWorkingTime($user_id)
4292 {
4293 global $DIC;
4294 $ilDB = $DIC['ilDB'];
4295
4296 $result = $ilDB->queryF(
4297 "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",
4298 array('integer','integer'),
4299 array($this->getTestId(), $user_id)
4300 );
4301 $time = 0;
4302 while ($row = $ilDB->fetchAssoc($result)) {
4303 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4304 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4305 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4306 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4307 $time += ($epoch_2 - $epoch_1);
4308 }
4309 return $time;
4310 }
4311
4319 {
4320 return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4321 }
4322
4331 {
4332 global $DIC;
4333 $ilDB = $DIC['ilDB'];
4334
4335 $result = $ilDB->queryF(
4336 "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",
4337 array('integer'),
4338 array($test_id)
4339 );
4340 $time = 0;
4341 $times = array();
4342 while ($row = $ilDB->fetchAssoc($result)) {
4343 if (!array_key_exists($row["active_fi"], $times)) {
4344 $times[$row["active_fi"]] = 0;
4345 }
4346 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4347 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4348 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4349 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4350 $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4351 }
4352 return $times;
4353 }
4354
4361 public function getCompleteWorkingTimeOfParticipant($active_id)
4362 {
4363 global $DIC;
4364 $ilDB = $DIC['ilDB'];
4365
4366 $result = $ilDB->queryF(
4367 "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",
4368 array('integer','integer'),
4369 array($this->getTestId(), $active_id)
4370 );
4371 $time = 0;
4372 while ($row = $ilDB->fetchAssoc($result)) {
4373 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4374 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4375 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4376 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4377 $time += ($epoch_2 - $epoch_1);
4378 }
4379 return $time;
4380 }
4381
4388 public static function _getWorkingTimeOfParticipantForPass($active_id, $pass)
4389 {
4390 global $DIC;
4391 $ilDB = $DIC['ilDB'];
4392
4393 $result = $ilDB->queryF(
4394 "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4395 array('integer','integer'),
4396 array($active_id, $pass)
4397 );
4398 $time = 0;
4399 while ($row = $ilDB->fetchAssoc($result)) {
4400 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4401 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4402 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4403 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4404 $time += ($epoch_2 - $epoch_1);
4405 }
4406 return $time;
4407 }
4408
4416 public function getVisitTimeOfParticipant($active_id)
4417 {
4418 return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4419 }
4420
4429 public function _getVisitTimeOfParticipant($test_id, $active_id)
4430 {
4431 global $DIC;
4432 $ilDB = $DIC['ilDB'];
4433
4434 $result = $ilDB->queryF(
4435 "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",
4436 array('integer','integer'),
4437 array($test_id, $active_id)
4438 );
4439 $firstvisit = 0;
4440 $lastvisit = 0;
4441 while ($row = $ilDB->fetchAssoc($result)) {
4442 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4443 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4444 if ($firstvisit == 0 || $epoch_1 < $firstvisit) {
4445 $firstvisit = $epoch_1;
4446 }
4447 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4448 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4449 if ($epoch_2 > $lastvisit) {
4450 $lastvisit = $epoch_2;
4451 }
4452 }
4453 return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4454 }
4455
4462 public function &evalStatistical($active_id)
4463 {
4464 global $DIC;
4465 $ilDB = $DIC['ilDB'];
4466 // $ilBench = $DIC['ilBench'];
4467 $pass = ilObjTest::_getResultPass($active_id);
4468 $test_result = &$this->getTestResult($active_id, $pass);
4469 $result = $ilDB->queryF(
4470 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
4471 array('integer'),
4472 array($active_id)
4473 );
4474 $times = array();
4475 $first_visit = 0;
4476 $last_visit = 0;
4477 while ($row = $ilDB->fetchObject($result)) {
4478 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4479 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4480 if (!$first_visit) {
4481 $first_visit = $epoch_1;
4482 }
4483 if ($epoch_1 < $first_visit) {
4484 $first_visit = $epoch_1;
4485 }
4486 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4487 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4488 if (!$last_visit) {
4489 $last_visit = $epoch_2;
4490 }
4491 if ($epoch_2 > $last_visit) {
4492 $last_visit = $epoch_2;
4493 }
4494 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4495 }
4496 $max_time = 0;
4497 foreach ($times as $key => $value) {
4498 $max_time += $value;
4499 }
4500 if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"])) {
4501 $percentage = 0.0;
4502 } else {
4503 $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4504 if ($percentage < 0) {
4505 $percentage = 0.0;
4506 }
4507 }
4508 $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4509 $first_date = getdate($first_visit);
4510 $last_date = getdate($last_visit);
4511 $qworkedthrough = 0;
4512 foreach ($test_result as $key => $value) {
4513 if (preg_match("/\d+/", $key)) {
4514 $qworkedthrough += $value["workedthrough"];
4515 }
4516 }
4517 if (!$qworkedthrough) {
4518 $atimeofwork = 0;
4519 } else {
4520 $atimeofwork = $max_time / $qworkedthrough;
4521 }
4522
4523 $obligationsAnswered = $test_result["test"]["obligations_answered"];
4524
4525 $result_mark = "";
4526 $passed = "";
4527
4528 if ($mark_obj) {
4529 $result_mark = $mark_obj->getShortName();
4530
4531 if ($mark_obj->getPassed() && $obligationsAnswered) {
4532 $passed = 1;
4533 } else {
4534 $passed = 0;
4535 }
4536 }
4537 $percent_worked_through = 0;
4538 if (count($this->questions)) {
4539 $percent_worked_through = $qworkedthrough / count($this->questions);
4540 }
4541 $result_array = array(
4542 "qworkedthrough" => $qworkedthrough,
4543 "qmax" => count($this->questions),
4544 "pworkedthrough" => $percent_worked_through,
4545 "timeofwork" => $max_time,
4546 "atimeofwork" => $atimeofwork,
4547 "firstvisit" => $first_date,
4548 "lastvisit" => $last_date,
4549 "resultspoints" => $test_result["test"]["total_reached_points"],
4550 "maxpoints" => $test_result["test"]["total_max_points"],
4551 "resultsmarks" => $result_mark,
4552 "passed" => $passed,
4553 "distancemedian" => "0"
4554 );
4555 foreach ($test_result as $key => $value) {
4556 if (preg_match("/\d+/", $key)) {
4557 $result_array[$key] = $value;
4558 }
4559 }
4560 return $result_array;
4561 }
4562
4570 public function &getTotalPointsPassedArray()
4571 {
4572 $totalpoints_array = array();
4573 $all_users = &$this->evalTotalParticipantsArray();
4574 foreach ($all_users as $active_id => $user_name) {
4575 $test_result = &$this->getTestResult($active_id);
4576 $reached = $test_result["test"]["total_reached_points"];
4577 $total = $test_result["test"]["total_max_points"];
4578 $percentage = $total != 0 ? $reached / $total : 0;
4579 $mark = $this->mark_schema->getMatchingMark($percentage * 100.0);
4580
4581 $obligationsAnswered = $test_result["test"]["obligations_answered"];
4582
4583 if ($mark) {
4584 if ($mark->getPassed() && $obligationsAnswered) {
4585 array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4586 }
4587 }
4588 }
4589 return $totalpoints_array;
4590 }
4591
4597 public function &getParticipants()
4598 {
4599 global $DIC;
4600 $ilDB = $DIC['ilDB'];
4601 $result = $ilDB->queryF(
4602 "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",
4603 array('integer'),
4604 array($this->getTestId())
4605 );
4606 $persons_array = array();
4607 while ($row = $ilDB->fetchAssoc($result)) {
4608 $name = $this->lng->txt("anonymous");
4609 $fullname = $this->lng->txt("anonymous");
4610 $login = "";
4611 if (!$this->getAnonymity()) {
4612 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4613 $name = $this->lng->txt("deleted_user");
4614 $fullname = $this->lng->txt("deleted_user");
4615 $login = $this->lng->txt("unknown");
4616 } else {
4617 $login = $row["login"];
4618 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4619 $name = $this->lng->txt("anonymous");
4620 $fullname = $this->lng->txt("anonymous");
4621 } else {
4622 $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4623 $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4624 }
4625 }
4626 }
4627 $persons_array[$row["active_id"]] = array(
4628 "name" => $name,
4629 "fullname" => $fullname,
4630 "login" => $login
4631 );
4632 }
4633 return $persons_array;
4634 }
4635
4642 public function &evalTotalPersonsArray($name_sort_order = "asc")
4643 {
4644 global $DIC;
4645 $ilDB = $DIC['ilDB'];
4646 $result = $ilDB->queryF(
4647 "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),
4648 array('integer'),
4649 array($this->getTestId())
4650 );
4651 $persons_array = array();
4652 while ($row = $ilDB->fetchAssoc($result)) {
4653 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row["active_id"])) {
4654 continue;
4655 }
4656
4657 if ($this->getAnonymity()) {
4658 $persons_array[$row["active_id"]] = $this->lng->txt("anonymous");
4659 } else {
4660 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4661 $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4662 } else {
4663 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4664 $persons_array[$row["active_id"]] = $row["lastname"];
4665 } else {
4666 $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4667 }
4668 }
4669 }
4670 }
4671 return $persons_array;
4672 }
4673
4680 public function &evalTotalParticipantsArray($name_sort_order = "asc")
4681 {
4682 global $DIC;
4683 $ilDB = $DIC['ilDB'];
4684 $result = $ilDB->queryF(
4685 "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),
4686 array('integer'),
4687 array($this->getTestId())
4688 );
4689 $persons_array = array();
4690 while ($row = $ilDB->fetchAssoc($result)) {
4691 if ($this->getAnonymity()) {
4692 $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("anonymous"));
4693 } else {
4694 if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4695 $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4696 } else {
4697 if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4698 $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4699 } else {
4700 $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4701 }
4702 }
4703 }
4704 }
4705 return $persons_array;
4706 }
4707
4714 public function &getQuestionsOfTest($active_id)
4715 {
4716 global $DIC;
4717 $ilDB = $DIC['ilDB'];
4718 if ($this->isRandomTest()) {
4719 $ilDB->setLimit($this->getQuestionCount(), 0);
4720 $result = $ilDB->queryF(
4721 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4722 "tst_test_rnd_qst.pass, qpl_questions.points " .
4723 "FROM tst_test_rnd_qst, qpl_questions " .
4724 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4725 "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4726 array('integer'),
4727 array($active_id)
4728 );
4729 } else {
4730 $result = $ilDB->queryF(
4731 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4732 "qpl_questions.points " .
4733 "FROM tst_test_question, tst_active, qpl_questions " .
4734 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4735 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4736 array('integer'),
4737 array($active_id)
4738 );
4739 }
4740 $qtest = array();
4741 if ($result->numRows()) {
4742 while ($row = $ilDB->fetchAssoc($result)) {
4743 array_push($qtest, $row);
4744 }
4745 }
4746 return $qtest;
4747 }
4748
4755 public function &getQuestionsOfPass($active_id, $pass)
4756 {
4757 global $DIC;
4758 $ilDB = $DIC['ilDB'];
4759 if ($this->isRandomTest()) {
4760 $ilDB->setLimit($this->getQuestionCount(), 0);
4761 $result = $ilDB->queryF(
4762 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4763 "qpl_questions.points " .
4764 "FROM tst_test_rnd_qst, qpl_questions " .
4765 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4766 "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
4767 "ORDER BY tst_test_rnd_qst.sequence",
4768 array('integer', 'integer'),
4769 array($active_id, $pass)
4770 );
4771 } else {
4772 $result = $ilDB->queryF(
4773 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4774 "qpl_questions.points " .
4775 "FROM tst_test_question, tst_active, qpl_questions " .
4776 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4777 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4778 array('integer'),
4779 array($active_id)
4780 );
4781 }
4782 $qpass = array();
4783 if ($result->numRows()) {
4784 while ($row = $ilDB->fetchAssoc($result)) {
4785 array_push($qpass, $row);
4786 }
4787 }
4788 return $qpass;
4789 }
4790
4795
4800 {
4802 }
4803
4808 {
4809 $this->accessFilteredParticipantList = $accessFilteredParticipantList;
4810 }
4811
4816 {
4817 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
4818 require_once 'Modules/Test/classes/class.ilTestParticipantAccessFilter.php';
4819
4820 $list = new ilTestParticipantList($this);
4821 $list->initializeFromDbRows($this->getTestParticipants());
4822
4823 $list = $list->getAccessFilteredList(
4825 );
4826
4827 return $list;
4828 }
4829
4830 public function getUnfilteredEvaluationData()
4831 {
4833 global $DIC;
4834
4835 $ilDB = $DIC->database();
4836
4837 include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
4838 include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
4839 include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
4840
4841 $data = new ilTestEvaluationData($this);
4842
4843 $query = "
4844 SELECT tst_test_result.*,
4845 qpl_questions.original_id,
4846 qpl_questions.title questiontitle,
4847 qpl_questions.points maxpoints
4848
4849 FROM tst_test_result, qpl_questions, tst_active
4850
4851 WHERE tst_active.active_id = tst_test_result.active_fi
4852 AND qpl_questions.question_id = tst_test_result.question_fi
4853 AND tst_active.test_fi = %s
4854
4855 ORDER BY tst_active.active_id ASC, tst_test_result.pass ASC, tst_test_result.tstamp DESC
4856 ";
4857
4858 $result = $ilDB->queryF(
4859 $query,
4860 array('integer'),
4861 array($this->getTestId())
4862 );
4863
4864 $pass = null;
4865 $checked = array();
4866 $datasets = 0;
4867 $questionData = [];
4868
4869 while ($row = $ilDB->fetchAssoc($result)) {
4870 $participantObject = $data->getParticipant($row["active_fi"]);
4871
4872 if (!($participantObject instanceof ilTestEvaluationUserData)) {
4873 continue;
4874 }
4875
4876 $passObject = $participantObject->getPass($row["pass"]);
4877
4878 if (!($passObject instanceof ilTestEvaluationPassData)) {
4879 continue;
4880 }
4881
4882 $passObject->addAnsweredQuestion(
4883 $row["question_fi"],
4884 $row["maxpoints"],
4885 $row["points"],
4886 $row['answered'],
4887 null,
4888 $row['manual']
4889 );
4890 }
4891
4892 foreach (array_keys($data->getParticipants()) as $active_id) {
4893 if ($this->isRandomTest()) {
4894 for ($testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++) {
4895 $ilDB->setLimit($this->getQuestionCount(), 0);
4896
4897 $query = "
4898 SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, qpl_questions.original_id,
4899 tst_test_rnd_qst.pass, qpl_questions.points, qpl_questions.title
4900 FROM tst_test_rnd_qst, qpl_questions
4901 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
4902 AND tst_test_rnd_qst.pass = %s
4903 AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence
4904 ";
4905
4906 $result = $ilDB->queryF(
4907 $query,
4908 array('integer','integer'),
4909 array($testpass, $active_id)
4910 );
4911
4912 if ($result->numRows()) {
4913 while ($row = $ilDB->fetchAssoc($result)) {
4914 $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
4915
4916 $data->getParticipant($active_id)->addQuestion(
4917 $row["original_id"],
4918 $row["question_fi"],
4919 $row["points"],
4920 $row["sequence"],
4921 $tpass
4922 );
4923
4924 $data->addQuestionTitle($row["question_fi"], $row["title"]);
4925 }
4926 }
4927 }
4928 } elseif ($this->isDynamicTest()) {
4929 $lastPass = $data->getParticipant($active_id)->getLastPass();
4930 for ($testpass = 0; $testpass <= $lastPass; $testpass++) {
4931 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4932 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig(
4933 $DIC->repositoryTree(),
4934 $DIC->database(),
4935 $DIC['ilPluginAdmin'],
4936 $this
4937 );
4938 $dynamicQuestionSetConfig->loadFromDb();
4939
4940 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4941 $testSequenceFactory = new ilTestSequenceFactory($DIC->database(), $DIC->language(), $DIC['ilPluginAdmin'], $this);
4942 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $testpass);
4943
4944 $testSequence->loadFromDb($dynamicQuestionSetConfig);
4945 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4946
4947 $sequence = (array) $testSequence->getUserSequenceQuestions();
4948
4949 $questionsIdsToRequest = array_diff(array_values($sequence), array_values($questionData));
4950 if (count($questionsIdsToRequest) > 0) {
4951 $questionIdsCondition = ' ' . $DIC->database()->in('question_id', array_values($questionsIdsToRequest), false, 'integer') . ' ';
4952
4953 $res = $DIC->database()->queryF(
4954 "
4955 SELECT *
4956 FROM qpl_questions
4957 WHERE {$questionIdsCondition}",
4958 array('integer'),
4959 array($active_id)
4960 );
4961 while ($row = $DIC->database()->fetchAssoc($res)) {
4962 $questionData[$row['question_id']] = $row;
4963 $data->addQuestionTitle($row['question_id'], $row['title']);
4964 }
4965 }
4966
4967 foreach ($sequence as $questionId) {
4968 if (!isset($questionData[$questionId])) {
4969 continue;
4970 }
4971
4972 $row = $questionData[$questionId];
4973
4974 $data->getParticipant(
4975 $active_id
4976 )->addQuestion(
4977 $row['original_id'],
4978 $row['question_id'],
4979 $row['points'],
4980 null,
4981 $testpass
4982 );
4983 }
4984 }
4985 } else {
4986 $query = "
4987 SELECT tst_test_question.sequence, tst_test_question.question_fi,
4988 qpl_questions.points, qpl_questions.title, qpl_questions.original_id
4989 FROM tst_test_question, tst_active, qpl_questions
4990 WHERE tst_test_question.question_fi = qpl_questions.question_id
4991 AND tst_active.active_id = %s
4992 AND tst_active.test_fi = tst_test_question.test_fi
4993 ORDER BY tst_test_question.sequence
4994 ";
4995
4996 $result = $ilDB->queryF(
4997 $query,
4998 array('integer'),
4999 array($active_id)
5000 );
5001
5002 if ($result->numRows()) {
5003 $questionsbysequence = array();
5004
5005 while ($row = $ilDB->fetchAssoc($result)) {
5006 $questionsbysequence[$row["sequence"]] = $row;
5007 }
5008
5009 $seqresult = $ilDB->queryF(
5010 "SELECT * FROM tst_sequence WHERE active_fi = %s",
5011 array('integer'),
5012 array($active_id)
5013 );
5014
5015 while ($seqrow = $ilDB->fetchAssoc($seqresult)) {
5016 $questionsequence = unserialize($seqrow["sequence"]);
5017
5018 foreach ($questionsequence as $sidx => $seq) {
5019 $data->getParticipant($active_id)->addQuestion(
5020 $questionsbysequence[$seq]["original_id"],
5021 $questionsbysequence[$seq]["question_fi"],
5022 $questionsbysequence[$seq]["points"],
5023 $sidx + 1,
5024 $seqrow["pass"]
5025 );
5026
5027 $data->addQuestionTitle(
5028 $questionsbysequence[$seq]["question_fi"],
5029 $questionsbysequence[$seq]["title"]
5030 );
5031 }
5032 }
5033 }
5034 }
5035 }
5036
5037 if ($this->getECTSOutput()) {
5038 $passed_array = &$this->getTotalPointsPassedArray();
5039 }
5040
5041 foreach (array_keys($data->getParticipants()) as $active_id) {
5042 $tstUserData = $data->getParticipant($active_id);
5043
5044 $percentage = $tstUserData->getReachedPointsInPercent();
5045
5046 $obligationsAnswered = $tstUserData->areObligationsAnswered();
5047
5048 $mark = $this->mark_schema->getMatchingMark($percentage);
5049
5050 if (is_object($mark)) {
5051 $tstUserData->setMark($mark->getShortName());
5052 $tstUserData->setMarkOfficial($mark->getOfficialName());
5053
5054 $tstUserData->setPassed(
5055 $mark->getPassed() && $tstUserData->areObligationsAnswered()
5056 );
5057 }
5058
5059 if ($this->getECTSOutput()) {
5060 $ects_mark = $this->getECTSGrade(
5061 $passed_array,
5062 $tstUserData->getReached(),
5063 $tstUserData->getMaxPoints()
5064 );
5065
5066 $tstUserData->setECTSMark($ects_mark);
5067 }
5068
5069 $visitingTime = &$this->getVisitTimeOfParticipant($active_id);
5070
5071 $tstUserData->setFirstVisit($visitingTime["firstvisit"]);
5072 $tstUserData->setLastVisit($visitingTime["lastvisit"]);
5073 }
5074
5075 return $data;
5076 }
5077
5078 public static function _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
5079 {
5080 global $DIC;
5081 $ilDB = $DIC['ilDB'];
5082
5084
5085 switch ($questionSetType) {
5087
5088 $res = $ilDB->queryF(
5089 "
5090 SELECT COUNT(qpl_questions.question_id) qcount,
5091 SUM(qpl_questions.points) qsum
5092 FROM tst_active
5093 INNER JOIN tst_tests
5094 ON tst_tests.test_id = tst_active.test_fi
5095 INNER JOIN tst_dyn_quest_set_cfg
5096 ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
5097 INNER JOIN qpl_questions
5098 ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
5099 AND qpl_questions.original_id IS NULL
5100 AND qpl_questions.complete = %s
5101 WHERE tst_active.active_id = %s
5102 ",
5103 array('integer', 'integer'),
5104 array(1, $active_id)
5105 );
5106
5107 break;
5108
5110
5111 $res = $ilDB->queryF(
5112 "
5113 SELECT tst_test_rnd_qst.pass,
5114 COUNT(tst_test_rnd_qst.question_fi) qcount,
5115 SUM(qpl_questions.points) qsum
5116
5117 FROM tst_test_rnd_qst,
5118 qpl_questions
5119
5120 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
5121 AND tst_test_rnd_qst.active_fi = %s
5122 AND pass = %s
5123
5124 GROUP BY tst_test_rnd_qst.active_fi,
5125 tst_test_rnd_qst.pass
5126 ",
5127 array('integer', 'integer'),
5128 array($active_id, $pass)
5129 );
5130
5131 break;
5132
5134
5135 $res = $ilDB->queryF(
5136 "
5137 SELECT COUNT(tst_test_question.question_fi) qcount,
5138 SUM(qpl_questions.points) qsum
5139
5140 FROM tst_test_question,
5141 qpl_questions,
5142 tst_active
5143
5144 WHERE tst_test_question.question_fi = qpl_questions.question_id
5145 AND tst_test_question.test_fi = tst_active.test_fi
5146 AND tst_active.active_id = %s
5147
5148 GROUP BY tst_test_question.test_fi
5149 ",
5150 array('integer'),
5151 array($active_id)
5152 );
5153
5154 break;
5155
5156 default:
5157
5158 throw new ilTestException("not supported question set type: $questionSetType");
5159 }
5160
5161 $row = $ilDB->fetchAssoc($res);
5162
5163 if (is_array($row)) {
5164 return array("count" => $row["qcount"], "points" => $row["qsum"]);
5165 }
5166
5167 return array("count" => 0, "points" => 0);
5168 }
5169
5170 public function &getCompleteEvaluationData($withStatistics = true, $filterby = "", $filtertext = "")
5171 {
5172 include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5173 include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5174 include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5175 $data = $this->getUnfilteredEvaluationData();
5176 if ($withStatistics) {
5177 $data->calculateStatistics();
5178 }
5179 $data->setFilter($filterby, $filtertext);
5180 return $data;
5181 }
5182
5189 public function &evalResultsOverview()
5190 {
5191 return $this->_evalResultsOverview($this->getTestId());
5192 }
5193
5201 {
5202 global $DIC;
5203 $ilDB = $DIC['ilDB'];
5204
5205 $result = $ilDB->queryF(
5206 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5207 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5208 "qpl_questions.points maxpoints " .
5209 "FROM tst_test_result, qpl_questions, tst_active " .
5210 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5211 "WHERE tst_active.active_id = tst_test_result.active_fi " .
5212 "AND qpl_questions.question_id = tst_test_result.question_fi " .
5213 "AND tst_active.test_fi = %s " .
5214 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5215 array('integer'),
5216 array($test_id)
5217 );
5218 $overview = array();
5219 while ($row = $ilDB->fetchAssoc($result)) {
5220 if (!array_key_exists($row["active_fi"], $overview)) {
5221 $overview[$row["active_fi"]] = array();
5222 $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5223 $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5224 $overview[$row["active_fi"]]["title"] = $row["title"];
5225 $overview[$row["active_fi"]]["login"] = $row["login"];
5226 $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5227 $overview[$row["active_fi"]]["started"] = $row["started"];
5228 $overview[$row["active_fi"]]["finished"] = $row["finished"];
5229 }
5230 if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5231 $overview[$row["active_fi"]][$row["pass"]] = array();
5232 $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5233 $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5234 }
5235 array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5236 $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5237 }
5238 return $overview;
5239 }
5240
5248 public function &evalResultsOverviewOfParticipant($active_id)
5249 {
5250 global $DIC;
5251 $ilDB = $DIC['ilDB'];
5252
5253 $result = $ilDB->queryF(
5254 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5255 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5256 "qpl_questions.points maxpoints " .
5257 "FROM tst_test_result, qpl_questions, tst_active " .
5258 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5259 "WHERE tst_active.active_id = tst_test_result.active_fi " .
5260 "AND qpl_questions.question_id = tst_test_result.question_fi " .
5261 "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5262 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5263 array('integer', 'integer'),
5264 array($this->getTestId(), $active_id)
5265 );
5266 $overview = array();
5267 while ($row = $ilDB->fetchAssoc($result)) {
5268 if (!array_key_exists($row["active_fi"], $overview)) {
5269 $overview[$row["active_fi"]] = array();
5270 $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5271 $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5272 $overview[$row["active_fi"]]["title"] = $row["title"];
5273 $overview[$row["active_fi"]]["login"] = $row["login"];
5274 $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5275 $overview[$row["active_fi"]]["started"] = $row["started"];
5276 $overview[$row["active_fi"]]["finished"] = $row["finished"];
5277 }
5278 if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5279 $overview[$row["active_fi"]][$row["pass"]] = array();
5280 $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5281 $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5282 }
5283 array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5284 $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5285 }
5286 return $overview;
5287 }
5288
5300 public function buildName($user_id, $firstname, $lastname, $title)
5301 {
5302 $name = "";
5303 if (strlen($firstname . $lastname . $title) == 0) {
5304 $name = $this->lng->txt("deleted_user");
5305 } else {
5306 if ($user_id == ANONYMOUS_USER_ID) {
5307 $name = $lastname;
5308 } else {
5309 $name = trim($lastname . ", " . $firstname . " " . $title);
5310 }
5311 if ($this->getAnonymity()) {
5312 $name = $this->lng->txt("anonymous");
5313 }
5314 }
5315 return $name;
5316 }
5317
5330 public function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5331 {
5332 global $DIC;
5333 $lng = $DIC['lng'];
5334 $name = "";
5335 if (strlen($firstname . $lastname . $title) == 0) {
5336 $name = $lng->txt("deleted_user");
5337 } else {
5338 if ($user_id == ANONYMOUS_USER_ID) {
5339 $name = $lastname;
5340 } else {
5341 $name = trim($lastname . ", " . $firstname . " " . $title);
5342 }
5343 if ($is_anonymous) {
5344 $name = $lng->txt("anonymous");
5345 }
5346 }
5347 return $name;
5348 }
5349
5356 public function evalTotalStartedAverageTime($activeIdsFilter = null)
5357 {
5358 global $DIC; /* @var ILIAS\DI\Container $DIC */
5359
5360 $query = "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
5361
5362 if (is_array($activeIdsFilter) && count($activeIdsFilter)) {
5363 $query .= " AND " . $DIC->database()->in('active_id', $activeIdsFilter, false, 'integer');
5364 }
5365
5366 $result = $DIC->database()->queryF($query, array('integer'), array($this->getTestId()));
5367 $times = array();
5368 while ($row = $DIC->database()->fetchObject($result)) {
5369 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5370 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5371 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5372 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5373 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5374 }
5375 $max_time = 0;
5376 $counter = 0;
5377 foreach ($times as $key => $value) {
5378 $max_time += $value;
5379 $counter++;
5380 }
5381 if ($counter) {
5382 $average_time = round($max_time / $counter);
5383 } else {
5384 $average_time = 0;
5385 }
5386 return $average_time;
5387 }
5388
5395 public function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = false, $with_questioncount = false, $permission = "read")
5396 {
5397 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5398 return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5399 }
5400
5407 public function getEstimatedWorkingTime()
5408 {
5409 $time_in_seconds = 0;
5410 foreach ($this->questions as $question_id) {
5411 $question = &ilObjTest::_instanciateQuestion($question_id);
5412 $est_time = $question->getEstimatedWorkingTime();
5413 $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5414 }
5415 $hours = (int) ($time_in_seconds / 3600) ;
5416 $time_in_seconds = $time_in_seconds - ($hours * 3600);
5417 $minutes = (int) ($time_in_seconds / 60);
5418 $time_in_seconds = $time_in_seconds - ($minutes * 60);
5419 $result = array("hh" => $hours, "mm" => $minutes, "ss" => $time_in_seconds);
5420 return $result;
5421 }
5422
5429 public function getImagePath()
5430 {
5431 return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5432 }
5433
5440 public function getImagePathWeb()
5441 {
5442 include_once "./Services/Utilities/classes/class.ilUtil.php";
5443 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
5444 return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir);
5445 }
5446
5455 public function &createQuestionGUI($question_type, $question_id = -1)
5456 {
5457 if ((!$question_type) and ($question_id > 0)) {
5458 $question_type = $this->getQuestionType($question_id);
5459 }
5460
5461 if (!strlen($question_type)) {
5462 return null;
5463 }
5464
5465 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5466 assQuestion::_includeClass($question_type, 1);
5467
5468 $question_type_gui = assQuestion::getGuiClassNameByQuestionType($question_type);
5469 $question = new $question_type_gui();
5470
5471 if ($question_id > 0) {
5472 $question->object->loadFromDb($question_id);
5473
5474 global $DIC;
5475 $ilCtrl = $DIC['ilCtrl'];
5476 $ilDB = $DIC['ilDB'];
5477 $ilUser = $DIC['ilUser'];
5478 $lng = $DIC['lng'];
5479
5480 $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
5481 $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
5482
5483 $assSettings = new ilSetting('assessment');
5484 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
5485 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
5486 $processLockerFactory->setQuestionId($question->object->getId());
5487 $processLockerFactory->setUserId($ilUser->getId());
5488 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
5489 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
5490 $question->object->setProcessLocker($processLockerFactory->getLocker());
5491 }
5492
5493 return $question;
5494 }
5495
5505 public static function _instanciateQuestion($question_id)
5506 {
5507 if (strcmp($question_id, "") != 0) {
5508 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5509 return assQuestion::_instanciateQuestion($question_id);
5510 }
5511 }
5512
5521 public function moveQuestions($move_questions, $target_index, $insert_mode)
5522 {
5523 $this->questions = array_values($this->questions);
5524 $array_pos = array_search($target_index, $this->questions);
5525 if ($insert_mode == 0) {
5526 $part1 = array_slice($this->questions, 0, $array_pos);
5527 $part2 = array_slice($this->questions, $array_pos);
5528 } elseif ($insert_mode == 1) {
5529 $part1 = array_slice($this->questions, 0, $array_pos + 1);
5530 $part2 = array_slice($this->questions, $array_pos + 1);
5531 }
5532 foreach ($move_questions as $question_id) {
5533 if (!(array_search($question_id, $part1) === false)) {
5534 unset($part1[array_search($question_id, $part1)]);
5535 }
5536 if (!(array_search($question_id, $part2) === false)) {
5537 unset($part2[array_search($question_id, $part2)]);
5538 }
5539 }
5540 $part1 = array_values($part1);
5541 $part2 = array_values($part2);
5542 $new_array = array_values(array_merge($part1, $move_questions, $part2));
5543 $this->questions = array();
5544 $counter = 1;
5545 foreach ($new_array as $question_id) {
5546 $this->questions[$counter] = $question_id;
5547 $counter++;
5548 }
5549 $this->saveQuestionsToDb();
5550 }
5551
5552
5560 public function startingTimeReached()
5561 {
5562 if ($this->isStartingTimeEnabled() && $this->getStartingTime() != 0) {
5563 $now = time();
5564 if ($now < $this->getStartingTime()) {
5565 return false;
5566 }
5567 }
5568 return true;
5569 }
5570
5578 public function endingTimeReached()
5579 {
5580 if ($this->isEndingTimeEnabled() && $this->getEndingTime() != 0) {
5581 $now = time();
5582 if ($now > $this->getEndingTime()) {
5583 return true;
5584 }
5585 }
5586 return false;
5587 }
5588
5594 public function getAvailableQuestions($arrFilter, $completeonly = 0)
5595 {
5596 global $DIC;
5597 $pluginAdmin = $DIC['ilPluginAdmin'];
5598 $lng = $DIC['lng'];
5599 $ilUser = $DIC['ilUser'];
5600 $ilDB = $DIC['ilDB'];
5601
5602 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5603 $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = true, $equal_points = false, $could_be_offline = false, $showPath = false, $with_questioncount = false));
5604 $available = "";
5605 if (count($available_pools)) {
5606 $available = " AND " . $ilDB->in('qpl_questions.obj_fi', $available_pools, false, 'integer');
5607 } else {
5608 return array();
5609 }
5610 if ($completeonly) {
5611 $available .= " AND qpl_questions.complete = " . $ilDB->quote("1", 'text');
5612 }
5613
5614 $where = "";
5615 if (is_array($arrFilter)) {
5616 if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title'])) {
5617 $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
5618 }
5619 if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description'])) {
5620 $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
5621 }
5622 if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author'])) {
5623 $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
5624 }
5625 if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type'])) {
5626 $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
5627 }
5628 if (array_key_exists('qpl', $arrFilter) && strlen($arrFilter['qpl'])) {
5629 $where .= " AND " . $ilDB->like('object_data.title', 'text', "%%" . $arrFilter['qpl'] . "%%");
5630 }
5631 }
5632
5633 $original_ids = &$this->getExistingQuestions();
5634 $original_clause = " qpl_questions.original_id IS NULL";
5635 if (count($original_ids)) {
5636 $original_clause = " qpl_questions.original_id IS NULL AND " . $ilDB->in('qpl_questions.question_id', $original_ids, true, 'integer');
5637 }
5638
5639 $query_result = $ilDB->query("
5640 SELECT qpl_questions.*, qpl_questions.tstamp,
5641 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,
5642 object_data.title parent_title
5643 FROM qpl_questions, qpl_qst_type, object_data
5644 WHERE $original_clause $available
5645 AND object_data.obj_id = qpl_questions.obj_fi
5646 AND qpl_questions.tstamp > 0
5647 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
5648 $where
5649 ");
5650 $rows = array();
5651 $types = $this->getQuestionTypeTranslations();
5652 if ($query_result->numRows()) {
5653 while ($row = $ilDB->fetchAssoc($query_result)) {
5655
5656 if (!$row['plugin']) {
5657 $row[ 'ttype' ] = $lng->txt($row[ "type_tag" ]);
5658
5659 $rows[] = $row;
5660 continue;
5661 }
5662
5663 if (!$pluginAdmin->isActive(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name'])) {
5664 continue;
5665 }
5666
5667 $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name']);
5668 $row[ 'ttype' ] = $pl->getQuestionTypeTranslation();
5669
5670 $rows[] = $row;
5671 }
5672 }
5673 return $rows;
5674 }
5675
5680 public function fromXML(ilQTIAssessment $assessment)
5681 {
5682 unset($_SESSION["import_mob_xhtml"]);
5683
5684 $this->setDescription($assessment->getComment());
5685 $this->setTitle($assessment->getTitle());
5686
5687 $this->setIntroductionEnabled(false);
5688 foreach ($assessment->objectives as $objectives) {
5689 foreach ($objectives->materials as $material) {
5690 $intro = $this->QTIMaterialToString($material);
5691 $this->setIntroduction($intro);
5692 $this->setIntroductionEnabled(strlen($intro) > 0);
5693 }
5694 }
5695
5696 if (
5697 $assessment->getPresentationMaterial() &&
5698 $assessment->getPresentationMaterial()->getFlowMat(0) &&
5699 $assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)
5700 ) {
5701 $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)));
5702 }
5703
5704 foreach ($assessment->assessmentcontrol as $assessmentcontrol) {
5705 switch ($assessmentcontrol->getSolutionswitch()) {
5706 case "Yes":
5708 break;
5709 default:
5711 break;
5712 }
5713 }
5714
5715 $this->setStartingTimeEnabled(false);
5716 $this->setEndingTimeEnabled(false);
5717 $this->setPasswordEnabled(false);
5718 $this->setLimitUsersEnabled(false);
5719
5720 foreach ($assessment->qtimetadata as $metadata) {
5721 switch ($metadata["label"]) {
5722 case "test_type":
5723 // for old tests with a test type
5724 $type = $metadata["entry"];
5725 switch ($type) {
5726 case 1:
5727 // assessment
5728 $this->setAnonymity(1);
5729 break;
5730 case 2:
5731 // self assessment
5732 break;
5733 case 4:
5734 // online exam
5735 $this->setFixedParticipants(1);
5737 $this->setShowSolutionPrintview(1);
5738 break;
5739 case 5:
5740 // varying random test
5741 break;
5742 }
5743 break;
5744 case "sequence_settings":
5745 $this->setSequenceSettings($metadata["entry"]);
5746 break;
5747 case "solution_details":
5748 $this->setShowSolutionDetails((int) $metadata["entry"]);
5749 break;
5750 case "print_bs_with_res":
5751 $this->setPrintBestSolutionWithResult((int) $metadata["entry"]);
5752 break;
5753 case "author":
5754 $this->setAuthor($metadata["entry"]);
5755 break;
5756 case "nr_of_tries":
5757 $this->setNrOfTries($metadata["entry"]);
5758 break;
5759 case "pass_waiting":
5760 $this->setPassWaiting($metadata["entry"]);
5761 break;
5762 case "kiosk":
5763 $this->setKiosk($metadata["entry"]);
5764 break;
5765 case "showfinalstatement":
5766 $this->setShowFinalStatement($metadata["entry"]);
5767 break;
5768 case "showinfo":
5769 $this->setShowInfo($metadata["entry"]);
5770 break;
5771 case "forcejs":
5772 $this->setForceJS($metadata["entry"]);
5773 break;
5774 case "customstyle":
5775 $this->setCustomStyle($metadata["entry"]);
5776 break;
5777
5778 case "highscore_enabled":
5779 $this->setHighscoreEnabled($metadata["entry"]);
5780 break;
5781
5782 case "highscore_anon":
5783 $this->setHighscoreAnon($metadata["entry"]);
5784 break;
5785
5786 case "highscore_achieved_ts":
5787 $this->setHighscoreAchievedTS($metadata["entry"]);
5788 break;
5789
5790 case "highscore_score":
5791 $this->setHighscoreScore($metadata["entry"]);
5792 break;
5793
5794 case "highscore_percentage":
5795 $this->setHighscorePercentage($metadata["entry"]);
5796 break;
5797
5798 case "highscore_hints":
5799 $this->setHighscoreHints($metadata["entry"]);
5800 break;
5801
5802 case "highscore_wtime":
5803 $this->setHighscoreWTime($metadata["entry"]);
5804 break;
5805
5806 case "highscore_own_table":
5807 $this->setHighscoreOwnTable($metadata["entry"]);
5808 break;
5809
5810 case "highscore_top_table":
5811 $this->setHighscoreTopTable($metadata["entry"]);
5812 break;
5813
5814 case "highscore_top_num":
5815 $this->setHighscoreTopNum($metadata["entry"]);
5816 break;
5817
5818 case "hide_previous_results":
5819 if ($metadata["entry"] == 0) {
5820 $this->setUsePreviousAnswers(1);
5821 } else {
5822 $this->setUsePreviousAnswers(0);
5823 }
5824 break;
5825 case "use_previous_answers":
5826 $this->setUsePreviousAnswers($metadata["entry"]);
5827 break;
5828 case "answer_feedback":
5829 $this->setAnswerFeedback($metadata["entry"]);
5830 break;
5831 case "hide_title_points":
5832 $this->setTitleOutput($metadata["entry"]);
5833 break;
5834 case "title_output":
5835 $this->setTitleOutput($metadata["entry"]);
5836 break;
5837 case "question_set_type":
5838 $this->setQuestionSetType($metadata["entry"]);
5839 break;
5840 case "random_test":
5841 if ($metadata["entry"]) {
5842 $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
5843 } else {
5844 $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
5845 }
5846 break;
5847 case "results_presentation":
5848 $this->setResultsPresentation($metadata["entry"]);
5849 break;
5850 case "reset_processing_time":
5851 $this->setResetProcessingTime($metadata["entry"]);
5852 break;
5853 case "instant_verification":
5854 $this->setInstantFeedbackSolution($metadata["entry"]);
5855 break;
5856 case "follow_qst_answer_fixation":
5857 $this->setFollowupQuestionAnswerFixationEnabled((bool) $metadata["entry"]);
5858 break;
5859 case "instant_feedback_answer_fixation":
5860 $this->setInstantFeedbackAnswerFixationEnabled((bool) $metadata["entry"]);
5861 break;
5862 case "force_instant_feedback":
5863 $this->setForceInstantFeedbackEnabled((bool) $metadata["entry"]);
5864 break;
5865 case "answer_feedback_points":
5866 $this->setAnswerFeedbackPoints($metadata["entry"]);
5867 break;
5868 case "anonymity":
5869 $this->setAnonymity($metadata["entry"]);
5870 break;
5871 case "use_pool":
5872 $this->setPoolUsage((int) $metadata["entry"]);
5873 break;
5874 case "show_cancel":
5875 $this->setShowCancel($metadata["entry"]);
5876 break;
5877 case "show_marker":
5878 $this->setShowMarker($metadata["entry"]);
5879 break;
5880 case "fixed_participants":
5881 $this->setFixedParticipants($metadata["entry"]);
5882 break;
5883 case "score_reporting":
5884 $this->setScoreReporting($metadata["entry"]);
5885 break;
5886 case "shuffle_questions":
5887 $this->setShuffleQuestions($metadata["entry"]);
5888 break;
5889 case "count_system":
5890 $this->setCountSystem($metadata["entry"]);
5891 break;
5892 case "mc_scoring":
5893 $this->setMCScoring($metadata["entry"]);
5894 break;
5895 case "mailnotification":
5896 $this->setMailNotification($metadata["entry"]);
5897 break;
5898 case "mailnottype":
5899 $this->setMailNotificationType($metadata["entry"]);
5900 break;
5901 case "exportsettings":
5902 $this->setExportSettings($metadata['entry']);
5903 break;
5904 case "score_cutting":
5905 $this->setScoreCutting($metadata["entry"]);
5906 break;
5907 case "password":
5908 $this->setPassword($metadata["entry"]);
5909 $this->setPasswordEnabled(strlen($metadata["entry"]) > 0);
5910 break;
5911 case "allowedUsers":
5912 $this->setAllowedUsers($metadata["entry"]);
5913 $this->setLimitUsersEnabled((int) $metadata["entry"] > 0);
5914 break;
5915 case "allowedUsersTimeGap":
5916 $this->setAllowedUsersTimeGap($metadata["entry"]);
5917 break;
5918 case "pass_scoring":
5919 $this->setPassScoring($metadata["entry"]);
5920 break;
5921 case 'pass_deletion_allowed':
5922 $this->setPassDeletionAllowed((int) $metadata['entry']);
5923 break;
5924 case "show_summary":
5925 $this->setListOfQuestionsSettings($metadata["entry"]);
5926 break;
5927 case "reporting_date":
5928 $iso8601period = $metadata["entry"];
5929 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5930 $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
5931 }
5932 break;
5933 case 'enable_processing_time':
5934 $this->setEnableProcessingTime($metadata['entry']);
5935 break;
5936 case "processing_time":
5937 $this->setProcessingTime($metadata['entry']);
5938 break;
5939 case "starting_time":
5940 $iso8601period = $metadata["entry"];
5941 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5942 $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);
5943 $this->setStartingTime($date_time->get(IL_CAL_UNIX));
5944 $this->setStartingTimeEnabled(true);
5945 }
5946 break;
5947 case "ending_time":
5948 $iso8601period = $metadata["entry"];
5949 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5950 $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);
5951 $this->setEndingTime($date_time->get(IL_CAL_UNIX));
5952 $this->setEndingTimeEnabled(true);
5953 }
5954 break;
5955 case "enable_examview":
5956 $this->setEnableExamview($metadata["entry"]);
5957 break;
5958 case 'show_examview_html':
5959 $this->setShowExamviewHtml($metadata['entry']);
5960 break;
5961 case 'show_examview_pdf':
5962 $this->setShowExamviewPdf($metadata['entry']);
5963 break;
5964 case 'redirection_mode':
5965 $this->setRedirectionMode($metadata['entry']);
5966 break;
5967 case 'redirection_url':
5968 $this->setRedirectionUrl($metadata['entry']);
5969 break;
5970 case 'examid_in_kiosk':
5971 case 'examid_in_test_pass':
5972 $this->setShowExamIdInTestPassEnabled($metadata['entry']);
5973 break;
5974 case 'show_exam_id':
5975 case 'examid_in_test_res':
5976 $this->setShowExamIdInTestResultsEnabled($metadata['entry']);
5977 break;
5978 case 'enable_archiving':
5979 $this->setEnableArchiving($metadata['entry']);
5980 break;
5981 case 'sign_submission':
5982 $this->setSignSubmission($metadata['entry']);
5983 break;
5984 case 'char_selector_availability':
5985 $this->setCharSelectorAvailability($metadata['entry']);
5986 break;
5987 case 'char_selector_definition':
5988 $this->setCharSelectorDefinition($metadata['entry']);
5989 break;
5990 case 'skill_service':
5991 $this->setSkillServiceEnabled((bool) $metadata['entry']);
5992 break;
5993 case 'result_tax_filters':
5994 $this->setResultFilterTaxIds(strlen($metadata['entry']) ? unserialize($metadata['entry']) : array());
5995 break;
5996 case 'show_grading_status':
5997 $this->setShowGradingStatusEnabled((bool) $metadata['entry']);
5998 break;
5999 case 'show_grading_mark':
6000 $this->setShowGradingMarkEnabled((bool) $metadata['entry']);
6001 break;
6002 case 'activation_limited':
6003 $this->setActivationLimited($metadata['entry']);
6004 break;
6005 case 'activation_start_time':
6006 $this->setActivationStartingTime($metadata['entry']);
6007 break;
6008 case 'activation_end_time':
6009 $this->setActivationEndingTime($metadata['entry']);
6010 break;
6011 case 'activation_visibility':
6012 $this->setActivationVisibility($metadata['entry']);
6013 break;
6014 case 'autosave':
6015 $this->setAutosave($metadata['entry']);
6016 break;
6017 case 'autosave_ival':
6018 $this->setAutosaveIval($metadata['entry']);
6019 break;
6020 case 'offer_question_hints':
6021 $this->setOfferingQuestionHintsEnabled($metadata['entry']);
6022 break;
6023 case 'instant_feedback_specific':
6024 $this->setSpecificAnswerFeedback($metadata['entry']);
6025 break;
6026 case 'obligations_enabled':
6027 $this->setObligationsEnabled($metadata['entry']);
6028 break;
6029 }
6030 if (preg_match("/mark_step_\d+/", $metadata["label"])) {
6031 $xmlmark = $metadata["entry"];
6032 preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
6033 $mark_short = $matches[1];
6034 preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
6035 $mark_official = $matches[1];
6036 preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
6037 $mark_percentage = $matches[1];
6038 preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
6039 $mark_passed = $matches[1];
6040 $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
6041 }
6042 }
6043 // handle the import of media objects in XHTML code
6044 if (is_array($_SESSION["import_mob_xhtml"])) {
6045 include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6046 include_once "./Services/RTE/classes/class.ilRTE.php";
6047 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
6048 foreach ($_SESSION["import_mob_xhtml"] as $mob) {
6049 $importfile = ilObjTest::_getImportDirectory() . '/' . $_SESSION["tst_import_subdir"] . '/' . $mob["uri"];
6050 if (file_exists($importfile)) {
6051 $media_object = &ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false);
6052 ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
6053 $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
6054 $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
6055 } else {
6056 global $DIC;
6057 $ilLog = $DIC['ilLog'];
6058 $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
6059 }
6060 }
6061 $this->saveToDb();
6062 }
6063 }
6064
6070 public function toXML()
6071 {
6072 include_once("./Services/Xml/classes/class.ilXmlWriter.php");
6073 $a_xml_writer = new ilXmlWriter;
6074 // set xml header
6075 $a_xml_writer->xmlHeader();
6076 $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
6077 $a_xml_writer->xmlStartTag("questestinterop");
6078
6079 $attrs = array(
6080 "ident" => "il_" . IL_INST_ID . "_tst_" . $this->getTestId(),
6081 "title" => $this->getTitle()
6082 );
6083 $a_xml_writer->xmlStartTag("assessment", $attrs);
6084 // add qti comment
6085 $a_xml_writer->xmlElement("qticomment", null, $this->getDescription());
6086
6087 // add qti duration
6088 if ($this->enable_processing_time) {
6089 preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
6090 $a_xml_writer->xmlElement("duration", null, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
6091 }
6092
6093 // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
6094 $a_xml_writer->xmlStartTag("qtimetadata");
6095 $a_xml_writer->xmlStartTag("qtimetadatafield");
6096 $a_xml_writer->xmlElement("fieldlabel", null, "ILIAS_VERSION");
6097 $a_xml_writer->xmlElement("fieldentry", null, $this->ilias->getSetting("ilias_version"));
6098 $a_xml_writer->xmlEndTag("qtimetadatafield");
6099
6100 // anonymity
6101 $a_xml_writer->xmlStartTag("qtimetadatafield");
6102 $a_xml_writer->xmlElement("fieldlabel", null, "anonymity");
6103 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnonymity()));
6104 $a_xml_writer->xmlEndTag("qtimetadatafield");
6105
6106 $a_xml_writer->xmlStartTag("qtimetadatafield");
6107 $a_xml_writer->xmlElement("fieldlabel", null, "use_pool");
6108 $a_xml_writer->xmlElement("fieldentry", null, $this->getPoolUsage() ? 1 : 0);
6109 $a_xml_writer->xmlEndTag("qtimetadatafield");
6110
6111 // question set type (fixed, random, dynamic, ...)
6112 $a_xml_writer->xmlStartTag("qtimetadatafield");
6113 $a_xml_writer->xmlElement("fieldlabel", null, "question_set_type");
6114 $a_xml_writer->xmlElement("fieldentry", null, $this->getQuestionSetType());
6115 $a_xml_writer->xmlEndTag("qtimetadatafield");
6116
6117 // sequence settings
6118 $a_xml_writer->xmlStartTag("qtimetadatafield");
6119 $a_xml_writer->xmlElement("fieldlabel", null, "sequence_settings");
6120 $a_xml_writer->xmlElement("fieldentry", null, $this->getSequenceSettings());
6121 $a_xml_writer->xmlEndTag("qtimetadatafield");
6122
6123 // author
6124 $a_xml_writer->xmlStartTag("qtimetadatafield");
6125 $a_xml_writer->xmlElement("fieldlabel", null, "author");
6126 $a_xml_writer->xmlElement("fieldentry", null, $this->getAuthor());
6127 $a_xml_writer->xmlEndTag("qtimetadatafield");
6128
6129 // reset processing time
6130 $a_xml_writer->xmlStartTag("qtimetadatafield");
6131 $a_xml_writer->xmlElement("fieldlabel", null, "reset_processing_time");
6132 $a_xml_writer->xmlElement("fieldentry", null, $this->getResetProcessingTime());
6133 $a_xml_writer->xmlEndTag("qtimetadatafield");
6134
6135 // count system
6136 $a_xml_writer->xmlStartTag("qtimetadatafield");
6137 $a_xml_writer->xmlElement("fieldlabel", null, "count_system");
6138 $a_xml_writer->xmlElement("fieldentry", null, $this->getCountSystem());
6139 $a_xml_writer->xmlEndTag("qtimetadatafield");
6140
6141 // multiple choice scoring
6142 $a_xml_writer->xmlStartTag("qtimetadatafield");
6143 $a_xml_writer->xmlElement("fieldlabel", null, "mc_scoring");
6144 $a_xml_writer->xmlElement("fieldentry", null, $this->getMCScoring());
6145 $a_xml_writer->xmlEndTag("qtimetadatafield");
6146
6147 // multiple choice scoring
6148 $a_xml_writer->xmlStartTag("qtimetadatafield");
6149 $a_xml_writer->xmlElement("fieldlabel", null, "score_cutting");
6150 $a_xml_writer->xmlElement("fieldentry", null, $this->getScoreCutting());
6151 $a_xml_writer->xmlEndTag("qtimetadatafield");
6152
6153 // multiple choice scoring
6154 $a_xml_writer->xmlStartTag("qtimetadatafield");
6155 $a_xml_writer->xmlElement("fieldlabel", null, "password");
6156 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassword());
6157 $a_xml_writer->xmlEndTag("qtimetadatafield");
6158
6159 // allowed users
6160 $a_xml_writer->xmlStartTag("qtimetadatafield");
6161 $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsers");
6162 $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsers());
6163 $a_xml_writer->xmlEndTag("qtimetadatafield");
6164
6165 // allowed users time gap
6166 $a_xml_writer->xmlStartTag("qtimetadatafield");
6167 $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsersTimeGap");
6168 $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsersTimeGap());
6169 $a_xml_writer->xmlEndTag("qtimetadatafield");
6170
6171 // pass scoring
6172 $a_xml_writer->xmlStartTag("qtimetadatafield");
6173 $a_xml_writer->xmlElement("fieldlabel", null, "pass_scoring");
6174 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassScoring());
6175 $a_xml_writer->xmlEndTag("qtimetadatafield");
6176
6177 $a_xml_writer->xmlStartTag('qtimetadatafield');
6178 $a_xml_writer->xmlElement('fieldlabel', null, 'pass_deletion_allowed');
6179 $a_xml_writer->xmlElement('fieldentry', null, (int) $this->isPassDeletionAllowed());
6180 $a_xml_writer->xmlEndTag('qtimetadatafield');
6181
6182 // score reporting date
6183 if ($this->getReportingDate()) {
6184 $a_xml_writer->xmlStartTag("qtimetadatafield");
6185 $a_xml_writer->xmlElement("fieldlabel", null, "reporting_date");
6186 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6187 $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]));
6188 $a_xml_writer->xmlEndTag("qtimetadatafield");
6189 }
6190 // number of tries
6191 $a_xml_writer->xmlStartTag("qtimetadatafield");
6192 $a_xml_writer->xmlElement("fieldlabel", null, "nr_of_tries");
6193 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getNrOfTries()));
6194 $a_xml_writer->xmlEndTag("qtimetadatafield");
6195
6196 // pass_waiting
6197 $a_xml_writer->xmlStartTag("qtimetadatafield");
6198 $a_xml_writer->xmlElement("fieldlabel", null, "pass_waiting");
6199 $a_xml_writer->xmlElement("fieldentry", null, $this->getPassWaiting());
6200 $a_xml_writer->xmlEndTag("qtimetadatafield");
6201
6202 // kiosk
6203 $a_xml_writer->xmlStartTag("qtimetadatafield");
6204 $a_xml_writer->xmlElement("fieldlabel", null, "kiosk");
6205 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getKiosk()));
6206 $a_xml_writer->xmlEndTag("qtimetadatafield");
6207
6208
6209 //redirection_mode
6210 $a_xml_writer->xmlStartTag('qtimetadatafield');
6211 $a_xml_writer->xmlElement("fieldlabel", null, "redirection_mode");
6212 $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionMode());
6213 $a_xml_writer->xmlEndTag("qtimetadatafield");
6214
6215 //redirection_url
6216 $a_xml_writer->xmlStartTag('qtimetadatafield');
6217 $a_xml_writer->xmlElement("fieldlabel", null, "redirection_url");
6218 $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionUrl());
6219 $a_xml_writer->xmlEndTag("qtimetadatafield");
6220
6221 // use previous answers
6222 $a_xml_writer->xmlStartTag("qtimetadatafield");
6223 $a_xml_writer->xmlElement("fieldlabel", null, "use_previous_answers");
6224 $a_xml_writer->xmlElement("fieldentry", null, $this->getUsePreviousAnswers());
6225 $a_xml_writer->xmlEndTag("qtimetadatafield");
6226
6227 // hide title points
6228 $a_xml_writer->xmlStartTag("qtimetadatafield");
6229 $a_xml_writer->xmlElement("fieldlabel", null, "title_output");
6230 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getTitleOutput()));
6231 $a_xml_writer->xmlEndTag("qtimetadatafield");
6232
6233 // results presentation
6234 $a_xml_writer->xmlStartTag("qtimetadatafield");
6235 $a_xml_writer->xmlElement("fieldlabel", null, "results_presentation");
6236 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getResultsPresentation()));
6237 $a_xml_writer->xmlEndTag("qtimetadatafield");
6238
6239 // examid in test pass
6240 $a_xml_writer->xmlStartTag("qtimetadatafield");
6241 $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_pass");
6242 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestPassEnabled()));
6243 $a_xml_writer->xmlEndTag("qtimetadatafield");
6244
6245 // examid in kiosk
6246 $a_xml_writer->xmlStartTag("qtimetadatafield");
6247 $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_res");
6248 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestResultsEnabled()));
6249 $a_xml_writer->xmlEndTag("qtimetadatafield");
6250
6251 // solution details
6252 $a_xml_writer->xmlStartTag("qtimetadatafield");
6253 $a_xml_writer->xmlElement("fieldlabel", null, "show_summary");
6254 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getListOfQuestionsSettings()));
6255 $a_xml_writer->xmlEndTag("qtimetadatafield");
6256
6257 // solution details
6258 $a_xml_writer->xmlStartTag("qtimetadatafield");
6259 $a_xml_writer->xmlElement("fieldlabel", null, "score_reporting");
6260 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getScoreReporting()));
6261 $a_xml_writer->xmlEndTag("qtimetadatafield");
6262
6263 $a_xml_writer->xmlStartTag("qtimetadatafield");
6264 $a_xml_writer->xmlElement("fieldlabel", null, "solution_details");
6265 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails());
6266 $a_xml_writer->xmlEndTag("qtimetadatafield");
6267 $a_xml_writer->xmlStartTag("qtimetadatafield");
6268 $a_xml_writer->xmlElement("fieldlabel", null, "print_bs_with_res");
6269 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails() ? (int) $this->isBestSolutionPrintedWithResult() : 0);
6270 $a_xml_writer->xmlEndTag("qtimetadatafield");
6271
6272 // solution details
6273 $a_xml_writer->xmlStartTag("qtimetadatafield");
6274 $a_xml_writer->xmlElement("fieldlabel", null, "instant_verification");
6275 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getInstantFeedbackSolution()));
6276 $a_xml_writer->xmlEndTag("qtimetadatafield");
6277
6278 // answer specific feedback
6279 $a_xml_writer->xmlStartTag("qtimetadatafield");
6280 $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback");
6281 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedback()));
6282 $a_xml_writer->xmlEndTag("qtimetadatafield");
6283
6284 // answer specific feedback of reached points
6285 $a_xml_writer->xmlStartTag("qtimetadatafield");
6286 $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback_points");
6287 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedbackPoints()));
6288 $a_xml_writer->xmlEndTag("qtimetadatafield");
6289
6290 // followup question previous answer freezing
6291 $a_xml_writer->xmlStartTag("qtimetadatafield");
6292 $a_xml_writer->xmlElement("fieldlabel", null, "follow_qst_answer_fixation");
6293 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isFollowupQuestionAnswerFixationEnabled());
6294 $a_xml_writer->xmlEndTag("qtimetadatafield");
6295
6296 // instant response answer freezing
6297 $a_xml_writer->xmlStartTag("qtimetadatafield");
6298 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6299 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6300 $a_xml_writer->xmlEndTag("qtimetadatafield");
6301
6302 // instant response forced
6303 $a_xml_writer->xmlStartTag("qtimetadatafield");
6304 $a_xml_writer->xmlElement("fieldlabel", null, "force_instant_feedback");
6305 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isForceInstantFeedbackEnabled());
6306 $a_xml_writer->xmlEndTag("qtimetadatafield");
6307
6308
6309 // highscore
6310 $highscore_metadata = array(
6311 'highscore_enabled' => array('value' => $this->getHighscoreEnabled()),
6312 'highscore_anon' => array('value' => $this->getHighscoreAnon()),
6313 'highscore_achieved_ts' => array('value' => $this->getHighscoreAchievedTS()),
6314 'highscore_score' => array('value' => $this->getHighscoreScore()),
6315 'highscore_percentage' => array('value' => $this->getHighscorePercentage()),
6316 'highscore_hints' => array('value' => $this->getHighscoreHints()),
6317 'highscore_wtime' => array('value' => $this->getHighscoreWTime()),
6318 'highscore_own_table' => array('value' => $this->getHighscoreOwnTable()),
6319 'highscore_top_table' => array('value' => $this->getHighscoreTopTable()),
6320 'highscore_top_num' => array('value' => $this->getHighscoreTopNum()),
6321 );
6322 foreach ($highscore_metadata as $label => $data) {
6323 $a_xml_writer->xmlStartTag("qtimetadatafield");
6324 $a_xml_writer->xmlElement("fieldlabel", null, $label);
6325 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $data['value']));
6326 $a_xml_writer->xmlEndTag("qtimetadatafield");
6327 }
6328
6329 // show cancel
6330 $a_xml_writer->xmlStartTag("qtimetadatafield");
6331 $a_xml_writer->xmlElement("fieldlabel", null, "show_cancel");
6332 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowCancel()));
6333 $a_xml_writer->xmlEndTag("qtimetadatafield");
6334
6335 // show marker
6336 $a_xml_writer->xmlStartTag("qtimetadatafield");
6337 $a_xml_writer->xmlElement("fieldlabel", null, "show_marker");
6338 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowMarker()));
6339 $a_xml_writer->xmlEndTag("qtimetadatafield");
6340
6341 // fixed participants
6342 $a_xml_writer->xmlStartTag("qtimetadatafield");
6343 $a_xml_writer->xmlElement("fieldlabel", null, "fixed_participants");
6344 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getFixedParticipants()));
6345 $a_xml_writer->xmlEndTag("qtimetadatafield");
6346
6347 // show final statement
6348 $a_xml_writer->xmlStartTag("qtimetadatafield");
6349 $a_xml_writer->xmlElement("fieldlabel", null, "showfinalstatement");
6350 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6351 $a_xml_writer->xmlEndTag("qtimetadatafield");
6352
6353 // show introduction only
6354 $a_xml_writer->xmlStartTag("qtimetadatafield");
6355 $a_xml_writer->xmlElement("fieldlabel", null, "showinfo");
6356 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6357 $a_xml_writer->xmlEndTag("qtimetadatafield");
6358
6359 // mail notification
6360 $a_xml_writer->xmlStartTag("qtimetadatafield");
6361 $a_xml_writer->xmlElement("fieldlabel", null, "mailnotification");
6362 $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotification());
6363 $a_xml_writer->xmlEndTag("qtimetadatafield");
6364
6365 // mail notification type
6366 $a_xml_writer->xmlStartTag("qtimetadatafield");
6367 $a_xml_writer->xmlElement("fieldlabel", null, "mailnottype");
6368 $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotificationType());
6369 $a_xml_writer->xmlEndTag("qtimetadatafield");
6370
6371 // export settings
6372 $a_xml_writer->xmlStartTag("qtimetadatafield");
6373 $a_xml_writer->xmlElement("fieldlabel", null, "exportsettings");
6374 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getExportSettings());
6375 $a_xml_writer->xmlEndTag("qtimetadatafield");
6376
6377 // force JavaScript
6378 $a_xml_writer->xmlStartTag("qtimetadatafield");
6379 $a_xml_writer->xmlElement("fieldlabel", null, "forcejs");
6380 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6381 $a_xml_writer->xmlEndTag("qtimetadatafield");
6382
6383 // custom style
6384 $a_xml_writer->xmlStartTag("qtimetadatafield");
6385 $a_xml_writer->xmlElement("fieldlabel", null, "customstyle");
6386 $a_xml_writer->xmlElement("fieldentry", null, $this->getCustomStyle());
6387 $a_xml_writer->xmlEndTag("qtimetadatafield");
6388
6389 // shuffle questions
6390 $a_xml_writer->xmlStartTag("qtimetadatafield");
6391 $a_xml_writer->xmlElement("fieldlabel", null, "shuffle_questions");
6392 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShuffleQuestions()));
6393 $a_xml_writer->xmlEndTag("qtimetadatafield");
6394
6395 // processing time
6396 $a_xml_writer->xmlStartTag("qtimetadatafield");
6397 $a_xml_writer->xmlElement("fieldlabel", null, "processing_time");
6398 $a_xml_writer->xmlElement("fieldentry", null, $this->getProcessingTime());
6399 $a_xml_writer->xmlEndTag("qtimetadatafield");
6400
6401 // enable_examview
6402 $a_xml_writer->xmlStartTag("qtimetadatafield");
6403 $a_xml_writer->xmlElement("fieldlabel", null, "enable_examview");
6404 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableExamview());
6405 $a_xml_writer->xmlEndTag("qtimetadatafield");
6406
6407 // show_examview_html
6408 $a_xml_writer->xmlStartTag("qtimetadatafield");
6409 $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_html");
6410 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewHtml());
6411 $a_xml_writer->xmlEndTag("qtimetadatafield");
6412
6413 // show_examview_pdf
6414 $a_xml_writer->xmlStartTag("qtimetadatafield");
6415 $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_pdf");
6416 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewPdf());
6417 $a_xml_writer->xmlEndTag("qtimetadatafield");
6418
6419 // enable_archiving
6420 $a_xml_writer->xmlStartTag("qtimetadatafield");
6421 $a_xml_writer->xmlElement("fieldlabel", null, "enable_archiving");
6422 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableArchiving());
6423 $a_xml_writer->xmlEndTag("qtimetadatafield");
6424
6425 // sign_submission
6426 $a_xml_writer->xmlStartTag("qtimetadatafield");
6427 $a_xml_writer->xmlElement("fieldlabel", null, "sign_submission");
6428 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSignSubmission());
6429 $a_xml_writer->xmlEndTag("qtimetadatafield");
6430
6431 // char_selector_availability
6432 $a_xml_writer->xmlStartTag("qtimetadatafield");
6433 $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_availability");
6434 $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getCharSelectorAvailability()));
6435 $a_xml_writer->xmlEndTag("qtimetadatafield");
6436
6437 // char_selector_definition
6438 $a_xml_writer->xmlStartTag("qtimetadatafield");
6439 $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_definition");
6440 $a_xml_writer->xmlElement("fieldentry", null, $this->getCharSelectorDefinition());
6441 $a_xml_writer->xmlEndTag("qtimetadatafield");
6442
6443 // skill_service
6444 $a_xml_writer->xmlStartTag("qtimetadatafield");
6445 $a_xml_writer->xmlElement("fieldlabel", null, "skill_service");
6446 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isSkillServiceEnabled());
6447 $a_xml_writer->xmlEndTag("qtimetadatafield");
6448
6449 // result_tax_filters
6450 $a_xml_writer->xmlStartTag("qtimetadatafield");
6451 $a_xml_writer->xmlElement("fieldlabel", null, "result_tax_filters");
6452 $a_xml_writer->xmlElement("fieldentry", null, serialize((array) $this->getResultFilterTaxIds()));
6453 $a_xml_writer->xmlEndTag("qtimetadatafield");
6454
6455 // show_grading_status
6456 $a_xml_writer->xmlStartTag("qtimetadatafield");
6457 $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_status");
6458 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingStatusEnabled());
6459 $a_xml_writer->xmlEndTag("qtimetadatafield");
6460
6461 // show_grading_mark
6462 $a_xml_writer->xmlStartTag("qtimetadatafield");
6463 $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_mark");
6464 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingMarkEnabled());
6465 $a_xml_writer->xmlEndTag("qtimetadatafield");
6466
6467
6468 // starting time
6469 if ($this->getStartingTime()) {
6470 $a_xml_writer->xmlStartTag("qtimetadatafield");
6471 $a_xml_writer->xmlElement("fieldlabel", null, "starting_time");
6472 $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->starting_time);
6473 $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6474 $a_xml_writer->xmlEndTag("qtimetadatafield");
6475 }
6476 // ending time
6477 if ($this->getEndingTime()) {
6478 $a_xml_writer->xmlStartTag("qtimetadatafield");
6479 $a_xml_writer->xmlElement("fieldlabel", null, "ending_time");
6480 $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->ending_time);
6481 $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6482 $a_xml_writer->xmlEndTag("qtimetadatafield");
6483 }
6484
6485
6486 //activation_limited
6487 $a_xml_writer->xmlStartTag("qtimetadatafield");
6488 $a_xml_writer->xmlElement("fieldlabel", null, "activation_limited");
6489 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isActivationLimited());
6490 $a_xml_writer->xmlEndTag("qtimetadatafield");
6491
6492 //activation_start_time
6493 $a_xml_writer->xmlStartTag("qtimetadatafield");
6494 $a_xml_writer->xmlElement("fieldlabel", null, "activation_start_time");
6495 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationStartingTime());
6496 $a_xml_writer->xmlEndTag("qtimetadatafield");
6497
6498 //activation_end_time
6499 $a_xml_writer->xmlStartTag("qtimetadatafield");
6500 $a_xml_writer->xmlElement("fieldlabel", null, "activation_end_time");
6501 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationEndingTime());
6502 $a_xml_writer->xmlEndTag("qtimetadatafield");
6503
6504 //activation_visibility
6505 $a_xml_writer->xmlStartTag("qtimetadatafield");
6506 $a_xml_writer->xmlElement("fieldlabel", null, "activation_visibility");
6507 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationVisibility());
6508 $a_xml_writer->xmlEndTag("qtimetadatafield");
6509
6510 // autosave
6511 $a_xml_writer->xmlStartTag("qtimetadatafield");
6512 $a_xml_writer->xmlElement("fieldlabel", null, "autosave");
6513 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosave());
6514 $a_xml_writer->xmlEndTag("qtimetadatafield");
6515
6516 // autosave_ival
6517 $a_xml_writer->xmlStartTag("qtimetadatafield");
6518 $a_xml_writer->xmlElement("fieldlabel", null, "autosave_ival");
6519 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosaveIval());
6520 $a_xml_writer->xmlEndTag("qtimetadatafield");
6521
6522 //offer_question_hints
6523 $a_xml_writer->xmlStartTag("qtimetadatafield");
6524 $a_xml_writer->xmlElement("fieldlabel", null, "offer_question_hints");
6525 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isOfferingQuestionHintsEnabled());
6526 $a_xml_writer->xmlEndTag("qtimetadatafield");
6527
6528 //instant_feedback_specific
6529 $a_xml_writer->xmlStartTag("qtimetadatafield");
6530 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_specific");
6531 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSpecificAnswerFeedback());
6532 $a_xml_writer->xmlEndTag("qtimetadatafield");
6533
6534 //instant_feedback_answer_fixation
6535 $a_xml_writer->xmlStartTag("qtimetadatafield");
6536 $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6537 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6538 $a_xml_writer->xmlEndTag("qtimetadatafield");
6539
6540 //obligations_enabled
6541 $a_xml_writer->xmlStartTag("qtimetadatafield");
6542 $a_xml_writer->xmlElement("fieldlabel", null, "obligations_enabled");
6543 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->areObligationsEnabled());
6544 $a_xml_writer->xmlEndTag("qtimetadatafield");
6545
6546 //enable_processing_time
6547 $a_xml_writer->xmlStartTag("qtimetadatafield");
6548 $a_xml_writer->xmlElement("fieldlabel", null, "enable_processing_time");
6549 $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableProcessingTime());
6550 $a_xml_writer->xmlEndTag("qtimetadatafield");
6551
6552 foreach ($this->mark_schema->mark_steps as $index => $mark) {
6553 // mark steps
6554 $a_xml_writer->xmlStartTag("qtimetadatafield");
6555 $a_xml_writer->xmlElement("fieldlabel", null, "mark_step_$index");
6556 $a_xml_writer->xmlElement("fieldentry", null, sprintf(
6557 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
6558 $mark->getShortName(),
6559 $mark->getOfficialName(),
6560 $mark->getMinimumLevel(),
6561 $mark->getPassed()
6562 ));
6563 $a_xml_writer->xmlEndTag("qtimetadatafield");
6564 }
6565 $a_xml_writer->xmlEndTag("qtimetadata");
6566
6567 // add qti objectives
6568 $a_xml_writer->xmlStartTag("objectives");
6569 $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6570 $a_xml_writer->xmlEndTag("objectives");
6571
6572 // add qti assessmentcontrol
6573 if ($this->getInstantFeedbackSolution() == 1) {
6574 $attrs = array(
6575 "solutionswitch" => "Yes"
6576 );
6577 } else {
6578 $attrs = null;
6579 }
6580 $a_xml_writer->xmlElement("assessmentcontrol", $attrs, null);
6581
6582 if (strlen($this->getFinalStatement())) {
6583 // add qti presentation_material
6584 $a_xml_writer->xmlStartTag("presentation_material");
6585 $a_xml_writer->xmlStartTag("flow_mat");
6586 $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6587 $a_xml_writer->xmlEndTag("flow_mat");
6588 $a_xml_writer->xmlEndTag("presentation_material");
6589 }
6590
6591 $attrs = array(
6592 "ident" => "1"
6593 );
6594 $a_xml_writer->xmlElement("section", $attrs, null);
6595 $a_xml_writer->xmlEndTag("assessment");
6596 $a_xml_writer->xmlEndTag("questestinterop");
6597
6598 $xml = $a_xml_writer->xmlDumpMem(false);
6599 return $xml;
6600 }
6601
6607 {
6608 $date_time_unix = new ilDateTime($unix_timestamp, IL_CAL_UNIX);
6609 $date_time = $date_time_unix->get(IL_CAL_DATETIME);
6610 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $date_time, $matches);
6611 $iso8601_period = sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]);
6612 return $iso8601_period;
6613 }
6614
6621 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6622 {
6623 global $DIC;
6624 $ilBench = $DIC['ilBench'];
6625
6626 $this->mob_ids = array();
6627 $this->file_ids = array();
6628
6629 // MetaData
6630 $this->exportXMLMetaData($a_xml_writer);
6631
6632 // PageObjects
6633 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Page Objects");
6634 $ilBench->start("ContentObjectExport", "exportPageObjects");
6635 $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6636 $ilBench->stop("ContentObjectExport", "exportPageObjects");
6637 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Page Objects");
6638
6639 // MediaObjects
6640 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Media Objects");
6641 $ilBench->start("ContentObjectExport", "exportMediaObjects");
6642 $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6643 $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6644 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Media Objects");
6645
6646 // FileItems
6647 $expLog->write(date("[y-m-d H:i:s] ") . "Start Export File Items");
6648 $ilBench->start("ContentObjectExport", "exportFileItems");
6649 $this->exportFileItems($a_target_dir, $expLog);
6650 $ilBench->stop("ContentObjectExport", "exportFileItems");
6651 $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export File Items");
6652 }
6653
6660 public function exportXMLMetaData(&$a_xml_writer)
6661 {
6662 include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6663 $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6664 $md2xml->setExportMode(true);
6665 $md2xml->startExport();
6666 $a_xml_writer->appendXML($md2xml->getXML());
6667 }
6668
6674 public function modifyExportIdentifier($a_tag, $a_param, $a_value)
6675 {
6676 if ($a_tag == "Identifier" && $a_param == "Entry") {
6677 include_once "./Services/Utilities/classes/class.ilUtil.php";
6678 $a_value = ilUtil::insertInstIntoID($a_value);
6679 }
6680
6681 return $a_value;
6682 }
6683
6684
6691 public function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6692 {
6693 global $DIC;
6694 $ilBench = $DIC['ilBench'];
6695
6696 include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6697
6698 foreach ($this->questions as $question_id) {
6699 $ilBench->start("ContentObjectExport", "exportPageObject");
6700 $expLog->write(date("[y-m-d H:i:s] ") . "Page Object " . $question_id);
6701
6702 $attrs = array();
6703 $a_xml_writer->xmlStartTag("PageObject", $attrs);
6704
6705
6706 // export xml to writer object
6707 $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6708 include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
6709 $page_object = new ilAssQuestionPage($question_id);
6710 $page_object->buildDom();
6711 $page_object->insertInstIntoIDs($a_inst);
6712 $mob_ids = $page_object->collectMediaObjects(false);
6713 require_once 'Services/COPage/classes/class.ilPCFileList.php';
6714 $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
6715 $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6716 $xml = str_replace("&", "&amp;", $xml);
6717 $a_xml_writer->appendXML($xml);
6718 $page_object->freeDom();
6719 unset($page_object);
6720
6721 $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6722
6723 // collect media objects
6724 $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6725 //$mob_ids = $page_obj->getMediaObjectIDs();
6726 foreach ($mob_ids as $mob_id) {
6727 $this->mob_ids[$mob_id] = $mob_id;
6728 }
6729 $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6730
6731 // collect all file items
6732 $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6733 //$file_ids = $page_obj->getFileItemIds();
6734 foreach ($file_ids as $file_id) {
6735 $this->file_ids[$file_id] = $file_id;
6736 }
6737 $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6738
6739 $a_xml_writer->xmlEndTag("PageObject");
6740 //unset($page_obj);
6741
6742 $ilBench->stop("ContentObjectExport", "exportPageObject");
6743 }
6744 }
6745
6752 public function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6753 {
6754 include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6755
6756 foreach ($this->mob_ids as $mob_id) {
6757 $expLog->write(date("[y-m-d H:i:s] ") . "Media Object " . $mob_id);
6758 if (ilObjMediaObject::_exists($mob_id)) {
6759 $media_obj = new ilObjMediaObject($mob_id);
6760 $media_obj->exportXML($a_xml_writer, $a_inst);
6761 $media_obj->exportFiles($a_target_dir);
6762 unset($media_obj);
6763 }
6764 }
6765 }
6766
6771 public function exportFileItems($a_target_dir, &$expLog)
6772 {
6773 include_once "./Modules/File/classes/class.ilObjFile.php";
6774
6775 foreach ($this->file_ids as $file_id) {
6776 $expLog->write(date("[y-m-d H:i:s] ") . "File Item " . $file_id);
6777 $file_obj = new ilObjFile($file_id, false);
6778 $file_obj->export($a_target_dir);
6779 unset($file_obj);
6780 }
6781 }
6782
6787 public function getImportMapping()
6788 {
6789 if (!is_array($this->import_mapping)) {
6790 return array();
6791 } else {
6792 return $this->import_mapping;
6793 }
6794 }
6795
6799 public function canEditEctsGrades()
6800 {
6801 return $this->canShowEctsGrades() && $this->canEditMarks();
6802 }
6803
6807 public function canShowEctsGrades()
6808 {
6809 return $this->getReportingDate();
6810 }
6811
6815 public function getECTSGrade($passed_array, $reached_points, $max_points)
6816 {
6817 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);
6818 }
6819
6823 public static function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6824 {
6825 include_once "./Modules/Test/classes/class.ilStatistics.php";
6826 // calculate the median
6827 $passed_statistics = new ilStatistics();
6828 $passed_statistics->setData($points_passed);
6829 $ects_percentiles = array(
6830 "A" => $passed_statistics->quantile($a),
6831 "B" => $passed_statistics->quantile($b),
6832 "C" => $passed_statistics->quantile($c),
6833 "D" => $passed_statistics->quantile($d),
6834 "E" => $passed_statistics->quantile($e)
6835 );
6836 if (count($points_passed) && ($reached_points >= $ects_percentiles["A"])) {
6837 return "A";
6838 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["B"])) {
6839 return "B";
6840 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["C"])) {
6841 return "C";
6842 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["D"])) {
6843 return "D";
6844 } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["E"])) {
6845 return "E";
6846 } elseif (strcmp($fx, "") != 0) {
6847 if ($max_points > 0) {
6848 $percentage = ($reached_points / $max_points) * 100.0;
6849 if ($percentage < 0) {
6850 $percentage = 0.0;
6851 }
6852 } else {
6853 $percentage = 0.0;
6854 }
6855 if ($percentage >= $fx) {
6856 return "FX";
6857 } else {
6858 return "F";
6859 }
6860 } else {
6861 return "F";
6862 }
6863 }
6864
6868 public function checkMarks()
6869 {
6870 return $this->mark_schema->checkMarks();
6871 }
6872
6876 public function getMarkSchema()
6877 {
6878 return $this->mark_schema;
6879 }
6880
6884 public function getMarkSchemaForeignId()
6885 {
6886 return $this->getTestId();
6887 }
6888
6891 public function onMarkSchemaSaved()
6892 {
6898 global $DIC;
6899 $ilDB = $DIC['ilDB'];
6900 $ilPluginAdmin = $DIC['ilPluginAdmin'];
6901 $tree = $DIC['tree'];
6902
6903 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
6904 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
6905 $this->saveCompleteStatus($testQuestionSetConfigFactory->getQuestionSetConfig());
6906
6907 if ($this->participantDataExist()) {
6908 $this->recalculateScores(true);
6909 }
6910 }
6911
6915 public function canEditMarks()
6916 {
6917 $total = $this->evalTotalPersons();
6918 if ($total > 0) {
6919 if ($this->getReportingDate()) {
6920 if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches)) {
6921 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
6922 $now = time();
6923 if ($now < $epoch_time) {
6924 return true;
6925 }
6926 }
6927 }
6928 return false;
6929 } else {
6930 return true;
6931 }
6932 }
6933
6941 public function setAuthor($author = "")
6942 {
6943 $this->author = $author;
6944 }
6945
6955 public function saveAuthorToMetadata($a_author = "")
6956 {
6957 $md = new ilMD($this->getId(), 0, $this->getType());
6958 $md_life = &$md->getLifecycle();
6959 if (!$md_life) {
6960 if (strlen($a_author) == 0) {
6961 global $DIC;
6962 $ilUser = $DIC['ilUser'];
6963 $a_author = $ilUser->getFullname();
6964 }
6965
6966 $md_life = &$md->addLifecycle();
6967 $md_life->save();
6968 $con = &$md_life->addContribute();
6969 $con->setRole("Author");
6970 $con->save();
6971 $ent = &$con->addEntity();
6972 $ent->setEntity($a_author);
6973 $ent->save();
6974 }
6975 }
6976
6982 public function createMetaData()
6983 {
6984 parent::createMetaData();
6985 $this->saveAuthorToMetadata();
6986 }
6987
6995 public function getAuthor()
6996 {
6997 $author = array();
6998 include_once "./Services/MetaData/classes/class.ilMD.php";
6999 $md = new ilMD($this->getId(), 0, $this->getType());
7000 $md_life = &$md->getLifecycle();
7001 if ($md_life) {
7002 $ids = &$md_life->getContributeIds();
7003 foreach ($ids as $id) {
7004 $md_cont = &$md_life->getContribute($id);
7005 if (strcmp($md_cont->getRole(), "Author") == 0) {
7006 $entids = &$md_cont->getEntityIds();
7007 foreach ($entids as $entid) {
7008 $md_ent = &$md_cont->getEntity($entid);
7009 array_push($author, $md_ent->getEntity());
7010 }
7011 }
7012 }
7013 }
7014 return join(",", $author);
7015 }
7016
7024 public static function _lookupAuthor($obj_id)
7025 {
7026 $author = array();
7027 include_once "./Services/MetaData/classes/class.ilMD.php";
7028 $md = new ilMD($obj_id, 0, "tst");
7029 $md_life = &$md->getLifecycle();
7030 if ($md_life) {
7031 $ids = &$md_life->getContributeIds();
7032 foreach ($ids as $id) {
7033 $md_cont = &$md_life->getContribute($id);
7034 if (strcmp($md_cont->getRole(), "Author") == 0) {
7035 $entids = &$md_cont->getEntityIds();
7036 foreach ($entids as $entid) {
7037 $md_ent = &$md_cont->getEntity($entid);
7038 array_push($author, $md_ent->getEntity());
7039 }
7040 }
7041 }
7042 }
7043 return join(",", $author);
7044 }
7045
7052 public static function _getAvailableTests($use_object_id = false)
7053 {
7054 global $DIC;
7055 $ilUser = $DIC['ilUser'];
7056 $ilDB = $DIC['ilDB'];
7057
7058 $result_array = array();
7059 $tests = array_slice(
7060 array_reverse(
7061 ilUtil::_getObjectsByOperations("tst", "write", $ilUser->getId(), PHP_INT_MAX)
7062 ),
7063 0,
7064 10000
7065 );
7066
7067 if (count($tests)) {
7068 $titles = ilObject::_prepareCloneSelection($tests, "tst");
7069 foreach ($tests as $ref_id) {
7070 if ($use_object_id) {
7072 $result_array[$obj_id] = $titles[$ref_id];
7073 } else {
7074 $result_array[$ref_id] = $titles[$ref_id];
7075 }
7076 }
7077 }
7078 return $result_array;
7079 }
7080
7089 public function cloneObject($a_target_id, $a_copy_id = 0, $a_omit_tree = false)
7090 {
7091 global $DIC;
7092
7093 $certificateLogger = $DIC->logger()->cert();
7094 $tree = $DIC['tree'];
7095 $ilDB = $DIC->database();
7096 $ilPluginAdmin = $DIC['ilPluginAdmin'];
7097
7098 $this->loadFromDb();
7099
7100 // Copy settings
7102 $newObj = parent::cloneObject($a_target_id, $a_copy_id, $a_omit_tree);
7103 $newObj->setTmpCopyWizardCopyId($a_copy_id);
7104 $this->cloneMetaData($newObj);
7105
7106 //copy online status if object is not the root copy object
7107 $cp_options = ilCopyWizardOptions::_getInstance($a_copy_id);
7108
7109 if (!$cp_options->isRootNode($this->getRefId())) {
7110 $newObj->setOfflineStatus($this->getOfflineStatus());
7111 }
7112
7113 $newObj->setAnonymity($this->getAnonymity());
7114 $newObj->setAnswerFeedback($this->getAnswerFeedback());
7115 $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
7116 $newObj->setAuthor($this->getAuthor());
7117 $newObj->setLimitUsersEnabled($this->isLimitUsersEnabled());
7118 $newObj->setAllowedUsers($this->getAllowedUsers());
7119 $newObj->setAllowedUsersTimeGap($this->getAllowedUsersTimeGap());
7120 $newObj->setCountSystem($this->getCountSystem());
7121 $newObj->setECTSFX($this->getECTSFX());
7122 $newObj->setECTSGrades($this->getECTSGrades());
7123 $newObj->setECTSOutput($this->getECTSOutput());
7124 $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
7125 $newObj->setEndingTimeEnabled($this->isEndingTimeEnabled());
7126 $newObj->setEndingTime($this->getEndingTime());
7127 $newObj->setFixedParticipants($this->getFixedParticipants());
7128 $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
7129 $newObj->setIntroductionEnabled($this->isIntroductionEnabled());
7130 $newObj->setIntroduction($this->getIntroduction());
7131 $newObj->setFinalStatement($this->getFinalStatement());
7132 $newObj->setShowInfo($this->getShowInfo());
7133 $newObj->setForceJS($this->getForceJS());
7134 $newObj->setCustomStyle($this->getCustomStyle());
7135 $newObj->setKiosk($this->getKiosk());
7136 $newObj->setShowFinalStatement($this->getShowFinalStatement());
7137 $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
7138 $newObj->setMCScoring($this->getMCScoring());
7139 $newObj->setMailNotification($this->getMailNotification());
7140 $newObj->setMailNotificationType($this->getMailNotificationType());
7141 $newObj->setNrOfTries($this->getNrOfTries());
7142 $newObj->setPassScoring($this->getPassScoring());
7143 $newObj->setPasswordEnabled($this->isPasswordEnabled());
7144 $newObj->setPassword($this->getPassword());
7145 $newObj->setProcessingTime($this->getProcessingTime());
7146 $newObj->setQuestionSetType($this->getQuestionSetType());
7147 $newObj->setReportingDate($this->getReportingDate());
7148 $newObj->setResetProcessingTime($this->getResetProcessingTime());
7149 $newObj->setResultsPresentation($this->getResultsPresentation());
7150 $newObj->setScoreCutting($this->getScoreCutting());
7151 $newObj->setScoreReporting($this->getScoreReporting());
7152 $newObj->setSequenceSettings($this->getSequenceSettings());
7153 $newObj->setShowCancel($this->getShowCancel());
7154 $newObj->setShowMarker($this->getShowMarker());
7155 $newObj->setShuffleQuestions($this->getShuffleQuestions());
7156 $newObj->setStartingTimeEnabled($this->isStartingTimeEnabled());
7157 $newObj->setStartingTime($this->getStartingTime());
7158 $newObj->setTitleOutput($this->getTitleOutput());
7159 $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
7160 $newObj->setRedirectionMode($this->getRedirectionMode());
7161 $newObj->setRedirectionUrl($this->getRedirectionUrl());
7162 $newObj->setCertificateVisibility($this->getCertificateVisibility());
7163 $newObj->mark_schema = clone $this->mark_schema;
7164 $newObj->setEnabledViewMode($this->getEnabledViewMode());
7165 $newObj->setTemplate($this->getTemplate());
7166 $newObj->setPoolUsage($this->getPoolUsage());
7167 $newObj->setPrintBestSolutionWithResult($this->isBestSolutionPrintedWithResult());
7168 $newObj->setShowExamIdInTestPassEnabled($this->isShowExamIdInTestPassEnabled());
7169 $newObj->setShowExamIdInTestResultsEnabled($this->isShowExamIdInTestResultsEnabled());
7170 $newObj->setEnableExamView($this->getEnableExamview());
7171 $newObj->setShowExamViewHtml($this->getShowExamviewHtml());
7172 $newObj->setShowExamViewPdf($this->getShowExamviewPdf());
7173 $newObj->setEnableArchiving($this->getEnableArchiving());
7174 $newObj->setSignSubmission($this->getSignSubmission());
7175 $newObj->setCharSelectorAvailability((int) $this->getCharSelectorAvailability());
7176 $newObj->setCharSelectorDefinition($this->getCharSelectorDefinition());
7177 $newObj->setSkillServiceEnabled($this->isSkillServiceEnabled());
7178 $newObj->setResultFilterTaxIds($this->getResultFilterTaxIds());
7179 $newObj->setFollowupQuestionAnswerFixationEnabled($this->isFollowupQuestionAnswerFixationEnabled());
7180 $newObj->setInstantFeedbackAnswerFixationEnabled($this->isInstantFeedbackAnswerFixationEnabled());
7181 $newObj->setForceInstantFeedbackEnabled($this->isForceInstantFeedbackEnabled());
7182 $newObj->setAutosave($this->getAutosave());
7183 $newObj->setAutosaveIval($this->getAutosaveIval());
7184 $newObj->setOfferingQuestionHintsEnabled($this->isOfferingQuestionHintsEnabled());
7185 $newObj->setSpecificAnswerFeedback($this->getSpecificAnswerFeedback());
7186 if ($this->isPassWaitingEnabled()) {
7187 $newObj->setPassWaiting($this->getPassWaiting());
7188 }
7189 $newObj->setObligationsEnabled($this->areObligationsEnabled());
7190 $newObj->saveToDb();
7191
7192 // clone certificate
7194 $templateRepository = new ilCertificateTemplateRepository($ilDB);
7195
7196 $cloneAction = new ilCertificateCloneAction(
7197 $ilDB,
7198 $factory,
7199 $templateRepository,
7200 $DIC->filesystem()->web(),
7201 $certificateLogger,
7203 );
7204
7205 $cloneAction->cloneCertificate($this, $newObj);
7206
7207 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7208 $testQuestionSetConfigFactory->getQuestionSetConfig()->cloneQuestionSetRelatedData($newObj);
7209
7210 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdList.php';
7211 $skillLevelThresholdList = new ilTestSkillLevelThresholdList($ilDB);
7212 $skillLevelThresholdList->setTestId($this->getTestId());
7213 $skillLevelThresholdList->loadFromDb();
7214 $skillLevelThresholdList->cloneListForTest($newObj->getTestId());
7215
7216 $newObj->saveToDb();
7217 $newObj->updateMetaData();// #14467
7218
7219 include_once('./Services/Tracking/classes/class.ilLPObjSettings.php');
7220 $obj_settings = new ilLPObjSettings($this->getId());
7221 $obj_settings->cloneSettings($newObj->getId());
7222
7223 return $newObj;
7224 }
7225
7232 public function getQuestionCount()
7233 {
7234 $num = 0;
7235
7236 if ($this->isRandomTest()) {
7237 global $DIC;
7238 $tree = $DIC['tree'];
7239 $ilDB = $DIC['ilDB'];
7240 $ilPluginAdmin = $DIC['ilPluginAdmin'];
7241
7242 $questionSetConfig = new ilTestRandomQuestionSetConfig(
7243 $tree,
7244 $ilDB,
7245 $ilPluginAdmin,
7246 $this
7247 );
7248
7249 $questionSetConfig->loadFromDb();
7250
7251 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
7252 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php';
7253 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetBuilderWithAmountPerPool.php';
7254 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php';
7255
7256 $sourcePoolDefinitionList = new ilTestRandomQuestionSetSourcePoolDefinitionList(
7257 $ilDB,
7258 $this,
7260 );
7261
7262 $sourcePoolDefinitionList->loadDefinitions();
7263
7264 $num = $sourcePoolDefinitionList->getQuestionAmount();
7265 } else {
7266 $num = $questionSetConfig->getQuestionAmountPerTest();
7267 }
7268 } else {
7269 $num = count($this->questions);
7270 }
7271
7272 return $num;
7273 }
7274
7282 public function logAction($logtext = "", $question_id = "")
7283 {
7284 global $DIC;
7285 $ilUser = $DIC['ilUser'];
7286
7287 $original_id = "";
7288 if (strcmp($question_id, "") != 0) {
7289 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7290 $original_id = assQuestion::_getOriginalId($question_id);
7291 }
7292 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7293 ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, true, $this->getRefId());
7294 }
7295
7303 public static function _getObjectIDFromTestID($test_id)
7304 {
7305 global $DIC;
7306 $ilDB = $DIC['ilDB'];
7307 $object_id = false;
7308 $result = $ilDB->queryF(
7309 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7310 array('integer'),
7311 array($test_id)
7312 );
7313 if ($result->numRows()) {
7314 $row = $ilDB->fetchAssoc($result);
7315 $object_id = $row["obj_fi"];
7316 }
7317 return $object_id;
7318 }
7319
7327 public static function _getObjectIDFromActiveID($active_id)
7328 {
7329 global $DIC;
7330 $ilDB = $DIC['ilDB'];
7331 $object_id = false;
7332 $result = $ilDB->queryF(
7333 "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",
7334 array('integer'),
7335 array($active_id)
7336 );
7337 if ($result->numRows()) {
7338 $row = $ilDB->fetchAssoc($result);
7339 $object_id = $row["obj_fi"];
7340 }
7341 return $object_id;
7342 }
7343
7351 public static function _getTestIDFromObjectID($object_id)
7352 {
7353 global $DIC;
7354 $ilDB = $DIC['ilDB'];
7355 $test_id = false;
7356 $result = $ilDB->queryF(
7357 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7358 array('integer'),
7359 array($object_id)
7360 );
7361 if ($result->numRows()) {
7362 $row = $ilDB->fetchAssoc($result);
7363 $test_id = $row["test_id"];
7364 }
7365 return $test_id;
7366 }
7367
7376 public function getTextAnswer($active_id, $question_id, $pass = null)
7377 {
7378 global $DIC;
7379 $ilDB = $DIC['ilDB'];
7380
7381 $res = "";
7382 if (($active_id) && ($question_id)) {
7383 if (is_null($pass)) {
7384 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7385 $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7386 }
7387 $result = $ilDB->queryF(
7388 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7389 array('integer', 'integer', 'integer'),
7390 array($active_id, $question_id, $pass)
7391 );
7392 if ($result->numRows() == 1) {
7393 $row = $ilDB->fetchAssoc($result);
7394 $res = $row["value1"];
7395 }
7396 }
7397 return $res;
7398 }
7399
7407 public function getQuestiontext($question_id)
7408 {
7409 global $DIC;
7410 $ilDB = $DIC['ilDB'];
7411
7412 $res = "";
7413 if ($question_id) {
7414 $result = $ilDB->queryF(
7415 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
7416 array('integer'),
7417 array($question_id)
7418 );
7419 if ($result->numRows() == 1) {
7420 $row = $ilDB->fetchAssoc($result);
7421 $res = $row["question_text"];
7422 }
7423 }
7424 return $res;
7425 }
7426
7431 {
7432 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
7433 $participantList = new ilTestParticipantList($this);
7434 $participantList->initializeFromDbRows($this->getInvitedUsers());
7435
7436 return $participantList;
7437 }
7438
7443 {
7444 require_once 'Modules/Test/classes/class.ilTestParticipantList.php';
7445 $participantList = new ilTestParticipantList($this);
7446 $participantList->initializeFromDbRows($this->getTestParticipants());
7447
7448 return $participantList;
7449 }
7450
7457 public function &getInvitedUsers($user_id = "", $order = "login, lastname, firstname")
7458 {
7459 global $DIC;
7460 $ilDB = $DIC['ilDB'];
7461
7462 $result_array = array();
7463
7464 if ($this->getAnonymity()) {
7465 if (is_numeric($user_id)) {
7466 $result = $ilDB->queryF(
7467 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7468 "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 " .
7469 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7470 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7471 "ORDER BY $order",
7472 array('text', 'text', 'text', 'integer', 'integer'),
7473 array("", $this->lng->txt("anonymous"), "", $this->getTestId(), $user_id)
7474 );
7475 } else {
7476 $result = $ilDB->queryF(
7477 "SELECT tst_active.active_id, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7478 "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 " .
7479 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7480 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7481 "ORDER BY $order",
7482 array('text', 'text', 'text', 'integer'),
7483 array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7484 );
7485 }
7486 } else {
7487 if (is_numeric($user_id)) {
7488 $result = $ilDB->queryF(
7489 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7490 "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 " .
7491 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7492 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7493 "ORDER BY $order",
7494 array('integer', 'integer'),
7495 array($this->getTestId(), $user_id)
7496 );
7497 } else {
7498 $result = $ilDB->queryF(
7499 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7500 "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 " .
7501 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7502 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7503 "ORDER BY $order",
7504 array('integer'),
7505 array($this->getTestId())
7506 );
7507 }
7508 }
7509 $result_array = array();
7510 while ($row = $ilDB->fetchAssoc($result)) {
7511 $result_array[$row['usr_id']] = $row;
7512 }
7513 return $result_array;
7514 }
7515
7522 public function &getTestParticipants()
7523 {
7524 global $DIC;
7525 $ilDB = $DIC['ilDB'];
7526
7527 if ($this->getAnonymity()) {
7528 $query = "
7529 SELECT tst_active.active_id,
7530 tst_active.tries,
7531 tst_active.user_fi usr_id,
7532 %s login,
7533 %s lastname,
7534 %s firstname,
7535 tst_active.submitted test_finished,
7536 usr_data.matriculation,
7537 usr_data.active,
7538 tst_active.lastindex,
7539 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7540 FROM tst_active
7541 LEFT JOIN usr_data
7542 ON tst_active.user_fi = usr_data.usr_id
7543 WHERE tst_active.test_fi = %s
7544 ORDER BY usr_data.lastname
7545 ";
7546 $result = $ilDB->queryF(
7547 $query,
7548 array('text', 'text', 'text', 'integer'),
7549 array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7550 );
7551 } else {
7552 $query = "
7553 SELECT tst_active.active_id,
7554 tst_active.tries,
7555 tst_active.user_fi usr_id,
7556 usr_data.login,
7557 usr_data.lastname,
7558 usr_data.firstname,
7559 tst_active.submitted test_finished,
7560 usr_data.matriculation,
7561 usr_data.active,
7562 tst_active.lastindex,
7563 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7564 FROM tst_active
7565 LEFT JOIN usr_data
7566 ON tst_active.user_fi = usr_data.usr_id
7567 WHERE tst_active.test_fi = %s
7568 ORDER BY usr_data.lastname
7569 ";
7570 $result = $ilDB->queryF(
7571 $query,
7572 array('integer'),
7573 array($this->getTestId())
7574 );
7575 }
7576 $data = array();
7577 while ($row = $ilDB->fetchAssoc($result)) {
7578 $data[$row['active_id']] = $row;
7579 }
7580 foreach ($data as $index => $participant) {
7581 if (strlen(trim($participant["firstname"] . $participant["lastname"])) == 0) {
7582 $data[$index]["lastname"] = $this->lng->txt("deleted_user");
7583 }
7584 }
7585 return $data;
7586 }
7587
7588 public function getTestParticipantsForManualScoring($filter = null)
7589 {
7590 global $DIC;
7591 $ilDB = $DIC['ilDB'];
7592
7593 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7595 if (count($scoring) == 0) {
7596 return array();
7597 }
7598
7599 $participants = &$this->getTestParticipants();
7600 $filtered_participants = array();
7601 foreach ($participants as $active_id => $participant) {
7602 $qstType_IN_manScoreableQstTypes = $ilDB->in('qpl_questions.question_type_fi', $scoring, false, 'integer');
7603
7604 $queryString = "
7605 SELECT tst_test_result.manual
7606
7607 FROM tst_test_result
7608
7609 INNER JOIN qpl_questions
7610 ON tst_test_result.question_fi = qpl_questions.question_id
7611
7612 WHERE tst_test_result.active_fi = %s
7613 AND $qstType_IN_manScoreableQstTypes
7614 ";
7615
7616 $result = $ilDB->queryF(
7617 $queryString,
7618 array("integer"),
7619 array($active_id)
7620 );
7621
7622 $count = $result->numRows();
7623
7624 if ($count > 0) {
7625 switch ($filter) {
7626 case 1: // only active users
7627 if ($participant->active) {
7628 $filtered_participants[$active_id] = $participant;
7629 }
7630 break;
7631 case 2: // only inactive users
7632 if (!$participant->active) {
7633 $filtered_participants[$active_id] = $participant;
7634 }
7635 break;
7636 case 3: // all users
7637 $filtered_participants[$active_id] = $participant;
7638 break;
7639 case 4:
7640 // already scored participants
7641 //$found = 0;
7642 //while ($row = $ilDB->fetchAssoc($result))
7643 //{
7644 // if ($row["manual"]) $found++;
7645 //}
7646 //if ($found == $count)
7647 //{
7648 //$filtered_participants[$active_id] = $participant;
7649 //}
7650 //else
7651 //{
7652 $assessmentSetting = new ilSetting("assessment");
7653 $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7654 if ($manscoring_done) {
7655 $filtered_participants[$active_id] = $participant;
7656 }
7657 //}
7658 break;
7659 case 5:
7660 // unscored participants
7661 //$found = 0;
7662 //while ($row = $ilDB->fetchAssoc($result))
7663 //{
7664 // if ($row["manual"]) $found++;
7665 //}
7666 //if ($found == 0)
7667 //{
7668 $assessmentSetting = new ilSetting("assessment");
7669 $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7670 if (!$manscoring_done) {
7671 $filtered_participants[$active_id] = $participant;
7672 }
7673 //}
7674 break;
7675 case 6:
7676 // partially scored participants
7677 $found = 0;
7678 while ($row = $ilDB->fetchAssoc($result)) {
7679 if ($row["manual"]) {
7680 $found++;
7681 }
7682 }
7683 if (($found > 0) && ($found < $count)) {
7684 $filtered_participants[$active_id] = $participant;
7685 }
7686 break;
7687 default:
7688 $filtered_participants[$active_id] = $participant;
7689 break;
7690 }
7691 }
7692 }
7693 return $filtered_participants;
7694 }
7695
7703 public function &getUserData($ids)
7704 {
7705 global $DIC;
7706 $ilDB = $DIC['ilDB'];
7707
7708 if (!is_array($ids) || count($ids) == 0) {
7709 return array();
7710 }
7711
7712 if ($this->getAnonymity()) {
7713 $result = $ilDB->queryF(
7714 "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",
7715 array('text', 'text', 'text'),
7716 array("", $this->lng->txt("anonymous"), "")
7717 );
7718 } else {
7719 $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");
7720 }
7721
7722 $result_array = array();
7723 while ($row = $ilDB->fetchAssoc($result)) {
7724 $result_array[$row["usr_id"]] = $row;
7725 }
7726 return $result_array;
7727 }
7728
7729 public function &getGroupData($ids)
7730 {
7731 if (!is_array($ids) || count($ids) == 0) {
7732 return array();
7733 }
7734 $result = array();
7735 foreach ($ids as $ref_id) {
7737 $result[$ref_id] = array("ref_id" => $ref_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7738 }
7739 return $result;
7740 }
7741
7742 public function &getRoleData($ids)
7743 {
7744 if (!is_array($ids) || count($ids) == 0) {
7745 return array();
7746 }
7747 $result = array();
7748 foreach ($ids as $obj_id) {
7749 $result[$obj_id] = array("obj_id" => $obj_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7750 }
7751 return $result;
7752 }
7753
7754
7761 public function inviteGroup($group_id)
7762 {
7763 include_once "./Modules/Group/classes/class.ilObjGroup.php";
7764 $group = new ilObjGroup($group_id);
7765 $members = $group->getGroupMemberIds();
7766 include_once './Services/User/classes/class.ilObjUser.php';
7767 foreach ($members as $user_id) {
7768 $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7769 }
7770 }
7771
7778 public function inviteRole($role_id)
7779 {
7780 global $DIC;
7781 $rbacreview = $DIC['rbacreview'];
7782 $members = $rbacreview->assignedUsers($role_id);
7783 include_once './Services/User/classes/class.ilObjUser.php';
7784 foreach ($members as $user_id) {
7785 $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7786 }
7787 }
7788
7789
7790
7797 public function disinviteUser($user_id)
7798 {
7799 global $DIC;
7800 $ilDB = $DIC['ilDB'];
7801
7802 $affectedRows = $ilDB->manipulateF(
7803 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7804 array('integer', 'integer'),
7805 array($this->getTestId(), $user_id)
7806 );
7807 }
7808
7815 public function inviteUser($user_id, $client_ip = "")
7816 {
7817 global $DIC;
7818 $ilDB = $DIC['ilDB'];
7819
7820 $affectedRows = $ilDB->manipulateF(
7821 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7822 array('integer', 'integer'),
7823 array($this->getTestId(), $user_id)
7824 );
7825 $affectedRows = $ilDB->manipulateF(
7826 "INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
7827 array('integer', 'integer', 'text', 'integer'),
7828 array($this->getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : null, time())
7829 );
7830 }
7831
7832
7833 public function setClientIP($user_id, $client_ip)
7834 {
7835 global $DIC;
7836 $ilDB = $DIC['ilDB'];
7837
7838 $affectedRows = $ilDB->manipulateF(
7839 "UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
7840 array('text', 'integer', 'integer', 'integer'),
7841 array((strlen($client_ip)) ? $client_ip : null, time(), $this->getTestId(), $user_id)
7842 );
7843 }
7844
7850 public static function _getSolvedQuestions($active_id, $question_fi = null)
7851 {
7852 global $DIC;
7853 $ilDB = $DIC['ilDB'];
7854 if (is_numeric($question_fi)) {
7855 $result = $ilDB->queryF(
7856 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
7857 array('integer', 'integer'),
7858 array($active_id, $question_fi)
7859 );
7860 } else {
7861 $result = $ilDB->queryF(
7862 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
7863 array('integer'),
7864 array($active_id)
7865 );
7866 }
7867 $result_array = array();
7868 while ($row = $ilDB->fetchAssoc($result)) {
7869 $result_array[$row["question_fi"]] = $row;
7870 }
7871 return $result_array;
7872 }
7873
7874
7878 public function setQuestionSetSolved($value, $question_id, $user_id)
7879 {
7880 global $DIC;
7881 $ilDB = $DIC['ilDB'];
7882
7883 $active_id = $this->getActiveIdOfUser($user_id);
7884 $affectedRows = $ilDB->manipulateF(
7885 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
7886 array('integer', 'integer'),
7887 array($active_id, $question_id)
7888 );
7889 $affectedRows = $ilDB->manipulateF(
7890 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
7891 array('integer', 'integer', 'integer'),
7892 array($value, $question_id, $active_id)
7893 );
7894 }
7895
7899 public function isTestFinished($active_id)
7900 {
7901 global $DIC;
7902 $ilDB = $DIC['ilDB'];
7903
7904 $result = $ilDB->queryF(
7905 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
7906 array('integer', 'integer'),
7907 array($active_id, 1)
7908 );
7909 return $result->numRows() == 1;
7910 }
7911
7915 public function isActiveTestSubmitted($user_id = null)
7916 {
7917 global $DIC;
7918 $ilUser = $DIC['ilUser'];
7919 $ilDB = $DIC['ilDB'];
7920
7921 if (!is_numeric($user_id)) {
7922 $user_id = $ilUser->getId();
7923 }
7924
7925 $result = $ilDB->queryF(
7926 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
7927 array('integer', 'integer', 'integer'),
7928 array($this->getTestId(), $user_id, 1)
7929 );
7930 return $result->numRows() == 1;
7931 }
7932
7936 public function hasNrOfTriesRestriction()
7937 {
7938 return $this->getNrOfTries() != 0;
7939 }
7940
7941
7947 public function isNrOfTriesReached($tries)
7948 {
7949 return $tries >= (int) $this->getNrOfTries();
7950 }
7951
7952
7961 public function getAllTestResults($participants, $prepareForCSV = true)
7962 {
7963 $results = array();
7964 $row = array(
7965 "user_id" => $this->lng->txt("user_id"),
7966 "matriculation" => $this->lng->txt("matriculation"),
7967 "lastname" => $this->lng->txt("lastname"),
7968 "firstname" => $this->lng->txt("firstname"),
7969 "login" => $this->lng->txt("login"),
7970 "reached_points" => $this->lng->txt("tst_reached_points"),
7971 "max_points" => $this->lng->txt("tst_maximum_points"),
7972 "percent_value" => $this->lng->txt("tst_percent_solved"),
7973 "mark" => $this->lng->txt("tst_mark"),
7974 "ects" => $this->lng->txt("ects_grade")
7975 );
7976 $results[] = $row;
7977 if (count($participants)) {
7978 if ($this->getECTSOutput()) {
7979 $passed_array = &$this->getTotalPointsPassedArray();
7980 }
7981 foreach ($participants as $active_id => $user_rec) {
7982 $mark = $ects_mark = '';
7983 $row = array();
7984 $reached_points = 0;
7985 $max_points = 0;
7986 foreach ($this->questions as $value) {
7987 $question = &ilObjTest::_instanciateQuestion($value);
7988 if (is_object($question)) {
7989 $max_points += $question->getMaximumPoints();
7990 $reached_points += $question->getReachedPoints($active_id);
7991 }
7992 }
7993 if ($max_points > 0) {
7994 $percentvalue = $reached_points / $max_points;
7995 if ($percentvalue < 0) {
7996 $percentvalue = 0.0;
7997 }
7998 } else {
7999 $percentvalue = 0;
8000 }
8001 $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
8002 $passed = "";
8003 if ($mark_obj) {
8004 $mark = $mark_obj->getOfficialName();
8005 if ($this->getECTSOutput()) {
8006 $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
8007 }
8008 }
8009 if ($this->getAnonymity()) {
8010 $user_rec['firstname'] = "";
8011 $user_rec['lastname'] = $this->lng->txt("anonymous");
8012 }
8013 $row = array(
8014 "user_id" => $user_rec['usr_id'],
8015 "matriculation" => $user_rec['matriculation'],
8016 "lastname" => $user_rec['lastname'],
8017 "firstname" => $user_rec['firstname'],
8018 "login" => $user_rec['login'],
8019 "reached_points" => $reached_points,
8020 "max_points" => $max_points,
8021 "percent_value" => $percentvalue,
8022 "mark" => $mark,
8023 "ects" => $ects_mark
8024 );
8025 $results[] = $prepareForCSV ? $this->processCSVRow($row, true) : $row;
8026 }
8027 }
8028 return $results;
8029 }
8030
8041 public function &processCSVRow($row, $quoteAll = false, $separator = ";")
8042 {
8043 $resultarray = array();
8044 foreach ($row as $rowindex => $entry) {
8045 $surround = false;
8046 if ($quoteAll) {
8047 $surround = true;
8048 }
8049 if (strpos($entry, "\"") !== false) {
8050 $entry = str_replace("\"", "\"\"", $entry);
8051 $surround = true;
8052 }
8053 if (strpos($entry, $separator) !== false) {
8054 $surround = true;
8055 }
8056 // replace all CR LF with LF (for Excel for Windows compatibility
8057 $entry = str_replace(chr(13) . chr(10), chr(10), $entry);
8058
8059 if ($surround) {
8060 $entry = "\"" . $entry . "\"";
8061 }
8062
8063 $resultarray[$rowindex] = $entry;
8064 }
8065 return $resultarray;
8066 }
8067
8076 public static function _getPass($active_id)
8077 {
8078 global $DIC;
8079 $ilDB = $DIC['ilDB'];
8080 $result = $ilDB->queryF(
8081 "SELECT tries FROM tst_active WHERE active_id = %s",
8082 array('integer'),
8083 array($active_id)
8084 );
8085 if ($result->numRows()) {
8086 $row = $ilDB->fetchAssoc($result);
8087 return $row["tries"];
8088 } else {
8089 return 0;
8090 }
8091 }
8092
8102 public static function _getMaxPass($active_id)
8103 {
8104 global $DIC;
8105 $ilDB = $DIC['ilDB'];
8106 $result = $ilDB->queryF(
8107 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
8108 array('integer'),
8109 array($active_id)
8110 );
8111 if ($result->numRows()) {
8112 $row = $ilDB->fetchAssoc($result);
8113 $max = $row["maxpass"];
8114 } else {
8115 $max = null;
8116 }
8117 return $max;
8118 }
8119
8125 public static function _getBestPass($active_id)
8126 {
8127 global $DIC;
8128 $ilDB = $DIC['ilDB'];
8129
8130 $result = $ilDB->queryF(
8131 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
8132 array('integer'),
8133 array($active_id)
8134 );
8135 if ($result->numRows()) {
8136 $bestrow = null;
8137 $bestfactor = 0;
8138 while ($row = $ilDB->fetchAssoc($result)) {
8139 if ($row["maxpoints"] > 0) {
8140 $factor = $row["points"] / $row["maxpoints"];
8141 } else {
8142 $factor = 0;
8143 }
8144
8145 if ($factor > $bestfactor) {
8146 $bestrow = $row;
8147 $bestfactor = $factor;
8148 }
8149 }
8150 if (is_array($bestrow)) {
8151 return $bestrow["pass"];
8152 } else {
8153 return 0;
8154 }
8155 } else {
8156 return 0;
8157 }
8158 }
8159
8168 public static function _getResultPass($active_id)
8169 {
8170 $counted_pass = null;
8171 if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS) {
8172 $counted_pass = ilObjTest::_getBestPass($active_id);
8173 } else {
8174 $counted_pass = ilObjTest::_getMaxPass($active_id);
8175 }
8176 return $counted_pass;
8177 }
8178
8188 public function getAnsweredQuestionCount($active_id, $pass = null)
8189 {
8190 if ($this->isDynamicTest()) {
8191 global $DIC;
8192 $tree = $DIC['tree'];
8193 $ilDB = $DIC['ilDB'];
8194 $lng = $DIC['lng'];
8195 $ilPluginAdmin = $DIC['ilPluginAdmin'];
8196
8197 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
8198 $testSessionFactory = new ilTestSessionFactory($this);
8199 $testSession = $testSessionFactory->getSession($active_id);
8200
8201 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
8202 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
8203 $testSequence = $testSequenceFactory->getSequenceByTestSession($testSession);
8204
8205 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
8206 $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
8207 $dynamicQuestionSetConfig->loadFromDb();
8208
8209 $testSequence->loadFromDb($dynamicQuestionSetConfig);
8210 $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
8211
8212 return $testSequence->getTrackedQuestionCount();
8213 }
8214
8215 if ($this->isRandomTest()) {
8216 $this->loadQuestions($active_id, $pass);
8217 }
8218 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
8219 $workedthrough = 0;
8220 foreach ($this->questions as $value) {
8221 if (assQuestion::_isWorkedThrough($active_id, $value, $pass)) {
8222 $workedthrough += 1;
8223 }
8224 }
8225 return $workedthrough;
8226 }
8227
8234 public static function lookupPassResultsUpdateTimestamp($active_id, $pass)
8235 {
8236 global $DIC;
8237 $ilDB = $DIC['ilDB'];
8238
8239 if (is_null($pass)) {
8240 $pass = 0;
8241 }
8242
8243 $query = "
8244 SELECT tst_pass_result.tstamp pass_res_tstamp,
8245 tst_test_result.tstamp quest_res_tstamp
8246
8247 FROM tst_pass_result
8248
8249 LEFT JOIN tst_test_result
8250 ON tst_test_result.active_fi = tst_pass_result.active_fi
8251 AND tst_test_result.pass = tst_pass_result.pass
8252
8253 WHERE tst_pass_result.active_fi = %s
8254 AND tst_pass_result.pass = %s
8255
8256 ORDER BY tst_test_result.tstamp DESC
8257 ";
8258
8259 $result = $ilDB->queryF(
8260 $query,
8261 array('integer', 'integer'),
8262 array($active_id, $pass)
8263 );
8264
8265 while ($row = $ilDB->fetchAssoc($result)) {
8266 if ($row['qres_tstamp']) {
8267 return $row['quest_res_tstamp'];
8268 }
8269
8270 return $row['pass_res_tstamp'];
8271 }
8272
8273 return 0;
8274 }
8275
8284 public function isExecutable($testSession, $user_id, $allowPassIncrease = false)
8285 {
8286 $result = array(
8287 "executable" => true,
8288 "errormessage" => ""
8289 );
8290 if (!$this->startingTimeReached()) {
8291 $result["executable"] = false;
8292 $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getStartingTime(), IL_CAL_UNIX)));
8293 return $result;
8294 }
8295 if ($this->endingTimeReached()) {
8296 $result["executable"] = false;
8297 $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getEndingTime(), IL_CAL_UNIX)));
8298 return $result;
8299 }
8300
8301 $active_id = $this->getActiveIdOfUser($user_id);
8302
8303 if ($this->getEnableProcessingTime()) {
8304 if ($active_id > 0) {
8305 $starting_time = $this->getStartingTimeOfUser($active_id);
8306 if ($starting_time !== false) {
8307 if ($this->isMaxProcessingTimeReached($starting_time, $active_id)) {
8308 if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > (self::_getPass($active_id) + 1)))) {
8309 // a test pass was quitted because the maximum processing time was reached, but the time
8310 // will be resetted for future passes, so if there are more passes allowed, the participant may
8311 // start the test again.
8312 // This code block is only called when $allowPassIncrease is TRUE which only happens when
8313 // the test info page is opened. Otherwise this will lead to unexpected results!
8314 $testSession->increasePass();
8315 $testSession->setLastSequence(0);
8316 $testSession->saveToDb();
8317 } else {
8318 $result["executable"] = false;
8319 $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8320 }
8321 return $result;
8322 }
8323 }
8324 }
8325 }
8326 global $DIC;
8327 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8328 $testPassesSelector = new ilTestPassesSelector($DIC['ilDB'], $this);
8329 $testPassesSelector->setActiveId($active_id);
8330 $testPassesSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8331
8332 if ($this->hasNrOfTriesRestriction() && ($active_id > 0)) {
8333 $closedPasses = $testPassesSelector->getClosedPasses();
8334
8335 if (count($closedPasses) >= $this->getNrOfTries()) {
8336 $result["executable"] = false;
8337 $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8338 return $result;
8339 }
8340 }
8341 if ($this->isPassWaitingEnabled() && $testPassesSelector->getLastFinishedPass() !== null) {
8342 $lastPass = $testPassesSelector->getLastFinishedPassTimestamp();
8343 if ($lastPass && strlen($this->getPassWaiting())) {
8344 $pass_waiting_string = $this->getPassWaiting();
8345 $time_values = explode(":", $pass_waiting_string);
8346 $next_pass_allowed = strtotime('+ ' . $time_values[0] . ' Months + ' . $time_values[1] . ' Days + ' . $time_values[2] . ' Hours' . $time_values[3] . ' Minutes', $lastPass);
8347
8348 if (time() < $next_pass_allowed) {
8349 $date = ilDatePresentation::formatDate(new ilDateTime($next_pass_allowed, IL_CAL_UNIX));
8350
8351 $result["executable"] = false;
8352 $result["errormessage"] = sprintf($this->lng->txt('wait_for_next_pass_hint_msg'), $date);
8353 return $result;
8354 }
8355 }
8356 }
8357 return $result;
8358 }
8359
8360
8362 {
8363 global $DIC; /* @var ILIAS\DI\Container $DIC */
8364
8365 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8366 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
8367
8368 $passSelector->setActiveId($testSession->getActiveId());
8369 $passSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8370
8371 return $passSelector->hasReportablePasses();
8372 }
8373
8375 {
8376 global $DIC; /* @var ILIAS\DI\Container $DIC */
8377
8378 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8379 $passSelector = new ilTestPassesSelector($DIC->database(), $this);
8380
8381 $passSelector->setActiveId($testSession->getActiveId());
8382 $passSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8383
8384 return $passSelector->hasExistingPasses();
8385 }
8386
8394 public function getStartingTimeOfUser($active_id, $pass = null)
8395 {
8396 global $DIC;
8397 $ilDB = $DIC['ilDB'];
8398
8399 if ($active_id < 1) {
8400 return false;
8401 }
8402 if ($pass === null) {
8403 $pass = ($this->getResetProcessingTime()) ? self::_getPass($active_id) : 0;
8404 }
8405 $result = $ilDB->queryF(
8406 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
8407 array('integer', 'integer'),
8408 array($active_id, $pass)
8409 );
8410 if ($result->numRows()) {
8411 $row = $ilDB->fetchAssoc($result);
8412 if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches)) {
8413 return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8414 } else {
8415 return time();
8416 }
8417 } else {
8418 return time();
8419 }
8420 }
8421
8430 public function isMaxProcessingTimeReached($starting_time, $active_id)
8431 {
8432 if ($this->getEnableProcessingTime()) {
8433 $processing_time = $this->getProcessingTimeInSeconds($active_id);
8434 $now = time();
8435 if ($now > ($starting_time + $processing_time)) {
8436 return true;
8437 } else {
8438 return false;
8439 }
8440 } else {
8441 return false;
8442 }
8443 }
8444
8445 public function &getTestQuestions()
8446 {
8447 global $DIC;
8448 $ilDB = $DIC['ilDB'];
8449
8450 $query = "
8451 SELECT questions.*,
8452 questtypes.type_tag,
8453 tstquest.sequence,
8454 tstquest.obligatory,
8455 origquest.obj_fi orig_obj_fi
8456
8457 FROM qpl_questions questions
8458
8459 INNER JOIN qpl_qst_type questtypes
8460 ON questtypes.question_type_id = questions.question_type_fi
8461
8462 INNER JOIN tst_test_question tstquest
8463 ON tstquest.question_fi = questions.question_id
8464
8465 LEFT JOIN qpl_questions origquest
8466 ON origquest.question_id = questions.original_id
8467
8468 WHERE tstquest.test_fi = %s
8469
8470 ORDER BY tstquest.sequence
8471 ";
8472
8473 $query_result = $ilDB->queryF(
8474 $query,
8475 array('integer'),
8476 array($this->getTestId())
8477 );
8478
8479 $questions = array();
8480
8481 while ($row = $ilDB->fetchAssoc($query_result)) {
8482 $question = $row;
8483
8484 $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8485
8486 $questions[] = $question;
8487 }
8488
8489 return $questions;
8490 }
8491
8496 public function isTestQuestion($questionId)
8497 {
8498 foreach ($this->getTestQuestions() as $questionData) {
8499 if ($questionData['question_id'] != $questionId) {
8500 continue;
8501 }
8502
8503 return true;
8504 }
8505
8506 return false;
8507 }
8508
8509 public function checkQuestionParent($questionId)
8510 {
8511 global $DIC; /* @var ILIAS\DI\Container $DIC */
8512
8513 $row = $DIC->database()->fetchAssoc($DIC->database()->queryF(
8514 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
8515 array('integer', 'integer'),
8516 array($questionId, $this->getId())
8517 ));
8518
8519 return (bool) $row['cnt'];
8520 }
8521
8526 {
8527 $points = 0;
8528
8529 foreach ($this->getTestQuestions() as $questionData) {
8530 $points += $questionData['points'];
8531 }
8532
8533 return $points;
8534 }
8535
8540 {
8541 $totalWorkingTime = '00:00:00';
8542
8543 foreach ($this->getTestQuestions() as $questionData) {
8545 $totalWorkingTime,
8546 $questionData['working_time']
8547 );
8548 }
8549
8550 return $totalWorkingTime;
8551 }
8552
8556 public function getPotentialRandomTestQuestions()
8557 {
8561 global $DIC;
8562 $ilDB = $DIC['ilDB'];
8563
8564 $query = "
8565 SELECT questions.*,
8566 questtypes.type_tag,
8567 origquest.obj_fi orig_obj_fi
8568
8569 FROM qpl_questions questions
8570
8571 INNER JOIN qpl_qst_type questtypes
8572 ON questtypes.question_type_id = questions.question_type_fi
8573
8574 INNER JOIN tst_rnd_cpy tstquest
8575 ON tstquest.qst_fi = questions.question_id
8576
8577 LEFT JOIN qpl_questions origquest
8578 ON origquest.question_id = questions.original_id
8579
8580 WHERE tstquest.tst_fi = %s
8581 ";
8582
8583 $query_result = $ilDB->queryF(
8584 $query,
8585 array('integer'),
8586 array($this->getTestId())
8587 );
8588
8589 $questions = array();
8590
8591 while ($row = $ilDB->fetchAssoc($query_result)) {
8592 $question = $row;
8593
8594 $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8595
8596 $questions[] = $question;
8597 }
8598
8599 return $questions;
8600 }
8601
8608 public function getShuffleQuestions()
8609 {
8610 return ($this->shuffle_questions) ? 1 : 0;
8611 }
8612
8619 public function setShuffleQuestions($a_shuffle)
8620 {
8621 $this->shuffle_questions = ($a_shuffle) ? 1 : 0;
8622 }
8623
8637 {
8638 return ($this->show_summary) ? $this->show_summary : 0;
8639 }
8640
8653 public function setListOfQuestionsSettings($a_value = 0)
8654 {
8655 $this->show_summary = $a_value;
8656 }
8657
8664 public function getListOfQuestions()
8665 {
8666 if (($this->show_summary & 1) > 0) {
8667 return true;
8668 } else {
8669 return false;
8670 }
8671 }
8672
8679 public function setListOfQuestions($a_value = true)
8680 {
8681 if ($a_value) {
8682 $this->show_summary = 1;
8683 } else {
8684 $this->show_summary = 0;
8685 }
8686 }
8687
8694 public function getListOfQuestionsStart()
8695 {
8696 if (($this->show_summary & 2) > 0) {
8697 return true;
8698 } else {
8699 return false;
8700 }
8701 }
8702
8709 public function setListOfQuestionsStart($a_value = true)
8710 {
8711 if ($a_value && $this->getListOfQuestions()) {
8712 $this->show_summary = $this->show_summary | 2;
8713 }
8714 if (!$a_value && $this->getListOfQuestions()) {
8715 if ($this->getListOfQuestionsStart()) {
8716 $this->show_summary = $this->show_summary ^ 2;
8717 }
8718 }
8719 }
8720
8727 public function getListOfQuestionsEnd()
8728 {
8729 if (($this->show_summary & 4) > 0) {
8730 return true;
8731 } else {
8732 return false;
8733 }
8734 }
8735
8742 public function setListOfQuestionsEnd($a_value = true)
8743 {
8744 if ($a_value && $this->getListOfQuestions()) {
8745 $this->show_summary = $this->show_summary | 4;
8746 }
8747 if (!$a_value && $this->getListOfQuestions()) {
8748 if ($this->getListOfQuestionsEnd()) {
8749 $this->show_summary = $this->show_summary ^ 4;
8750 }
8751 }
8752 }
8753
8761 {
8762 if (($this->show_summary & 8) > 0) {
8763 return true;
8764 } else {
8765 return false;
8766 }
8767 }
8768
8775 public function setListOfQuestionsDescription($a_value = true)
8776 {
8777 if ($a_value && $this->getListOfQuestions()) {
8778 $this->show_summary = $this->show_summary | 8;
8779 }
8780 if (!$a_value && $this->getListOfQuestions()) {
8781 if ($this->getListOfQuestionsDescription()) {
8782 $this->show_summary = $this->show_summary ^ 8;
8783 }
8784 }
8785 }
8786
8793 public function getResultsPresentation()
8794 {
8795 return ($this->results_presentation) ? $this->results_presentation : 0;
8796 }
8797
8804 public function getShowPassDetails()
8805 {
8806 if (($this->results_presentation & 1) > 0) {
8807 return true;
8808 } else {
8809 return false;
8810 }
8811 }
8812
8819 public function getShowSolutionDetails()
8820 {
8821 if (($this->results_presentation & 2) > 0) {
8822 return true;
8823 } else {
8824 return false;
8825 }
8826 }
8827
8835 {
8836 if (($this->results_presentation & 4) > 0) {
8837 return true;
8838 } else {
8839 return false;
8840 }
8841 }
8842
8849 public function getShowSolutionFeedback()
8850 {
8851 if (($this->results_presentation & 8) > 0) {
8852 return true;
8853 } else {
8854 return false;
8855 }
8856 }
8857
8865 {
8866 if (($this->results_presentation & 16) > 0) {
8867 return true;
8868 } else {
8869 return false;
8870 }
8871 }
8872
8880 {
8881 if (($this->results_presentation & 32) > 0) {
8882 return true;
8883 } else {
8884 return false;
8885 }
8886 }
8887
8893 {
8894 if (($this->results_presentation & 64) > 0) {
8895 return true;
8896 } else {
8897 return false;
8898 }
8899 }
8900
8906 {
8907 if (($this->results_presentation & 128) > 0) {
8908 return true;
8909 } else {
8910 return false;
8911 }
8912 }
8913
8920 public function setResultsPresentation($a_results_presentation = 3)
8921 {
8922 $this->results_presentation = $a_results_presentation;
8923 }
8924
8933 public function setShowPassDetails($a_details = 1)
8934 {
8935 if ($a_details) {
8936 $this->results_presentation = $this->results_presentation | 1;
8937 } else {
8938 if ($this->getShowPassDetails()) {
8939 $this->results_presentation = $this->results_presentation ^ 1;
8940 }
8941 }
8942 }
8943
8950 public function setShowSolutionDetails($a_details = 1)
8951 {
8952 if ($a_details) {
8953 $this->results_presentation = $this->results_presentation | 2;
8954 } else {
8955 if ($this->getShowSolutionDetails()) {
8956 $this->results_presentation = $this->results_presentation ^ 2;
8957 }
8958 }
8959 }
8960
8967 public function canShowSolutionPrintview($user_id = null)
8968 {
8969 return $this->getShowSolutionPrintview();
8970 }
8971
8978 public function setShowSolutionPrintview($a_printview = 1)
8979 {
8980 if ($a_printview) {
8981 $this->results_presentation = $this->results_presentation | 4;
8982 } else {
8983 if ($this->getShowSolutionPrintview()) {
8984 $this->results_presentation = $this->results_presentation ^ 4;
8985 }
8986 }
8987 }
8988
8995 public function setShowSolutionFeedback($a_feedback = true)
8996 {
8997 if ($a_feedback) {
8998 $this->results_presentation = $this->results_presentation | 8;
8999 } else {
9000 if ($this->getShowSolutionFeedback()) {
9001 $this->results_presentation = $this->results_presentation ^ 8;
9002 }
9003 }
9004 }
9005
9012 public function setShowSolutionAnswersOnly($a_full = true)
9013 {
9014 if ($a_full) {
9015 $this->results_presentation = $this->results_presentation | 16;
9016 } else {
9017 if ($this->getShowSolutionAnswersOnly()) {
9018 $this->results_presentation = $this->results_presentation ^ 16;
9019 }
9020 }
9021 }
9022
9029 public function setShowSolutionSignature($a_signature = false)
9030 {
9031 if ($a_signature) {
9032 $this->results_presentation = $this->results_presentation | 32;
9033 } else {
9034 if ($this->getShowSolutionSignature()) {
9035 $this->results_presentation = $this->results_presentation ^ 32;
9036 }
9037 }
9038 }
9039
9046 public function setShowSolutionSuggested($a_solution = false)
9047 {
9048 if ($a_solution) {
9049 $this->results_presentation = $this->results_presentation | 64;
9050 } else {
9051 if ($this->getShowSolutionSuggested()) {
9052 $this->results_presentation = $this->results_presentation ^ 64;
9053 }
9054 }
9055 }
9056
9062 public function setShowSolutionListComparison($a_comparison = false)
9063 {
9064 if ($a_comparison) {
9065 $this->results_presentation = $this->results_presentation | 128;
9066 } else {
9067 if ($this->getShowSolutionListComparison()) {
9068 $this->results_presentation = $this->results_presentation ^ 128;
9069 }
9070 }
9071 }
9072
9076 public static function _getUserIdFromActiveId($active_id)
9077 {
9078 global $DIC;
9079 $ilDB = $DIC['ilDB'];
9080 $result = $ilDB->queryF(
9081 "SELECT user_fi FROM tst_active WHERE active_id = %s",
9082 array('integer'),
9083 array($active_id)
9084 );
9085 if ($result->numRows()) {
9086 $row = $ilDB->fetchAssoc($result);
9087 return $row["user_fi"];
9088 } else {
9089 return -1;
9090 }
9091 }
9092
9096 public function isLimitUsersEnabled()
9097 {
9099 }
9100
9105 {
9106 $this->limitUsersEnabled = $limitUsersEnabled;
9107 }
9108
9109 public function getAllowedUsers()
9110 {
9111 return ($this->allowedUsers) ? $this->allowedUsers : 0;
9112 }
9113
9114 public function setAllowedUsers($a_allowed_users)
9115 {
9116 $this->allowedUsers = $a_allowed_users;
9117 }
9118
9119 public function getAllowedUsersTimeGap()
9120 {
9121 return ($this->allowedUsersTimeGap) ? $this->allowedUsersTimeGap : 0;
9122 }
9123
9124 public function setAllowedUsersTimeGap($a_allowed_users_time_gap)
9125 {
9126 $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
9127 }
9128
9130 {
9131 global $DIC;
9132 $ilDB = $DIC['ilDB'];
9133
9134 $nr_of_users = $this->getAllowedUsers();
9135 $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
9136 if (($nr_of_users > 0) && ($time_gap > 0)) {
9137 $now = time();
9138 $time_border = $now - $time_gap;
9139 $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
9140 $query = "
9141 SELECT DISTINCT tst_times.active_fi
9142 FROM tst_times
9143 INNER JOIN tst_active
9144 ON tst_times.active_fi = tst_active.active_id
9145 AND (
9146 tst_times.pass > tst_active.last_finished_pass OR tst_active.last_finished_pass IS NULL
9147 )
9148 WHERE tst_times.tstamp > %s
9149 AND tst_active.test_fi = %s
9150 ";
9151 $result = $ilDB->queryF($query, array('integer', 'integer'), array($time_border, $this->getTestId()));
9152 if ($result->numRows() >= $nr_of_users) {
9153 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
9155 $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
9156 }
9157 return false;
9158 } else {
9159 return true;
9160 }
9161 }
9162 return true;
9163 }
9164
9165 public function _getLastAccess($active_id)
9166 {
9167 global $DIC;
9168 $ilDB = $DIC['ilDB'];
9169
9170 $result = $ilDB->queryF(
9171 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
9172 array('integer'),
9173 array($active_id)
9174 );
9175 if ($result->numRows()) {
9176 $row = $ilDB->fetchAssoc($result);
9177 return $row["finished"];
9178 }
9179 return "";
9180 }
9181
9182 public static function lookupLastTestPassAccess($activeId, $passIndex)
9183 {
9184 global $DIC; /* @var \ILIAS\DI\Container $DIC */
9185
9186 $query = "
9187 SELECT MAX(tst_times.tstamp) as last_pass_access
9188 FROM tst_times
9189 WHERE active_fi = %s
9190 AND pass = %s
9191 ";
9192
9193 $res = $DIC->database()->queryF(
9194 $query,
9195 array('integer', 'integer'),
9196 array($activeId, $passIndex)
9197 );
9198
9199 while ($row = $DIC->database()->fetchAssoc($res)) {
9200 return $row['last_pass_access'];
9201 }
9202
9203 return null;
9204 }
9205
9213 public function isHTML($a_text)
9214 {
9215 if (preg_match("/<[^>]*?>/", $a_text)) {
9216 return true;
9217 } else {
9218 return false;
9219 }
9220 }
9221
9229 public function QTIMaterialToString($a_material)
9230 {
9231 $result = "";
9232 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
9233 $material = $a_material->getMaterial($i);
9234 if (strcmp($material["type"], "mattext") == 0) {
9235 $result .= $material["material"]->getContent();
9236 }
9237 if (strcmp($material["type"], "matimage") == 0) {
9238 $matimage = $material["material"];
9239 if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) {
9240 // import an mediaobject which was inserted using tiny mce
9241 if (!is_array($_SESSION["import_mob_xhtml"])) {
9242 $_SESSION["import_mob_xhtml"] = array();
9243 }
9244 array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
9245 }
9246 }
9247 }
9248 global $DIC;
9249 $ilLog = $DIC['ilLog'];
9250 $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
9251 return $result;
9252 }
9253
9262 public function addQTIMaterial(&$a_xml_writer, $a_material)
9263 {
9264 include_once "./Services/RTE/classes/class.ilRTE.php";
9265 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9266
9267 $a_xml_writer->xmlStartTag("material");
9268 $attrs = array(
9269 "texttype" => "text/plain"
9270 );
9271 if ($this->isHTML($a_material)) {
9272 $attrs["texttype"] = "text/xhtml";
9273 }
9274 $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
9275
9276 $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9277 foreach ($mobs as $mob) {
9278 $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9279 if (strpos($a_material, "mm_$mob") !== false) {
9280 if (ilObjMediaObject::_exists($mob)) {
9281 $mob_obj = new ilObjMediaObject($mob);
9282 $imgattrs = array(
9283 "label" => $moblabel,
9284 "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9285 );
9286 }
9287 $a_xml_writer->xmlElement("matimage", $imgattrs, null);
9288 }
9289 }
9290 $a_xml_writer->xmlEndTag("material");
9291 }
9292
9299 public function prepareTextareaOutput($txt_output, $prepare_for_latex_output = false, $omitNl2BrWhenTextArea = false)
9300 {
9301 include_once "./Services/Utilities/classes/class.ilUtil.php";
9302 return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output, $omitNl2BrWhenTextArea);
9303 }
9304
9311 public function saveCertificateVisibility($a_value)
9312 {
9313 global $DIC;
9314 $ilDB = $DIC['ilDB'];
9315
9316 $affectedRows = $ilDB->manipulateF(
9317 "UPDATE tst_tests SET certificate_visibility = %s, tstamp = %s WHERE test_id = %s",
9318 array('text', 'integer', 'integer'),
9319 array($a_value, time(), $this->getTestId())
9320 );
9321 }
9322
9330 {
9331 return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0;
9332 }
9333
9340 public function setCertificateVisibility($a_value)
9341 {
9342 $this->certificate_visibility = $a_value;
9343 }
9344
9351 public function getAnonymity()
9352 {
9353 return ($this->anonymity) ? 1 : 0;
9354 }
9355
9362 public function setAnonymity($a_value = 0)
9363 {
9364 switch ($a_value) {
9365 case 1:
9366 $this->anonymity = 1;
9367 break;
9368 default:
9369 $this->anonymity = 0;
9370 break;
9371 }
9372 }
9373
9380 public function getShowCancel()
9381 {
9382 return ($this->show_cancel) ? 1 : 0;
9383 }
9384
9391 public function setShowCancel($a_value = 1)
9392 {
9393 switch ($a_value) {
9394 case 1:
9395 $this->show_cancel = 1;
9396 break;
9397 default:
9398 $this->show_cancel = 0;
9399 break;
9400 }
9401 }
9402
9409 public function getShowMarker()
9410 {
9411 return ($this->show_marker) ? 1 : 0;
9412 }
9413
9420 public function setShowMarker($a_value = 1)
9421 {
9422 switch ($a_value) {
9423 case 1:
9424 $this->show_marker = 1;
9425 break;
9426 default:
9427 $this->show_marker = 0;
9428 break;
9429 }
9430 }
9431
9438 public function getFixedParticipants()
9439 {
9440 return ($this->fixed_participants) ? 1 : 0;
9441 }
9442
9449 public function setFixedParticipants($a_value = 1)
9450 {
9451 switch ($a_value) {
9452 case 1:
9453 $this->fixed_participants = 1;
9454 break;
9455 default:
9456 $this->fixed_participants = 0;
9457 break;
9458 }
9459 }
9460
9468 public static function _lookupAnonymity($a_obj_id)
9469 {
9470 global $DIC;
9471 $ilDB = $DIC['ilDB'];
9472
9473 $result = $ilDB->queryF(
9474 "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
9475 array('integer'),
9476 array($a_obj_id)
9477 );
9478 while ($row = $ilDB->fetchAssoc($result)) {
9479 return $row['anonymity'];
9480 }
9481 return 0;
9482 }
9483
9490 public static function lookupQuestionSetTypeByActiveId($active_id)
9491 {
9492 global $DIC;
9493 $ilDB = $DIC['ilDB'];
9494
9495 $query = "
9496 SELECT tst_tests.question_set_type
9497 FROM tst_active
9498 INNER JOIN tst_tests
9499 ON tst_active.test_fi = tst_tests.test_id
9500 WHERE tst_active.active_id = %s
9501 ";
9502
9503 $res = $ilDB->queryF($query, array('integer'), array($active_id));
9504
9505 while ($row = $ilDB->fetchAssoc($res)) {
9506 return $row['question_set_type'];
9507 }
9508
9509 return null;
9510 }
9511
9520 public function _lookupRandomTestFromActiveId($active_id)
9521 {
9522 throw new Exception(__METHOD__ . ' is deprecated ... use ilObjTest::lookupQuestionSetTypeByActiveId() instead!');
9523
9524 global $DIC;
9525 $ilDB = $DIC['ilDB'];
9526
9527 $result = $ilDB->queryF(
9528 "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",
9529 array('integer'),
9530 array($active_id)
9531 );
9532 while ($row = $ilDB->fetchAssoc($result)) {
9533 return $row['random_test'];
9534 }
9535 return 0;
9536 }
9537
9548 public function userLookupFullName($user_id, $overwrite_anonymity = false, $sorted_order = false, $suffix = "")
9549 {
9550 if ($this->getAnonymity() && !$overwrite_anonymity) {
9551 return $this->lng->txt("anonymous") . $suffix;
9552 } else {
9553 include_once './Services/User/classes/class.ilObjUser.php';
9554 $uname = ilObjUser::_lookupName($user_id);
9555 if (strlen($uname["firstname"] . $uname["lastname"]) == 0) {
9556 $uname["firstname"] = $this->lng->txt("deleted_user");
9557 }
9558 if ($sorted_order) {
9559 return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9560 } else {
9561 return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9562 }
9563 }
9564 }
9565
9573 public function getStartTestLabel($active_id)
9574 {
9575 if ($this->getNrOfTries() == 1) {
9576 return $this->lng->txt("tst_start_test");
9577 }
9578 $active_pass = self::_getPass($active_id);
9579 $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9580 if ($res == 0) {
9581 if ($active_pass == 0) {
9582 return $this->lng->txt("tst_start_test");
9583 } else {
9584 return $this->lng->txt("tst_start_new_test_pass");
9585 }
9586 } else {
9587 return $this->lng->txt("tst_resume_test");
9588 }
9589 }
9590
9596 public function getAvailableDefaults()
9597 {
9602 global $DIC;
9603 $ilDB = $DIC['ilDB'];
9604 $ilUser = $DIC['ilUser'];
9605
9606 $result = $ilDB->queryF(
9607 "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
9608 array('integer'),
9609 array($ilUser->getId())
9610 );
9611 $defaults = array();
9612 while ($row = $ilDB->fetchAssoc($result)) {
9613 $defaults[$row["test_defaults_id"]] = $row;
9614 }
9615 return $defaults;
9616 }
9617
9625 public function &getTestDefaults($test_defaults_id)
9626 {
9627 return self::_getTestDefaults($test_defaults_id);
9628 }
9629
9630 public static function _getTestDefaults($test_defaults_id)
9631 {
9632 global $DIC;
9633 $ilDB = $DIC['ilDB'];
9634
9635 $result = $ilDB->queryF(
9636 "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9637 array('integer'),
9638 array($test_defaults_id)
9639 );
9640 if ($result->numRows() == 1) {
9641 $row = $ilDB->fetchAssoc($result);
9642 return $row;
9643 } else {
9644 return null;
9645 }
9646 }
9647
9654 public function deleteDefaults($test_default_id)
9655 {
9656 global $DIC;
9657 $ilDB = $DIC['ilDB'];
9658 $affectedRows = $ilDB->manipulateF(
9659 "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9660 array('integer'),
9661 array($test_default_id)
9662 );
9663 }
9664
9671 public function addDefaults($a_name)
9672 {
9673 global $DIC;
9674 $ilDB = $DIC['ilDB'];
9675 $ilUser = $DIC['ilUser'];
9676 $testsettings = array(
9677 "TitleOutput" => $this->getTitleOutput(),
9678 "PassScoring" => $this->getPassScoring(),
9679 "IntroEnabled" => $this->isIntroductionEnabled(),
9680 "Introduction" => $this->getIntroduction(),
9681 "FinalStatement" => $this->getFinalStatement(),
9682 "ShowInfo" => $this->getShowInfo(),
9683 "ForceJS" => $this->getForceJS(),
9684 "CustomStyle" => $this->getCustomStyle(),
9685 "ShowFinalStatement" => $this->getShowFinalStatement(),
9686 "SequenceSettings" => $this->getSequenceSettings(),
9687 "ScoreReporting" => $this->getScoreReporting(),
9688 "ScoreCutting" => $this->getScoreCutting(),
9689 'SpecificAnswerFeedback' => $this->getSpecificAnswerFeedback(),
9690 'PrintBsWithRes' => (int) $this->isBestSolutionPrintedWithResult(),
9691 "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9692 "AnswerFeedback" => $this->getAnswerFeedback(),
9693 "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9694 "ResultsPresentation" => $this->getResultsPresentation(),
9695 "Anonymity" => $this->getAnonymity(),
9696 "ShowCancel" => $this->getShowCancel(),
9697 "ShowMarker" => $this->getShowMarker(),
9698 "ReportingDate" => $this->getReportingDate(),
9699 "NrOfTries" => $this->getNrOfTries(),
9700 "Shuffle" => $this->getShuffleQuestions(),
9701 "Kiosk" => $this->getKiosk(),
9702 "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9703 "ProcessingTime" => $this->getProcessingTime(),
9704 "EnableProcessingTime" => $this->getEnableProcessingTime(),
9705 "ResetProcessingTime" => $this->getResetProcessingTime(),
9706 "StartingTimeEnabled" => $this->isStartingTimeEnabled(),
9707 "StartingTime" => $this->getStartingTime(),
9708 "EndingTimeEnabled" => $this->isEndingTimeEnabled(),
9709 "EndingTime" => $this->getEndingTime(),
9710 "ECTSOutput" => $this->getECTSOutput(),
9711 "ECTSFX" => $this->getECTSFX(),
9712 "ECTSGrades" => $this->getECTSGrades(),
9713 "questionSetType" => $this->getQuestionSetType(),
9714 "CountSystem" => $this->getCountSystem(),
9715 "MCScoring" => $this->getMCScoring(),
9716 "mailnotification" => $this->getMailNotification(),
9717 "mailnottype" => $this->getMailNotificationType(),
9718 "exportsettings" => $this->getExportSettings(),
9719 "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings(),
9720 'obligations_enabled' => (int) $this->areObligationsEnabled(),
9721 'offer_question_hints' => (int) $this->isOfferingQuestionHintsEnabled(),
9722 'pass_deletion_allowed' => (int) $this->isPassDeletionAllowed(),
9723 'enable_examview' => $this->getEnableExamview(),
9724 'show_examview_html' => $this->getShowExamviewHtml(),
9725 'show_examview_pdf' => $this->getShowExamviewPdf(),
9726 'char_selector_availability' => $this->getCharSelectorAvailability(),
9727 'char_selector_definition' => $this->getCharSelectorDefinition(),
9728 'skill_service' => (int) $this->isSkillServiceEnabled(),
9729 'result_tax_filters' => (array) $this->getResultFilterTaxIds(),
9730 'show_grading_status' => (int) $this->isShowGradingStatusEnabled(),
9731 'show_grading_mark' => (int) $this->isShowGradingMarkEnabled(),
9732
9733 'follow_qst_answer_fixation' => $this->isFollowupQuestionAnswerFixationEnabled(),
9734 'inst_fb_answer_fixation' => $this->isInstantFeedbackAnswerFixationEnabled(),
9735 'force_inst_fb' => $this->isForceInstantFeedbackEnabled(),
9736 'redirection_mode' => $this->getRedirectionMode(),
9737 'redirection_url' => $this->getRedirectionUrl(),
9738 'sign_submission' => $this->getSignSubmission(),
9739 'autosave' => (int) $this->getAutosave(),
9740 'autosave_ival' => (int) $this->getAutosaveIval(),
9741 'examid_in_test_pass' => (int) $this->isShowExamIdInTestPassEnabled(),
9742 'examid_in_test_res' => (int) $this->isShowExamIdInTestResultsEnabled(),
9743
9744 'enable_archiving' => (int) $this->getEnableArchiving(),
9745 'password_enabled' => (int) $this->isPasswordEnabled(),
9746 'password' => (string) $this->getPassword(),
9747 'fixed_participants' => $this->getFixedParticipants(),
9748 'limit_users_enabled' => $this->isLimitUsersEnabled(),
9749 'allowedusers' => $this->getAllowedUsers(),
9750 'alloweduserstimegap' => $this->getAllowedUsersTimeGap(),
9751 'pool_usage' => $this->getPoolUsage(),
9752 'activation_limited' => $this->isActivationLimited(),
9753 'activation_start_time' => $this->getActivationStartingTime(),
9754 'activation_end_time' => $this->getActivationEndingTime(),
9755 'activation_visibility' => $this->getActivationVisibility(),
9756 'highscore_enabled' => $this->getHighscoreEnabled(),
9757 'highscore_anon' => $this->getHighscoreAnon(),
9758 'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
9759 'highscore_score' => $this->getHighscoreScore(),
9760 'highscore_percentage' => $this->getHighscorePercentage(),
9761 'highscore_hints' => $this->getHighscoreHints(),
9762 'highscore_wtime' => $this->getHighscoreWTime(),
9763 'highscore_own_table' => $this->getHighscoreOwnTable(),
9764 'highscore_top_table' => $this->getHighscoreTopTable(),
9765 'highscore_top_num' => $this->getHighscoreTopNum(),
9766 'use_previous_answers' => (string) $this->getUsePreviousAnswers(),
9767 'pass_waiting' => $this->getPassWaiting()
9768 );
9769
9770 $next_id = $ilDB->nextId('tst_test_defaults');
9771 $ilDB->insert(
9772 'tst_test_defaults',
9773 array(
9774 'test_defaults_id' => array('integer', $next_id),
9775 'name' => array('text', $a_name),
9776 'user_fi' => array('integer', $ilUser->getId()),
9777 'defaults' => array('clob', serialize($testsettings)),
9778 'marks' => array('clob', serialize($this->mark_schema)),
9779 'tstamp' => array('integer', time())
9780 )
9781 );
9782 }
9783
9791 public function applyDefaults($test_defaults)
9792 {
9793 $testsettings = unserialize($test_defaults["defaults"]);
9794 include_once "./Modules/Test/classes/class.assMarkSchema.php";
9795 $this->mark_schema = unserialize($test_defaults["marks"]);
9796
9797 $this->setTitleOutput($testsettings["TitleOutput"]);
9798 $this->setPassScoring($testsettings["PassScoring"]);
9799 $this->setIntroductionEnabled($testsettings["IntroEnabled"]);
9800 $this->setIntroduction($testsettings["Introduction"]);
9801 $this->setFinalStatement($testsettings["FinalStatement"]);
9802 $this->setShowInfo($testsettings["ShowInfo"]);
9803 $this->setForceJS($testsettings["ForceJS"]);
9804 $this->setCustomStyle($testsettings["CustomStyle"]);
9805 $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
9806 $this->setSequenceSettings($testsettings["SequenceSettings"]);
9807 $this->setScoreReporting($testsettings["ScoreReporting"]);
9808 $this->setScoreCutting($testsettings['ScoreCutting']);
9809 $this->setSpecificAnswerFeedback($testsettings['SpecificAnswerFeedback']);
9810 $this->setPrintBestSolutionWithResult((bool) $testsettings['PrintBsWithRes']);
9811 $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
9812 $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
9813 $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
9814 $this->setResultsPresentation($testsettings["ResultsPresentation"]);
9815 $this->setAnonymity($testsettings["Anonymity"]);
9816 $this->setShowCancel($testsettings["ShowCancel"]);
9817 $this->setShuffleQuestions($testsettings["Shuffle"]);
9818 $this->setShowMarker($testsettings["ShowMarker"]);
9819 $this->setReportingDate($testsettings["ReportingDate"]);
9820 $this->setNrOfTries($testsettings["NrOfTries"]);
9821 $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
9822 $this->setRedirectionMode($testsettings['redirection_mode']);
9823 $this->setRedirectionUrl($testsettings['redirection_url']);
9824 $this->setProcessingTime($testsettings["ProcessingTime"]);
9825 $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
9826 $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
9827 $this->setStartingTimeEnabled($testsettings["StartingTimeEnabled"]);
9828 $this->setStartingTime($testsettings["StartingTime"]);
9829 $this->setKiosk($testsettings["Kiosk"]);
9830 $this->setEndingTimeEnabled($testsettings["EndingTimeEnabled"]);
9831 $this->setEndingTime($testsettings["EndingTime"]);
9832 $this->setECTSOutput($testsettings["ECTSOutput"]);
9833 $this->setECTSFX($testsettings["ECTSFX"]);
9834 $this->setECTSGrades($testsettings["ECTSGrades"]);
9835 if (isset($testsettings["isRandomTest"])) {
9836 if ($testsettings["isRandomTest"]) {
9837 $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
9838 } else {
9839 $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
9840 }
9841 } elseif (isset($testsettings["questionSetType"])) {
9842 $this->setQuestionSetType($testsettings["questionSetType"]);
9843 }
9844 $this->setCountSystem($testsettings["CountSystem"]);
9845 $this->setMCScoring($testsettings["MCScoring"]);
9846 $this->setMailNotification($testsettings["mailnotification"]);
9847 $this->setMailNotificationType($testsettings["mailnottype"]);
9848 $this->setExportSettings($testsettings['exportsettings']);
9849 $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
9850 $this->setObligationsEnabled($testsettings["obligations_enabled"]);
9851 $this->setOfferingQuestionHintsEnabled($testsettings["offer_question_hints"]);
9852 $this->setHighscoreEnabled($testsettings['highscore_enabled']);
9853 $this->setHighscoreAnon($testsettings['highscore_anon']);
9854 $this->setHighscoreAchievedTS($testsettings['highscore_achieved_ts']);
9855 $this->setHighscoreScore($testsettings['highscore_score']);
9856 $this->setHighscorePercentage($testsettings['highscore_percentage']);
9857 $this->setHighscoreHints($testsettings['highscore_hints']);
9858 $this->setHighscoreWTime($testsettings['highscore_wtime']);
9859 $this->setHighscoreOwnTable($testsettings['highscore_own_table']);
9860 $this->setHighscoreTopTable($testsettings['highscore_top_table']);
9861 $this->setHighscoreTopNum($testsettings['highscore_top_num']);
9862 $this->setPassDeletionAllowed($testsettings['pass_deletion_allowed']);
9863 if (isset($testsettings['examid_in_kiosk'])) {
9864 $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_kiosk']);
9865 } else {
9866 $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_test_pass']);
9867 }
9868 if (isset($testsettings['show_exam_id'])) {
9869 $this->setShowExamIdInTestResultsEnabled($testsettings['show_exam_id']);
9870 } else {
9871 $this->setShowExamIdInTestResultsEnabled($testsettings['examid_in_test_res']);
9872 }
9873 $this->setEnableExamview($testsettings['enable_examview']);
9874 $this->setShowExamviewHtml($testsettings['show_examview_html']);
9875 $this->setShowExamviewPdf($testsettings['show_examview_pdf']);
9876 $this->setEnableArchiving($testsettings['enable_archiving']);
9877 $this->setSignSubmission($testsettings['sign_submission']);
9878 $this->setCharSelectorAvailability($testsettings['char_selector_availability']);
9879 $this->setCharSelectorDefinition($testsettings['char_selector_definition']);
9880 $this->setSkillServiceEnabled((bool) $testsettings['skill_service']);
9881 $this->setResultFilterTaxIds((array) $testsettings['result_tax_filters']);
9882 $this->setShowGradingStatusEnabled((bool) $testsettings['show_grading_status']);
9883 $this->setShowGradingMarkEnabled((bool) $testsettings['show_grading_mark']);
9884
9885 $this->setFollowupQuestionAnswerFixationEnabled($testsettings['follow_qst_answer_fixation']);
9886 $this->setInstantFeedbackAnswerFixationEnabled($testsettings['inst_fb_answer_fixation']);
9887 $this->setForceInstantFeedbackEnabled($testsettings['force_inst_fb']);
9888 $this->setRedirectionMode($testsettings['redirection_mode']);
9889 $this->setRedirectionUrl($testsettings['redirection_url']);
9890
9891 $this->setAutosave($testsettings['autosave']);
9892 $this->setAutosaveIval($testsettings['autosave_ival']);
9893 $this->setShowExamIdInTestResultsEnabled((int) $testsettings['examid_in_test_res']);
9894 $this->setPasswordEnabled($testsettings['password_enabled']);
9895 $this->setPassword($testsettings['password']);
9896 $this->setFixedParticipants($testsettings['fixed_participants']);
9897 $this->setLimitUsersEnabled($testsettings['limit_users_enabled']);
9898 $this->setAllowedUsers($testsettings['allowedusers']);
9899 $this->setAllowedUsersTimeGap($testsettings['alloweduserstimegap']);
9900 $this->setUsePreviousAnswers($testsettings['use_previous_answers']);
9901 $this->setPoolUsage($testsettings['pool_usage']);
9902 $this->setActivationLimited($testsettings['activation_limited']);
9903 $this->setActivationStartingTime($testsettings['activation_start_time']);
9904 $this->setActivationEndingTime($testsettings['activation_end_time']);
9905 $this->setActivationVisibility($testsettings['activation_visibility']);
9906 $this->setPassWaiting($testsettings['pass_waiting']);
9907
9908 $this->saveToDb();
9909
9910 return true;
9911 }
9912
9920 public function processPrintoutput2FO($print_output)
9921 {
9922 if (extension_loaded("tidy")) {
9923 $config = array(
9924 "indent" => false,
9925 "output-xml" => true,
9926 "numeric-entities" => true
9927 );
9928 $tidy = new tidy();
9929 $tidy->parseString($print_output, $config, 'utf8');
9930 $tidy->cleanRepair();
9931 $print_output = tidy_get_output($tidy);
9932 $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
9933 } else {
9934 $print_output = str_replace("&nbsp;", "&#160;", $print_output);
9935 $print_output = str_replace("&otimes;", "X", $print_output);
9936 }
9937 $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
9938
9939 // additional font support
9940 global $DIC;
9941 $xsl = str_replace(
9942 'font-family="Helvetica, unifont"',
9943 'font-family="' . $DIC['ilSetting']->get('rpc_pdf_font', 'Helvetica, unifont') . '"',
9944 $xsl
9945 );
9946
9947 $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
9948 $xh = xslt_create();
9949 $params = array();
9950 $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", null, $args, $params);
9951 xslt_error($xh);
9952 xslt_free($xh);
9953 return $output;
9954 }
9955
9962 public function deliverPDFfromHTML($content, $title = null)
9963 {
9964 $content = preg_replace("/href=\".*?\"/", "", $content);
9965 $printbody = new ilTemplate("tpl.il_as_tst_print_body.html", true, true, "Modules/Test");
9966 $printbody->setVariable("TITLE", ilUtil::prepareFormOutput($this->getTitle()));
9967 $printbody->setVariable("ADM_CONTENT", $content);
9968 $printbody->setCurrentBlock("css_file");
9969 $printbody->setVariable("CSS_FILE", $this->getTestStyleLocation("filesystem"));
9970 $printbody->parseCurrentBlock();
9971 $printbody->setCurrentBlock("css_file");
9972 $printbody->setVariable("CSS_FILE", ilUtil::getStyleSheetLocation("filesystem", "delos.css"));
9973 $printbody->parseCurrentBlock();
9974 $printoutput = $printbody->get();
9975 $html = str_replace("href=\"./", "href=\"" . ILIAS_HTTP_PATH . "/", $printoutput);
9976 $html = preg_replace("/<div id=\"dontprint\">.*?<\\/div>/ims", "", $html);
9977 if (extension_loaded("tidy")) {
9978 $config = array(
9979 "indent" => false,
9980 "output-xml" => true,
9981 "numeric-entities" => true
9982 );
9983 $tidy = new tidy();
9984 $tidy->parseString($html, $config, 'utf8');
9985 $tidy->cleanRepair();
9986 $html = tidy_get_output($tidy);
9987 $html = preg_replace("/^.*?(<html)/", "\\1", $html);
9988 } else {
9989 $html = str_replace("&nbsp;", "&#160;", $html);
9990 $html = str_replace("&otimes;", "X", $html);
9991 }
9992 $html = preg_replace("/src=\".\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
9994 }
9995
10002 public function deliverPDFfromFO($fo, $title = null)
10003 {
10004 global $DIC;
10005 $ilLog = $DIC['ilLog'];
10006
10007 include_once "./Services/Utilities/classes/class.ilUtil.php";
10008 $fo_file = ilUtil::ilTempnam() . ".fo";
10009 $fp = fopen($fo_file, "w");
10010 fwrite($fp, $fo);
10011 fclose($fp);
10012
10013 include_once './Services/WebServices/RPC/classes/class.ilRpcClientFactory.php';
10014 try {
10015 $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo);
10016 $filename = (strlen($title)) ? $title : $this->getTitle();
10017 ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
10018 return true;
10019 } catch (Exception $e) {
10020 $ilLog->write(__METHOD__ . ': ' . $e->getMessage());
10021 return false;
10022 }
10023 }
10024
10034 public static function getManualFeedback($active_id, $question_id, $pass)
10035 {
10036 global $DIC;
10037 $ilDB = $DIC['ilDB'];
10038 $feedback = "";
10039 $result = $ilDB->queryF(
10040 "SELECT feedback FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10041 array('integer', 'integer', 'integer'),
10042 array($active_id, $question_id, $pass)
10043 );
10044 if ($result->numRows()) {
10045 $row = $ilDB->fetchAssoc($result);
10046 include_once("./Services/RTE/classes/class.ilRTE.php");
10047 $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
10048 }
10049 return $feedback;
10050 }
10051
10062 public function saveManualFeedback($active_id, $question_id, $pass, $feedback)
10063 {
10064 global $DIC;
10065 $ilDB = $DIC['ilDB'];
10066
10067 $affectedRows = $ilDB->manipulateF(
10068 "DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10069 array('integer', 'integer', 'integer'),
10070 array($active_id, $question_id, $pass)
10071 );
10072
10073 if (strlen($feedback)) {
10074 $next_id = $ilDB->nextId('tst_manual_fb');
10076 $result = $ilDB->insert(
10077 'tst_manual_fb',
10078 array(
10079 'manual_feedback_id' => array( 'integer', $next_id ),
10080 'active_fi' => array( 'integer', $active_id ),
10081 'question_fi' => array( 'integer', $question_id ),
10082 'pass' => array( 'integer', $pass),
10083 'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc($feedback, 0) ),
10084 'tstamp' => array( 'integer', time() ),
10085 )
10086 );
10087 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
10089 global $DIC;
10090 $lng = $DIC['lng'];
10091 $ilUser = $DIC['ilUser'];
10092 include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
10093 $username = ilObjTestAccess::_getParticipantData($active_id);
10094 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10095 $this->logAction(sprintf($lng->txtlng("assessment", "log_manual_feedback", ilObjAssessmentFolder::_getLogLanguage()), $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")", $username, assQuestion::_getQuestionTitle($question_id), $feedback));
10096 }
10097 }
10098 return true;
10099 }
10100
10108 public function getJavaScriptOutput()
10109 {
10110 return true;
10111
10112 // global $DIC;
10113// $ilUser = $DIC['ilUser'];
10114// if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
10115// if ($this->getForceJS()) return TRUE;
10116// $assessmentSetting = new ilSetting("assessment");
10117// return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
10118 }
10119
10120 public function &createTestSequence($active_id, $pass, $shuffle)
10121 {
10122 include_once "./Modules/Test/classes/class.ilTestSequence.php";
10123 $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10124 }
10125
10131 public function setTestId($a_id)
10132 {
10133 $this->test_id = $a_id;
10134 }
10135
10144 public function getDetailedTestResults($participants)
10145 {
10146 $results = array();
10147 if (count($participants)) {
10148 foreach ($participants as $active_id => $user_rec) {
10149 $row = array();
10150 $reached_points = 0;
10151 $max_points = 0;
10152 foreach ($this->questions as $value) {
10153 $question = &ilObjTest::_instanciateQuestion($value);
10154 if (is_object($question)) {
10155 $max_points += $question->getMaximumPoints();
10156 $reached_points += $question->getReachedPoints($active_id);
10157 if ($max_points > 0) {
10158 $percentvalue = $reached_points / $max_points;
10159 if ($percentvalue < 0) {
10160 $percentvalue = 0.0;
10161 }
10162 } else {
10163 $percentvalue = 0;
10164 }
10165 if ($this->getAnonymity()) {
10166 $user_rec['firstname'] = "";
10167 $user_rec['lastname'] = $this->lng->txt("anonymous");
10168 }
10169 $row = array(
10170 "user_id" => $user_rec['usr_id'],
10171 "matriculation" => $user_rec['matriculation'],
10172 "lastname" => $user_rec['lastname'],
10173 "firstname" => $user_rec['firstname'],
10174 "login" => $user_rec['login'],
10175 "question_id" => $question->getId(),
10176 "question_title" => $question->getTitle(),
10177 "reached_points" => $reached_points,
10178 "max_points" => $max_points
10179 );
10180 $results[] = $row;
10181 }
10182 }
10183 }
10184 }
10185 return $results;
10186 }
10187
10191 public static function _lookupTestObjIdForQuestionId($a_q_id)
10192 {
10193 global $DIC;
10194 $ilDB = $DIC['ilDB'];
10195
10196 $result = $ilDB->queryF(
10197 "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",
10198 array('integer'),
10199 array($a_q_id)
10200 );
10201 $rec = $ilDB->fetchAssoc($result);
10202 return $rec["obj_id"];
10203 }
10204
10211 public function isPluginActive($a_pname)
10212 {
10213 global $DIC;
10214 $ilPluginAdmin = $DIC['ilPluginAdmin'];
10215 if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname)) {
10216 return true;
10217 } else {
10218 return false;
10219 }
10220 }
10221
10222 public function getPassed($active_id)
10223 {
10224 global $DIC;
10225 $ilDB = $DIC['ilDB'];
10226
10227 $result = $ilDB->queryF(
10228 "SELECT passed FROM tst_result_cache WHERE active_fi = %s",
10229 array('integer'),
10230 array($active_id)
10231 );
10232 if ($result->numRows()) {
10233 $row = $ilDB->fetchAssoc($result);
10234 return $row['passed'];
10235 } else {
10236 $counted_pass = ilObjTest::_getResultPass($active_id);
10237 $result_array = &$this->getTestResult($active_id, $counted_pass);
10238 return $result_array["test"]["passed"];
10239 }
10240 }
10241
10247 public function canShowCertificate($testSession, $user_id, $active_id)
10248 {
10249 if ($this->canShowTestResults($testSession)) {
10251
10252 $cert = $factory->create($this);
10253
10254 if ($cert->isComplete()) {
10255 $vis = $this->getCertificateVisibility();
10256 $showcert = false;
10257 switch ($vis) {
10258 case 0:
10259 $showcert = true;
10260 break;
10261 case 1:
10262 if ($this->getPassed($active_id)) {
10263 $showcert = true;
10264 }
10265 break;
10266 case 2:
10267 $showcert = false;
10268 break;
10269 }
10270 if ($showcert) {
10271 return true;
10272 } else {
10273 return false;
10274 }
10275 } else {
10276 return false;
10277 }
10278 } else {
10279 return false;
10280 }
10281 }
10282
10286 public function getParticipantsForTestAndQuestion($test_id, $question_id)
10287 {
10289 global $DIC;
10290 $ilDB = $DIC['ilDB'];
10291
10292 $query = "
10293 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
10294 FROM tst_test_result
10295 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s
10296 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi
10297 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi
10298 WHERE tst_test_result.question_fi = %s
10299 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC
10300 ";
10301
10302 $result = $ilDB->queryF(
10303 $query,
10304 array('integer', 'integer'),
10305 array($test_id, $question_id)
10306 );
10307 $foundusers = array();
10309 while ($row = $ilDB->fetchAssoc($result)) {
10310 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row["active_fi"])) {
10311 continue;
10312 }
10313
10314 if (!array_key_exists($row["active_fi"], $foundusers)) {
10315 $foundusers[$row["active_fi"]] = array();
10316 }
10317 array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10318 }
10319 return $foundusers;
10320 }
10321
10328 {
10329 $data = &$this->getCompleteEvaluationData();
10330 $foundParticipants = &$data->getParticipants();
10331 $results = array("overview" => array(), "questions" => array());
10332 if (count($foundParticipants)) {
10333 $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10334 $total_finished = $data->getTotalFinishedParticipants();
10335 $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10336 $average_time = $this->evalTotalStartedAverageTime($data->getParticipantIds());
10337 $diff_seconds = $average_time;
10338 $diff_hours = floor($diff_seconds / 3600);
10339 $diff_seconds -= $diff_hours * 3600;
10340 $diff_minutes = floor($diff_seconds / 60);
10341 $diff_seconds -= $diff_minutes * 60;
10342 $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10343 $total_passed = 0;
10344 $total_passed_reached = 0;
10345 $total_passed_max = 0;
10346 $total_passed_time = 0;
10347 foreach ($foundParticipants as $userdata) {
10348 if ($userdata->getPassed()) {
10349 $total_passed++;
10350 $total_passed_reached += $userdata->getReached();
10351 $total_passed_max += $userdata->getMaxpoints();
10352 $total_passed_time += $userdata->getTimeOfWork();
10353 }
10354 }
10355 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10356 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10357 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10358 $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10359 $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);
10360 $average_time = $average_passed_time;
10361 $diff_seconds = $average_time;
10362 $diff_hours = floor($diff_seconds / 3600);
10363 $diff_seconds -= $diff_hours * 3600;
10364 $diff_minutes = floor($diff_seconds / 60);
10365 $diff_seconds -= $diff_minutes * 60;
10366 $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10367 }
10368
10369 foreach ($data->getQuestionTitles() as $question_id => $question_title) {
10370 $answered = 0;
10371 $reached = 0;
10372 $max = 0;
10373 foreach ($foundParticipants as $userdata) {
10374 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
10375 if (is_object($userdata->getPass($i))) {
10376 $question = &$userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10377 if (is_array($question)) {
10378 $answered++;
10379 $reached += $question["reached"];
10380 $max += $question["points"];
10381 }
10382 }
10383 }
10384 }
10385 $percent = $max ? $reached / $max * 100.0 : 0;
10386 $results["questions"][$question_id] = array(
10387 $question_title,
10388 sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10389 sprintf("%.2f", $percent) . "%",
10390 $answered,
10391 sprintf("%.2f", $answered ? $reached / $answered : 0),
10392 sprintf("%.2f", $answered ? $max / $answered : 0),
10393 $percent / 100.0
10394 );
10395 }
10396 return $results;
10397 }
10398
10402 public function getXMLZip()
10403 {
10404 require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10405 $expFactory = new ilTestExportFactory($this);
10406 $test_exp = $expFactory->getExporter('xml');
10407 return $test_exp->buildExportFile();
10408 }
10409
10413 public function getMailNotification()
10414 {
10416 }
10417
10423 public function setMailNotification($a_notification)
10424 {
10425 $this->mailnotification = $a_notification;
10426 }
10427
10428 public function sendSimpleNotification($active_id)
10429 {
10430 include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10431
10432 $mail = new ilTestMailNotification();
10433 $owner_id = $this->getOwner();
10434 $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10435 $mail->sendSimpleNotification($owner_id, $this->getTitle(), $usr_data);
10436 }
10437
10444 {
10445 include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
10446 include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
10447 $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI($this->getRefId()), 'outEvaluation', $this->getAnonymity());
10448 return $table_gui->getSelectedColumns();
10449 }
10450
10451 public function sendAdvancedNotification($active_id)
10452 {
10453 include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10454
10455 $mail = new ilTestMailNotification();
10456 $owner_id = $this->getOwner();
10457 $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10458
10459 $participantList = new ilTestParticipantList($this);
10460 $participantList->initializeFromDbRows($this->getTestParticipants());
10461
10462 require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10463 $expFactory = new ilTestExportFactory($this);
10464 $exportObj = $expFactory->getExporter('results');
10465 $exportObj->setForcedAccessFilteredParticipantList($participantList);
10466 $file = $exportObj->exportToExcel($deliver = false, 'active_id', $active_id, $passedonly = false);
10467 include_once "./Services/Mail/classes/class.ilFileDataMail.php";
10468 $fd = new ilFileDataMail(ANONYMOUS_USER_ID);
10469 $fd->copyAttachmentFile($file, "result_" . $active_id . ".xls");
10470 $file_names[] = "result_" . $active_id . ".xls";
10471
10472 $mail->sendAdvancedNotification($owner_id, $this->getTitle(), $usr_data, $file_names);
10473
10474 if (count($file_names)) {
10475 $fd->unlinkFiles($file_names);
10476 unset($fd);
10477 @unlink($file);
10478 }
10479 }
10480
10481 public function createRandomSolutions($number)
10482 {
10483 global $DIC;
10484 $ilDB = $DIC['ilDB'];
10485
10486 // 1. get a user
10487 $query = "SELECT usr_id FROM usr_data";
10488 $result = $ilDB->query($query);
10489 while ($data = $ilDB->fetchAssoc($result)) {
10490 $activequery = sprintf(
10491 "SELECT user_fi FROM tst_active WHERE test_fi = %s AND user_fi = %s",
10492 $ilDB->quote($this->getTestId()),
10493 $ilDB->quote($data['usr_id'])
10494 );
10495 $activeresult = $ilDB->query($activequery);
10496 if ($activeresult->numRows() == 0) {
10497 $user_id = $data['usr_id'];
10498 if ($user_id != 13) {
10499 include_once "./Modules/Test/classes/class.ilTestSession.php";
10501 $testSession->setRefId($this->getRefId());
10502 $testSession->setTestId($this->getTestId());
10503 $testSession->setUserId($user_id);
10504 $testSession->saveToDb();
10505 $passes = ($this->getNrOfTries()) ? $this->getNrOfTries() : 10;
10506 $random = new \ilRandom();
10507 $nr_of_passes = $random->int(1, $passes);
10508 $active_id = $testSession->getActiveId();
10509 for ($pass = 0; $pass < $nr_of_passes; $pass++) {
10510 include_once "./Modules/Test/classes/class.ilTestSequence.php";
10511 $testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10512 $testSequence->loadFromDb();
10513 $testSequence->loadQuestions();
10514 if (!$testSequence->hasSequence()) {
10515 $testSequence->createNewSequence($this->getQuestionCount(), $shuffle);
10516 $testSequence->saveToDb();
10517 }
10518 for ($seq = 1; $seq <= count($this->questions); $seq++) {
10519 $question_id = $testSequence->getQuestionForSequence($seq);
10520 $objQuestion = ilObjTest::_instanciateQuestion($question_id);
10521 $assSettings = new ilSetting('assessment');
10522 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
10523 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
10524 $processLockerFactory->setQuestionId($objQuestion->getId());
10525 $processLockerFactory->setUserId($testSession->getUserId());
10526 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
10527 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
10528 $objQuestion->setProcessLocker($processLockerFactory->getLocker());
10529 $objQuestion->createRandomSolution($testSession->getActiveId(), $pass);
10530 }
10531 $testSession->increasePass();
10532 $testSession->setLastSequence(0);
10533 $testSession->setLastFinishedPass($pass);
10534 $testSession->setSubmitted(1);
10535 $testSession->setSubmittedTimestamp(date('Y-m-d H:i:s'));
10536 $testSession->saveToDb();
10537 }
10538 $number--;
10539 if ($number == 0) {
10540 return;
10541 }
10542 }
10543 }
10544 }
10545 }
10546
10547 public function getResultsForActiveId($active_id)
10548 {
10549 global $DIC;
10550 $ilDB = $DIC['ilDB'];
10551
10552 $query = "
10553 SELECT *
10554 FROM tst_result_cache
10555 WHERE active_fi = %s
10556 ";
10557
10558 $result = $ilDB->queryF(
10559 $query,
10560 array('integer'),
10561 array($active_id)
10562 );
10563
10564 if (!$result->numRows()) {
10565 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10566
10568
10569 $query = "
10570 SELECT *
10571 FROM tst_result_cache
10572 WHERE active_fi = %s
10573 ";
10574
10575 $result = $ilDB->queryF(
10576 $query,
10577 array('integer'),
10578 array($active_id)
10579 );
10580 }
10581
10582 $row = $ilDB->fetchAssoc($result);
10583
10584 return $row;
10585 }
10586
10587 public function getMailNotificationType()
10588 {
10589 if ($this->mailnottype == 1) {
10590 return $this->mailnottype;
10591 } else {
10592 return 0;
10593 }
10594 }
10595
10597 {
10598 if ($a_type == 1) {
10599 $this->mailnottype = 1;
10600 } else {
10601 $this->mailnottype = 0;
10602 }
10603 }
10604
10605 public function getExportSettings()
10606 {
10607 if ($this->exportsettings) {
10608 return $this->exportsettings;
10609 } else {
10610 return 0;
10611 }
10612 }
10613
10614 public function setExportSettings($a_settings)
10615 {
10616 if ($a_settings) {
10617 $this->exportsettings = $a_settings;
10618 } else {
10619 $this->exportsettings = 0;
10620 }
10621 }
10622
10624 {
10625 if (($this->exportsettings & 1) > 0) {
10626 return true;
10627 } else {
10628 return false;
10629 }
10630 }
10631
10632 public function setExportSettingsSingleChoiceShort($a_settings)
10633 {
10634 if ($a_settings) {
10635 $this->exportsettings = $this->exportsettings | 1;
10636 } else {
10638 $this->exportsettings = $this->exportsettings ^ 1;
10639 }
10640 }
10641 }
10642
10643 public function getEnabledViewMode()
10644 {
10645 return $this->enabled_view_mode;
10646 }
10647
10648 public function setEnabledViewMode($mode)
10649 {
10650 $this->enabled_view_mode = $mode;
10651 }
10652
10653 public function setTemplate($template_id)
10654 {
10655 $this->template_id = (int) $template_id;
10656 }
10657
10658 public function getTemplate()
10659 {
10660 return $this->template_id;
10661 }
10662
10663 public function moveQuestionAfterOLD($previous_question_id, $new_question_id)
10664 {
10665 $new_array = array();
10666 $position = 1;
10667
10668 $query = 'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
10669 $types = array('integer');
10670 $values = array($this->getTestId());
10671
10672 $new_question_id += 1;
10673
10674 global $DIC;
10675 $ilDB = $DIC['ilDB'];
10676 $inserted = false;
10677 $res = $ilDB->queryF($query, $types, $values);
10678 while ($row = $ilDB->fetchAssoc($res)) {
10679 $qid = $row['question_fi'];
10680
10681 if ($qid == $new_question_id) {
10682 continue;
10683 } elseif ($qid == $previous_question_id) {
10684 $new_array[$position++] = $qid;
10685 $new_array[$position++] = $new_question_id;
10686 $inserted = true;
10687 } else {
10688 $new_array[$position++] = $qid;
10689 }
10690 }
10691
10692 $update_query = 'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
10693 $update_types = array('integer', 'integer', 'integer');
10694
10695 foreach ($new_array as $position => $qid) {
10696 $ilDB->manipulateF(
10697 $update_query,
10698 $update_types,
10699 $vals = array(
10700 $position,
10701 $this->getTestId(),
10702 $qid
10703 )
10704 );
10705 }
10706 }
10707
10709 {
10710 return (
10713 );
10714 }
10715
10717 {
10718 $values = array();
10719
10720 if ($this->getSpecificAnswerFeedback()) {
10721 $values[] = 'instant_feedback_specific';
10722 }
10723 if ($this->getGenericAnswerFeedback()) {
10724 $values[] = 'instant_feedback_generic';
10725 }
10726 if ($this->getAnswerFeedbackPoints()) {
10727 $values[] = 'instant_feedback_points';
10728 }
10729 if ($this->getInstantFeedbackSolution()) {
10730 $values[] = 'instant_feedback_solution';
10731 }
10732
10733 return $values;
10734 }
10735
10737 {
10738 if (is_array($options)) {
10739 $this->setGenericAnswerFeedback(in_array('instant_feedback_generic', $options) ? 1 : 0);
10740 $this->setSpecificAnswerFeedback(in_array('instant_feedback_specific', $options) ? 1 : 0);
10741 $this->setAnswerFeedbackPoints(in_array('instant_feedback_points', $options) ? 1 : 0);
10742 $this->setInstantFeedbackSolution(in_array('instant_feedback_solution', $options) ? 1 : 0);
10743 } else {
10744 $this->setGenericAnswerFeedback(0);
10745 $this->setSpecificAnswerFeedback(0);
10746 $this->setAnswerFeedbackPoints(0);
10748 }
10749 }
10750
10752 {
10753 $setter = array(
10754 'pass_details' => 'setShowPassDetails',
10755 'solution_details' => 'setShowSolutionDetails',
10756 'solution_printview' => 'setShowSolutionPrintview',
10757 'solution_feedback' => 'setShowSolutionFeedback',
10758 'solution_answers_only' => 'setShowSolutionAnswersOnly',
10759 'solution_signature' => 'setShowSolutionSignature',
10760 'solution_suggested' => 'setShowSolutionSuggested',
10761 );
10762 foreach ($setter as $key => $setter) {
10763 if (in_array($key, $options)) {
10764 $this->$setter(1);
10765 } else {
10766 $this->$setter(0);
10767 }
10768 }
10769 }
10770
10771 public function getPoolUsage()
10772 {
10773 return (boolean) $this->poolUsage;
10774 }
10775
10776 public function setPoolUsage($usage)
10777 {
10778 $this->poolUsage = (boolean) $usage;
10779 }
10780
10785 {
10786 global $DIC;
10787 $tree = $DIC['tree'];
10788 $db = $DIC['ilDB'];
10789 $pluginAdmin = $DIC['ilPluginAdmin'];
10790
10791 require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
10792 $qscFactory = new ilTestQuestionSetConfigFactory($tree, $db, $pluginAdmin, $this);
10793 $questionSetConfig = $qscFactory->getQuestionSetConfig();
10794
10795 /* @var ilTestFixedQuestionSetConfig $questionSetConfig */
10796 $reindexedSequencePositionMap = $questionSetConfig->reindexQuestionOrdering();
10797
10798 $this->loadQuestions();
10799
10800 return $reindexedSequencePositionMap;
10801 }
10802
10803 public function setQuestionOrderAndObligations($orders, $obligations)
10804 {
10805 global $DIC;
10806 $ilDB = $DIC['ilDB'];
10807
10808 asort($orders);
10809
10810 $i = 0;
10811
10812 foreach ($orders as $id => $position) {
10813 $i++;
10814
10815 $obligatory = (
10816 isset($obligations[$id]) && $obligations[$id] ? 1 : 0
10817 );
10818
10819 $query = "
10820 UPDATE tst_test_question
10821 SET sequence = %s,
10822 obligatory = %s
10823 WHERE question_fi = %s
10824 ";
10825
10826 $ilDB->manipulateF(
10827 $query,
10828 array('integer', 'integer', 'integer'),
10829 array($i, $obligatory, $id)
10830 );
10831 }
10832
10833 $this->loadQuestions();
10834 }
10835
10836 public function moveQuestionAfter($question_to_move, $question_before)
10837 {
10838 global $DIC;
10839 $ilDB = $DIC['ilDB'];
10840 //var_dump(func_get_args());
10841 if ($question_before) {
10842 $query = 'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
10843 $types = array('integer');
10844 $values = array($question_before);
10845 $rset = $ilDB->queryF($query, $types, $values);
10846 }
10847
10848 if (!$question_before || ($rset && !($row = $ilDB->fetchAssoc($rset)))) {
10849 $row = array(
10850 'sequence' => 0,
10851 'test_fi' => $this->getTestId(),
10852 );
10853 }
10854
10855 $update = 'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
10856 $types = array('integer', 'integer');
10857 $values = array($row['sequence'], $row['test_fi']);
10858 $ilDB->manipulateF($update, $types, $values);
10859
10860 $update = 'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
10861 $types = array('integer', 'integer');
10862 $values = array($row['sequence'] + 1, $question_to_move);
10863 $ilDB->manipulateF($update, $types, $values);
10864
10866 }
10867
10869 {
10870 global $DIC;
10871 $ilDB = $DIC['ilDB'];
10872
10874
10875 $IN_questions = $ilDB->in('q1.question_id', array_keys($questions), false, 'integer');
10876
10877 $query = "
10878 SELECT count(q1.question_id) cnt
10879
10880 FROM qpl_questions q1
10881
10882 INNER JOIN qpl_questions q2
10883 ON q2.question_id = q1.original_id
10884
10885 WHERE $IN_questions
10886 AND q1.obj_fi = q2.obj_fi
10887 ";
10888
10889 $rset = $ilDB->query($query);
10890
10891 $row = $ilDB->fetchAssoc($rset);
10892
10893 return $row['cnt'] > 0;
10894 }
10895
10902 public static function _lookupFinishedUserTests($a_user_id)
10903 {
10904 global $DIC;
10905 $ilDB = $DIC['ilDB'];
10906
10907 $result = $ilDB->queryF(
10908 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
10909 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
10910 " WHERE user_fi=%s" .
10911 " GROUP BY test_fi",
10912 array('integer', 'integer'),
10913 array($a_user_id, 1)
10914 );
10915 $all = array();
10916 while ($row = $ilDB->fetchAssoc($result)) {
10917 $obj_id = self::_getObjectIDFromTestID($row["test_fi"]);
10918 $all[$obj_id] = (bool) $row["pass"];
10919 }
10920 return $all;
10921 }
10922 public function getQuestions()
10923 {
10924 return $this->questions;
10925 }
10926
10927 public function isOnline()
10928 {
10929 return $this->online;
10930 }
10931
10932 public function setOnline($a_online = true)
10933 {
10934 $this->online = (bool) $a_online;
10935 }
10936
10940 public function getOldOnlineStatus()
10941 {
10943 }
10944
10949 {
10950 $this->oldOnlineStatus = $oldOnlineStatus;
10951 }
10952
10953 public function setPrintBestSolutionWithResult($status)
10954 {
10955 $this->print_best_solution_with_result = (bool) $status;
10956 }
10957
10959 {
10961 }
10962
10969 {
10971 }
10972
10979 {
10980 $this->offeringQuestionHintsEnabled = (bool) $offeringQuestionHintsEnabled;
10981 }
10982
10983 public function setActivationVisibility($a_value)
10984 {
10985 $this->activation_visibility = (bool) $a_value;
10986 }
10987
10988 public function getActivationVisibility()
10989 {
10991 }
10992
10993 public function isActivationLimited()
10994 {
10995 return (bool) $this->activation_limited;
10996 }
10997
10998 public function setActivationLimited($a_value)
10999 {
11000 $this->activation_limited = (bool) $a_value;
11001 }
11002
11003 /* GET/SET for highscore feature */
11004
11010 public function setHighscoreEnabled($a_enabled)
11011 {
11012 $this->_highscore_enabled = (bool) $a_enabled;
11013 }
11014
11020 public function getHighscoreEnabled()
11021 {
11022 return (bool) $this->_highscore_enabled;
11023 }
11024
11032 public function setHighscoreAnon($a_anon)
11033 {
11034 $this->_highscore_anon = (bool) $a_anon;
11035 }
11036
11046 public function getHighscoreAnon()
11047 {
11048 return (bool) $this->_highscore_anon;
11049 }
11050
11059 public function isHighscoreAnon()
11060 {
11061 if ($this->getAnonymity() == 1) {
11062 return true;
11063 } else {
11064 return (bool) $this->getHighscoreAnon();
11065 }
11066 }
11067
11073 public function setHighscoreAchievedTS($a_achieved_ts)
11074 {
11075 $this->_highscore_achieved_ts = (bool) $a_achieved_ts;
11076 }
11077
11083 public function getHighscoreAchievedTS()
11084 {
11085 return (bool) $this->_highscore_achieved_ts;
11086 }
11087
11093 public function setHighscoreScore($a_score)
11094 {
11095 $this->_highscore_score = (bool) $a_score;
11096 }
11097
11103 public function getHighscoreScore()
11104 {
11105 return (bool) $this->_highscore_score;
11106 }
11107
11113 public function setHighscorePercentage($a_percentage)
11114 {
11115 $this->_highscore_percentage = (bool) $a_percentage;
11116 }
11117
11123 public function getHighscorePercentage()
11124 {
11125 return (bool) $this->_highscore_percentage;
11126 }
11127
11133 public function setHighscoreHints($a_hints)
11134 {
11135 $this->_highscore_hints = (bool) $a_hints;
11136 }
11137
11143 public function getHighscoreHints()
11144 {
11145 return (bool) $this->_highscore_hints;
11146 }
11147
11153 public function setHighscoreWTime($a_wtime)
11154 {
11155 $this->_highscore_wtime = (bool) $a_wtime;
11156 }
11157
11163 public function getHighscoreWTime()
11164 {
11165 return (bool) $this->_highscore_wtime;
11166 }
11167
11173 public function setHighscoreOwnTable($a_own_table)
11174 {
11175 $this->_highscore_own_table = (bool) $a_own_table;
11176 }
11177
11183 public function getHighscoreOwnTable()
11184 {
11185 return (bool) $this->_highscore_own_table;
11186 }
11187
11193 public function setHighscoreTopTable($a_top_table)
11194 {
11195 $this->_highscore_top_table = (bool) $a_top_table;
11196 }
11197
11203 public function getHighscoreTopTable()
11204 {
11205 return (bool) $this->_highscore_top_table;
11206 }
11207
11214 public function setHighscoreTopNum($a_top_num)
11215 {
11216 $this->_highscore_top_num = (int) $a_top_num;
11217 }
11218
11227 public function getHighscoreTopNum($a_retval = 10)
11228 {
11229 $retval = $a_retval;
11230 if ((int) $this->_highscore_top_num != 0) {
11231 $retval = $this->_highscore_top_num;
11232 }
11233
11234 return $retval;
11235 }
11236
11240 public function getHighscoreMode()
11241 {
11242 switch (true) {
11243 case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
11245 break;
11246
11247 case $this->getHighscoreTopTable():
11249 break;
11250
11251 case $this->getHighscoreOwnTable():
11252 default:
11254 break;
11255 }
11256 }
11257
11261 public function setHighscoreMode($mode)
11262 {
11263 switch ($mode) {
11265 $this->setHighscoreTopTable(1);
11266 $this->setHighscoreOwnTable(1);
11267 break;
11268
11270 $this->setHighscoreTopTable(1);
11271 $this->setHighscoreOwnTable(0);
11272 break;
11273
11275 default:
11276 $this->setHighscoreTopTable(0);
11277 $this->setHighscoreOwnTable(1);
11278 break;
11279 }
11280 }
11281 /* End GET/SET for highscore feature*/
11282
11283 public function setSpecificAnswerFeedback($specific_answer_feedback)
11284 {
11285 switch ($specific_answer_feedback) {
11286 case 1:
11287 $this->specific_answer_feedback = 1;
11288 break;
11289 default:
11290 $this->specific_answer_feedback = 0;
11291 break;
11292 }
11293 }
11294
11296 {
11297 switch ($this->specific_answer_feedback) {
11298 case 1:
11299 return 1;
11300 default:
11301 return 0;
11302 }
11303 }
11304
11311 {
11312 $this->obligationsEnabled = (bool) $obligationsEnabled;
11313 }
11314
11320 public function areObligationsEnabled()
11321 {
11322 return (bool) $this->obligationsEnabled;
11323 }
11324
11331 public static function isQuestionObligationPossible($questionId)
11332 {
11333 require_once('Modules/TestQuestionPool/classes/class.assQuestion.php');
11334
11335 $classConcreteQuestion = assQuestion::_getQuestionType($questionId);
11336
11337 assQuestion::_includeClass($classConcreteQuestion, 0);
11338
11339 // static binder is not at work yet (in PHP < 5.3)
11340 //$obligationPossible = $classConcreteQuestion::isObligationPossible();
11341 $obligationPossible = call_user_func(array($classConcreteQuestion, 'isObligationPossible'), $questionId);
11342
11343 return $obligationPossible;
11344 }
11345
11352 public static function isQuestionObligatory($question_id)
11353 {
11354 global $DIC;
11355 $ilDB = $DIC['ilDB'];
11356
11357 $rset = $ilDB->queryF('SELECT obligatory FROM tst_test_question WHERE question_fi = %s', array('integer'), array($question_id));
11358
11359 if ($row = $ilDB->fetchAssoc($rset)) {
11360 return (bool) $row['obligatory'];
11361 }
11362
11363 return false;
11364 }
11365
11378 public static function allObligationsAnswered($test_id, $active_id, $pass)
11379 {
11380 global $DIC;
11381 $ilDB = $DIC['ilDB'];
11382
11383 $rset = $ilDB->queryF(
11384 'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
11385 array('integer', 'integer'),
11386 array($active_id, $pass)
11387 );
11388
11389 if ($row = $ilDB->fetchAssoc($rset)) {
11390 return (bool) $row['obligations_answered'];
11391 }
11392
11394 }
11395
11404 public static function hasObligations($test_id)
11405 {
11406 global $DIC;
11407 $ilDB = $DIC['ilDB'];
11408
11409 $rset = $ilDB->queryF(
11410 'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
11411 array('integer'),
11412 array($test_id)
11413 );
11414
11415 $row = $ilDB->fetchAssoc($rset);
11416
11417 return (bool) $row['cnt'] > 0;
11418 }
11419
11420 public function setAutosave($autosave)
11421 {
11422 $this->autosave = $autosave;
11423 }
11424
11425 public function getAutosave()
11426 {
11427 return $this->autosave;
11428 }
11429
11431 {
11432 $this->autosave_ival = $autosave_ival;
11433 }
11434
11435 public function getAutosaveIval()
11436 {
11437 return $this->autosave_ival;
11438 }
11439
11445 public function isPassDeletionAllowed()
11446 {
11448 }
11449
11456 {
11457 $this->passDeletionAllowed = (bool) $passDeletionAllowed;
11458 }
11459
11460 #region Examview / PDF Examview
11465 {
11466 $this->show_examview_html = $show_examview_html;
11467 }
11468
11472 public function getShowExamviewHtml()
11473 {
11475 }
11476
11481 {
11482 $this->show_examview_pdf = $show_examview_pdf;
11483 }
11484
11488 public function getShowExamviewPdf()
11489 {
11491 }
11492
11497 {
11498 $this->enable_examview = $enable_examview;
11499 }
11500
11504 public function getEnableExamview()
11505 {
11507 }
11508
11509 #endregion
11510
11512 {
11513 $this->activation_starting_time = $starting_time;
11514 }
11515
11517 {
11518 $this->activation_ending_time = $ending_time;
11519 }
11520
11522 {
11523 return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : null;
11524 }
11525
11526 public function getActivationEndingTime()
11527 {
11528 return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : null;
11529 }
11530
11538 {
11539 global $DIC;
11540 $ilDB = $DIC['ilDB'];
11541
11542 $times = array();
11543 $result = $ilDB->queryF("SELECT tst_times.active_fi, tst_times.started FROM tst_times, tst_active WHERE tst_times.active_fi = tst_active.active_id AND tst_active.test_fi = %s ORDER BY tst_times.tstamp DESC",
11544 array('integer'),
11545 array($this->getTestId())
11546 );
11547 while ($row = $ilDB->fetchAssoc($result)) {
11548 $times[$row['active_fi']] = $row['started'];
11549 }
11550 return $times;
11551 }
11552
11554 {
11555 global $DIC;
11556 $ilDB = $DIC['ilDB'];
11557
11558 $times = array();
11559 $result = $ilDB->queryF(
11560 "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",
11561 array('integer'),
11562 array($this->getTestId())
11563 );
11564 while ($row = $ilDB->fetchAssoc($result)) {
11565 $times[$row['active_fi']] = $row['additionaltime'];
11566 }
11567 return $times;
11568 }
11569
11570 public function getExtraTime($active_id)
11571 {
11572 global $DIC;
11573 $ilDB = $DIC['ilDB'];
11574
11575 $result = $ilDB->queryF(
11576 "SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
11577 array('integer'),
11578 array($active_id)
11579 );
11580 if ($result->numRows() > 0) {
11581 $row = $ilDB->fetchAssoc($result);
11582 return $row['additionaltime'];
11583 }
11584 return 0;
11585 }
11586
11587 public function addExtraTime($active_id, $minutes)
11588 {
11589 global $DIC; /* @var ILIAS\DI\Container $DIC */
11590
11591 require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
11592 $participantData = new ilTestParticipantData($DIC->database(), $DIC->language());
11593
11594 $participantData->setParticipantAccessFilter(
11596 );
11597
11598 if ($active_id) {
11599 $participantData->setActiveIdsFilter(array($active_id));
11600 }
11601
11602 $participantData->load($this->getTestId());
11603
11604 foreach ($participantData->getActiveIds() as $active_id) {
11605 $result = $DIC->database()->queryF(
11606 "SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
11607 array('integer'),
11608 array($active_id)
11609 );
11610
11611 if ($result->numRows() > 0) {
11612 $DIC->database()->manipulateF(
11613 "DELETE FROM tst_addtime WHERE active_fi = %s",
11614 array('integer'),
11615 array($active_id)
11616 );
11617 }
11618
11619 $DIC->database()->manipulateF(
11620 "UPDATE tst_active SET tries = %s, submitted = %s, submittimestamp = %s WHERE active_id = %s",
11621 array('integer','integer','timestamp','integer'),
11622 array(0, 0, null, $active_id)
11623 );
11624
11625 $DIC->database()->manipulateF(
11626 "INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
11627 array('integer','integer','integer'),
11628 array($active_id, $minutes, time())
11629 );
11630
11631 require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
11633 $this->logAction(sprintf($this->lng->txtlng("assessment", "log_added_extratime", ilObjAssessmentFolder::_getLogLanguage()), $minutes, $active_id));
11634 }
11635 }
11636 }
11637
11644 {
11645 $this->enable_archiving = $enable_archiving;
11646 return $this;
11647 }
11648
11652 public function getEnableArchiving()
11653 {
11655 }
11656
11657 public function getMaxPassOfTest()
11658 {
11662 global $DIC;
11663 $ilDB = $DIC['ilDB'];
11664
11665 $query = '
11666 SELECT MAX(tst_pass_result.pass) + 1 max_res
11667 FROM tst_pass_result
11668 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
11669 WHERE test_fi = ' . $ilDB->quote($this->getTestId(), 'integer') . '
11670 ';
11671 $res = $ilDB->query($query);
11672 $data = $ilDB->fetchAssoc($res);
11673 return (int) $data['max_res'];
11674 }
11675
11681 public static function lookupExamId($active_id, $pass)
11682 {
11683 global $DIC;
11684 $ilDB = $DIC['ilDB'];
11685
11686 $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
11687 $exam_id_result = $ilDB->queryF($exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ));
11688 if ($ilDB->numRows($exam_id_result) == 1) {
11689 $exam_id_row = $ilDB->fetchAssoc($exam_id_result);
11690
11691 if ($exam_id_row['exam_id'] != null) {
11692 return $exam_id_row['exam_id'];
11693 }
11694 }
11695
11696 return null;
11697 }
11698
11705 public static function buildExamId($active_id, $pass, $test_obj_id = null)
11706 {
11707 global $DIC;
11708 $ilSetting = $DIC['ilSetting'];
11709
11710 $inst_id = $ilSetting->get('inst_id', null);
11711
11712 if ($test_obj_id === null) {
11713 $obj_id = self::_getObjectIDFromActiveID($active_id);
11714 } else {
11715 $obj_id = $test_obj_id;
11716 }
11717
11718 $examId = 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
11719
11720 return $examId;
11721 }
11722
11724 {
11725 $this->show_exam_id_in_test_pass_enabled = $show_exam_id_in_test_pass_enabled;
11726 }
11727
11729 {
11731 }
11732
11737 {
11738 $this->show_exam_id_in_test_results_enabled = $show_exam_id_in_test_results_enabled;
11739 }
11740
11745 {
11747 }
11748
11753 {
11754 $this->sign_submission = $sign_submission;
11755 }
11756
11760 public function getSignSubmission()
11761 {
11763 }
11764
11768 public function setCharSelectorAvailability($availability)
11769 {
11770 $this->char_selector_availability = (int) $availability;
11771 }
11772
11777 {
11779 }
11780
11784 public function setCharSelectorDefinition($definition = '')
11785 {
11786 $this->char_selector_definition = $definition;
11787 }
11788
11793 {
11795 }
11796
11797
11804 {
11805 $this->questionSetType = $questionSetType;
11806 }
11807
11813 public function getQuestionSetType()
11814 {
11816 }
11817
11825 public static function lookupQuestionSetType($objId)
11826 {
11827 global $DIC;
11828 $ilDB = $DIC['ilDB'];
11829
11830 $query = "SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
11831
11832 $res = $ilDB->queryF($query, array('integer'), array($objId));
11833
11834 $questionSetType = null;
11835
11836 while ($row = $ilDB->fetchAssoc($res)) {
11837 $questionSetType = $row['question_set_type'];
11838 }
11839
11840 return $questionSetType;
11841 }
11842
11848 public function isFixedTest()
11849 {
11851 }
11852
11858 public function isRandomTest()
11859 {
11861 }
11862
11868 public function isDynamicTest()
11869 {
11871 }
11872
11880 public static function _lookupRandomTest($a_obj_id)
11881 {
11883 }
11884
11886 {
11887 switch ($questionSetType) {
11889 return $lng->txt('tst_question_set_type_fixed');
11890
11892 return $lng->txt('tst_question_set_type_random');
11893
11895 return $lng->txt('tst_question_set_type_dynamic');
11896 }
11897
11898 throw new ilTestException('invalid question set type value given: ' . $questionSetType);
11899 }
11900
11901 public function participantDataExist()
11902 {
11903 if ($this->participantDataExist === null) {
11904 $this->participantDataExist = (bool) $this->evalTotalPersons();
11905 }
11906
11908 }
11909
11910 public function recalculateScores($preserve_manscoring = false)
11911 {
11912 require_once 'class.ilTestScoring.php';
11913 $scoring = new ilTestScoring($this);
11914 $scoring->setPreserveManualScores($preserve_manscoring);
11915 $scoring->recalculateSolutions();
11916 }
11917
11918 public static function getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
11919 {
11920 require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
11921
11922 $questionChangeListeners = array(
11924 );
11925
11926 return $questionChangeListeners;
11927 }
11928
11929 public static function getTestObjIdsWithActiveForUserId($userId)
11930 {
11931 global $DIC;
11932 $ilDB = $DIC['ilDB'];
11933
11934 $query = "
11935 SELECT obj_fi
11936 FROM tst_active
11937 INNER JOIN tst_tests
11938 ON test_id = test_fi
11939 WHERE user_fi = %s
11940 ";
11941
11942 $res = $ilDB->queryF($query, array('integer'), array($userId));
11943
11944 $objIds = array();
11945
11946 while ($row = $ilDB->fetchAssoc($res)) {
11947 $objIds[] = (int) $row['obj_fi'];
11948 }
11949
11950 return $objIds;
11951 }
11952
11954 {
11955 $this->skillServiceEnabled = $skillServiceEnabled;
11956 }
11957
11958 public function isSkillServiceEnabled()
11959 {
11961 }
11962
11964 {
11965 $this->resultFilterTaxIds = $resultFilterTaxIds;
11966 }
11967
11968 public function getResultFilterTaxIds()
11969 {
11971 }
11972
11974 {
11975 if (!$this->isSkillServiceEnabled()) {
11976 return false;
11977 }
11978
11979 if (!self::isSkillManagementGloballyActivated()) {
11980 return false;
11981 }
11982
11983 return true;
11984 }
11985
11987
11988 public static function isSkillManagementGloballyActivated()
11989 {
11990 if (self::$isSkillManagementGloballyActivated === null) {
11991 include_once 'Services/Skill/classes/class.ilSkillManagementSettings.php';
11992 $skmgSet = new ilSkillManagementSettings();
11993
11994 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
11995 }
11996
11998 }
11999
12001 {
12002 $this->showGradingStatusEnabled = $showGradingStatusEnabled;
12003 }
12004
12006 {
12008 }
12009
12011 {
12012 $this->showGradingMarkEnabled = $showGradingMarkEnabled;
12013 }
12014
12015
12017 {
12019 }
12020
12022 {
12023 $this->followupQuestionAnswerFixationEnabled = $followupQuestionAnswerFixationEnabled;
12024 }
12025
12027 {
12029 }
12030
12032 {
12033 $this->instantFeedbackAnswerFixationEnabled = $instantFeedbackAnswerFixationEnabled;
12034 }
12035
12037 {
12039 }
12040
12045 {
12047 }
12048
12053 {
12054 $this->forceInstantFeedbackEnabled = $forceInstantFeedbackEnabled;
12055 }
12056
12057 public static function ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run = false)
12058 {
12059 global $DIC;
12060 $ilDB = $DIC['ilDB'];
12061 $lng = $DIC['lng'];
12062 $ilPluginAdmin = $DIC['ilPluginAdmin'];
12063
12064 /* @var ilObjTest $testOBJ */
12065
12066 $testOBJ = ilObjectFactory::getInstanceByRefId($testObjId, false);
12067
12068 $activeId = $testOBJ->getActiveIdOfUser($userId);
12069
12070 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12071 $testSessionFactory = new ilTestSessionFactory($testOBJ);
12072
12073 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12074 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12075
12076 $testSession = $testSessionFactory->getSession($activeId);
12077 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12078 $testSequence->loadFromDb();
12079
12080 // begin-patch lok changed smeyer
12081 if ($a_force_new_run) {
12082 if ($testSequence->hasSequence()) {
12083 $testSession->increasePass();
12084 }
12085 $testSession->setLastSequence(0);
12086 $testSession->saveToDb();
12087 }
12088 // end-patch lok
12089 }
12090
12091 public static function isParticipantsLastPassActive($testRefId, $userId)
12092 {
12093 global $DIC;
12094 $ilDB = $DIC['ilDB'];
12095 $lng = $DIC['lng'];
12096 $ilPluginAdmin = $DIC['ilPluginAdmin'];
12097
12098 /* @var ilObjTest $testOBJ */
12099
12100 $testOBJ = ilObjectFactory::getInstanceByRefId($testRefId, false);
12101
12102
12103 $activeId = $testOBJ->getActiveIdOfUser($userId);
12104
12105 require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12106 $testSessionFactory = new ilTestSessionFactory($testOBJ);
12107 // Added temporarily bugfix smeyer
12108 $testSessionFactory->reset();
12109
12110 require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12111 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12112
12113 $testSession = $testSessionFactory->getSession($activeId);
12114 $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12115 $testSequence->loadFromDb();
12116
12117 return $testSequence->hasSequence();
12118 }
12119
12123 public function isTestFinalBroken()
12124 {
12126 }
12127
12132 {
12133 $this->testFinalBroken = $testFinalBroken;
12134 }
12135
12136 public function adjustTestSequence()
12137 {
12141 global $DIC;
12142 $ilDB = $DIC['ilDB'];
12143
12144 $query = "
12145 SELECT COUNT(test_question_id) cnt
12146 FROM tst_test_question
12147 WHERE test_fi = %s
12148 ORDER BY sequence
12149 ";
12150
12151 $questRes = $ilDB->queryF($query, array('integer'), array($this->getTestId()));
12152
12153 $row = $ilDB->fetchAssoc($questRes);
12154 $questCount = $row['cnt'];
12155
12156 if ($this->getShuffleQuestions()) {
12157 $query = "
12158 SELECT tseq.*
12159 FROM tst_active tac
12160 INNER JOIN tst_sequence tseq
12161 ON tseq.active_fi = tac.active_id
12162 WHERE tac.test_fi = %s
12163 ";
12164
12165 $partRes = $ilDB->queryF(
12166 $query,
12167 array('integer'),
12168 array($this->getTestId())
12169 );
12170
12171 while ($row = $ilDB->fetchAssoc($partRes)) {
12172 $sequence = @unserialize($row['sequence']);
12173
12174 if (!$sequence) {
12175 $sequence = array();
12176 }
12177
12178 $sequence = array_filter($sequence, function ($value) use ($questCount) {
12179 return $value <= $questCount;
12180 });
12181
12182 $num_seq = count($sequence);
12183 if ($questCount > $num_seq) {
12184 $diff = $questCount - $num_seq;
12185 for ($i = 1; $i <= $diff; $i++) {
12186 $sequence[$num_seq + $i - 1] = $num_seq + $i;
12187 }
12188 }
12189
12190 $new_sequence = serialize($sequence);
12191
12192 $ilDB->update('tst_sequence', array(
12193 'sequence' => array('clob', $new_sequence)
12194 ), array(
12195 'active_fi' => array('integer', $row['active_fi']),
12196 'pass' => array('integer', $row['pass'])
12197 ));
12198 }
12199 } else {
12200 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : array());
12201
12202 $query = "
12203 SELECT tseq.*
12204 FROM tst_active tac
12205 INNER JOIN tst_sequence tseq
12206 ON tseq.active_fi = tac.active_id
12207 WHERE tac.test_fi = %s
12208 ";
12209
12210 $part_rest = $ilDB->queryF(
12211 $query,
12212 array('integer'),
12213 array($this->getTestId())
12214 );
12215
12216 while ($row = $ilDB->fetchAssoc($part_rest)) {
12217 $ilDB->update('tst_sequence', array(
12218 'sequence' => array('clob', $new_sequence)
12219 ), array(
12220 'active_fi' => array('integer', $row['active_fi']),
12221 'pass' => array('integer', $row['pass'])
12222 ));
12223 }
12224 }
12225 }
12226}
$result
$factory
Definition: metadata.php:43
$total
Definition: Utf8Test.php:87
$test
Definition: Utf8Test.php:84
$filename
Definition: buildRTE.php:89
$default
Definition: build.php:20
$_SESSION["AccountId"]
A class defining mark schemas for assessment test objects.
An exception for terminatinating execution or to throw for unit testing.
const IL_COMP_MODULE
const IL_CAL_UNIX
const IL_CAL_DATETIME
const NEWS_USERS
const NEWS_NOTICE
static getFeedbackClassNameByQuestionType($questionType)
static _getOriginalId($question_id)
Returns the original id of a question.
static sumTimesInISO8601FormatH_i_s_Extended($time1, $time2)
static _getSolutionMaxPass($question_id, $active_id)
Returns the maximum pass a users question solution.
static _updateTestResultCache($active_id, ilAssQuestionProcessLocker $processLocker=null)
@TODO Move this to a proper place.
static _getSuggestedSolutionOutput($question_id)
Returns the output of the suggested solution.
static getGuiClassNameByQuestionType($questionType)
static _isWorkedThrough($active_id, $question_id, $pass=null)
Returns true if the question was worked through in the given pass Worked through means that the user ...
static _includeClass($question_type, $gui=0)
Include the php class file for a given question type.
static _getQuestionTitle($question_id)
Returns the question title of a question with a given id.
static _getQuestionType($question_id)
Returns the question type of a question with a given id.
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
static deleteRequestsByActiveIds($activeIds)
Deletes all hint requests relating to a testactive included in given active ids.
Question page object.
static completeMissingPluginName($questionTypeData)
static _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.
Class ilFileDataMail.
static recursive_dirscan($dir, &$arr)
Recursively scans a given directory and writes path and filename into referenced array.
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 getPoolQuestionChangeListener(ilDBInterface $db, $poolObjId)
Class ilObjTestGUI.
static _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
{Returns the ECTS grade for a number of reached points.string The ECTS grade short description}
setHighscorePercentage($a_percentage)
Sets if the percentages of the scores pass should be shown.
getResetProcessingTime()
Returns wheather the processing time should be reset or not.
_buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
Builds a user name for the output depending on test type and existence of the user.
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
setPrintBestSolutionWithResult($status)
setAnswerFeedback($answer_feedback=0)
Sets the generic feedback for the test @deprecate Use setGenericAnswerFeedback instead.
__construct($a_id=0, $a_call_by_reference=true)
Constructor.
getPassed($active_id)
setIntroduction($introduction="")
Sets the introduction text of the ilObjTest object.
exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
export page objects to xml (see ilias_co.dtd)
setECTSFX($a_ects_fx)
{}
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
getProcessingTimeAsMinutes()
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
getEstimatedWorkingTime()
Returns the estimated working time for the test calculated from the working time of the contained que...
setShowInfo($a_info=1)
Set whether the complete information page is shown or the required data only.
const QUESTION_SET_TYPE_DYNAMIC
type setting value for dynamic question set (continues testing mode)
getTestId()
Gets the database id of the additional test data.
getECTSOutput()
{int|bool}
& createQuestionGUI($question_type, $question_id=-1)
Creates a question GUI instance of a given question type.
$followupQuestionAnswerFixationEnabled
endingTimeReached()
Returns true if the ending time of a test is reached An ending time is not available for self assessm...
setClientIP($user_id, $client_ip)
setAllowedUsersTimeGap($a_allowed_users_time_gap)
getQuestionSetType()
getter for question set type
setTestId($a_id)
Sets the test ID.
getShowKioskModeParticipant()
Returns the status of the kiosk mode participant.
setKiosk($kiosk=0)
Sets the kiosk mode for the test.
getQuestionTitle($title, $nr=null)
Returns the title of a test question and checks if the title output is allowed.
canShowEctsGrades()
{boolean}
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
getAnsweredQuestionCount($active_id, $pass=null)
Retrieves the number of answered questions for a given user in a given test.
getShowKioskModeTitle()
Returns the status of the kiosk mode title.
hasRandomQuestionsForPass($active_id, $pass)
Checkes wheather a random test has already created questions for a given pass or not.
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
getCountSystem()
Gets the count system for the calculation of points.
isShowExamIdInTestPassEnabled()
setPostponingEnabled($postponingEnabled)
setInstantFeedbackSolution($instant_feedback=0)
Sets the instant feedback for the solution.
canShowSolutionPrintview($user_id=null)
Calculates if a user may see the solution printview of his/her test results.
getEnableProcessingTime()
Returns the state of the processing time (enabled/disabled)
setShowKioskModeParticipant($a_participant=false)
Set to true, if the participant's name should be shown in kiosk mode.
getListOfQuestionsStart()
Returns if the list of questions should be presented as the first page of the test.
& getExistingQuestions($pass=null)
Get the id's of the questions which are already part of the test.
static _getTestIDFromObjectID($object_id)
Returns the ILIAS test id for a given object id.
loadFromDb()
Loads a ilObjTest object from a database.
pcArrayShuffle($array)
Shuffles the values of a given array.
_getTitleOutput($active_id)
Returns the value of the title_output status.
isAnyInstantFeedbackOptionEnabled()
isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
Returns true, if a test is complete for use and can be set online.
canShowTestResults(ilTestSession $testSession)
getInstantFeedbackSolution()
Returns 1 if the correct solution will be shown after answering a question.
setFinalStatement($a_statement="")
Sets the final statement text of the ilObjTest object.
setFixedParticipants($a_value=1)
Sets the fixed participants status.
getStartingTimeOfUser($active_id, $pass=null)
Returns the unix timestamp of the time a user started a test.
_getLastAccess($active_id)
getStartTestLabel($active_id)
Returns the "Start the Test" label for the Info page.
static _getTestDefaults($test_defaults_id)
setOnline($a_online=true)
& getParticipants()
Returns all persons who started the test.
setProcessingTime($processing_time="00:00:00")
Sets the processing time for the test.
setHighscoreAnon($a_anon)
Sets if the highscores should be anonymized.
getDetailedTestResults($participants)
returns all test results for all participants
setAllowedUsers($a_allowed_users)
isNrOfTriesReached($tries)
returns if number of tries are reached
reindexFixedQuestionOrdering()
static getTestObjIdsWithActiveForUserId($userId)
setKioskMode($a_kiosk=false)
Sets the kiosk mode for the test.
setTemplate($template_id)
setShowExamviewPdf($show_examview_pdf)
setShowSolutionSignature($a_signature=false)
Set to TRUE, if the signature field should be shown in the solution.
setShowExamIdInTestPassEnabled($show_exam_id_in_test_pass_enabled)
inviteUser($user_id, $client_ip="")
Invites a user to a test.
setScoreCutting($a_score_cutting=SCORE_CUT_QUESTION)
Sets the type of score cutting.
static _getCountSystem($active_id)
Gets the count system for the calculation of points.
evalTotalStartedAverageTime($activeIdsFilter=null)
Returns the average processing time for all started tests.
setFollowupQuestionAnswerFixationEnabled($followupQuestionAnswerFixationEnabled)
getQuestionCount()
Returns the number of questions in the test.
getQuestiontext($question_id)
Returns the question text for a given question.
setResultsPresentationOptionsByArray($options)
QTIMaterialToString($a_material)
Reads an QTI material tag an creates a text string.
& getTestDefaults($test_defaults_id)
Returns the test defaults for a given id.
const QUESTION_SET_TYPE_RANDOM
type setting value for random question set
saveAuthorToMetadata($a_author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
setOldOnlineStatus($oldOnlineStatus)
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
setPassDeletionAllowed($passDeletionAllowed)
setter for the test setting passDeletionAllowed
setHighscoreScore($a_score)
Sets if the actual score should be displayed.
const HIGHSCORE_SHOW_ALL_TABLES
sendSimpleNotification($active_id)
getXMLZip()
Get zipped xml file for test.
getShowSolutionListComparison()
static lookupExamId($active_id, $pass)
createExportDirectory()
creates data directory for export files (data_dir/tst_data/tst_<id>/export, depending on data directo...
setShowGradingStatusEnabled($showGradingStatusEnabled)
static _getActiveIdOfUser($user_id="", $test_id="")
Gets the active id of the tst_active table for the active user.
getExtraTime($active_id)
isPreviousSolutionReuseEnabled($activeId)
getFixedParticipants()
Returns the fixed participants status.
isBestSolutionPrintedWithResult()
_lookupRandomTestFromActiveId($active_id)
Returns the random status of a test with a given object id.
setPassword($a_password=null)
Sets the password for test access.
setShowSolutionDetails($a_details=1)
Sets if the the solution details should be presented to the user or not.
& createTestSequence($active_id, $pass, $shuffle)
$show_exam_id_in_test_results_enabled
getFinalStatement()
Gets the final statement.
getProcessingTimeAsArray()
Returns the processing time for the test.
questionMoveDown($question_id)
Moves a question down in order.
setShowFinalStatement($show=0)
Sets whether the final statement should be shown or not.
logAction($logtext="", $question_id="")
Logs an action into the Test&Assessment log.
createMetaData()
Create meta data entry.
getEvaluationAdditionalFields()
Gets additional user fields that should be shown in the user evaluation.
setEndingTimeEnabled($ending_time_enabled)
loadQuestions($active_id="", $pass=null)
Load the test question id's from the database.
& getCompleteEvaluationData($withStatistics=true, $filterby="", $filtertext="")
setShowPassDetails($a_details=1)
Sets if the pass details should be shown when a test is not finished.
insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly=false)
Insert a question in the list of questions.
buildName($user_id, $firstname, $lastname, $title)
Builds a user name for the output depending on test type and existence of the user.
setRedirectionUrl($redirection_url=null)
hasQuestionsWithoutQuestionpool()
$print_best_solution_with_result
setCountSystem($a_count_system=COUNT_PARTIAL_SOLUTIONS)
Sets the count system for the calculation of points.
buildIso8601PeriodFromUnixtimeForExportCompatibility($unix_timestamp)
$instantFeedbackAnswerFixationEnabled
static _getUsePreviousAnswers($active_id, $user_active_user_setting=false)
Returns if the previous results should be hidden for a learner.
removeQuestionFromSequences($questionId, $activeIds, ilTestReindexedSequencePositionMap $reindexedSequencePositionMap)
getImagePath()
Returns the image path for web accessable images of a test The image path is under the CLIENT_WEB_DIR...
getShowSolutionSignature()
Returns if the signature field should be shown in the test results.
getHighscoreAnon()
Gets if the highscores should be anonymized per setting.
exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export media objects to xml (see ilias_co.dtd)
getPassScoring()
Gets the pass scoring type.
setInstantFeedbackAnswerFixationEnabled($instantFeedbackAnswerFixationEnabled)
setHighscoreHints($a_hints)
Sets if the number of requested hints should be shown.
getPassword()
Returns the password for test access.
setPasswordEnabled($passwordEnabled)
setPassScoring($a_pass_scoring=SCORE_LAST_PASS)
Sets the pass scoring.
isHighscoreAnon()
Gets if the highscores should be displayed anonymized.
setOfferingQuestionHintsEnabled($offeringQuestionHintsEnabled)
sets offering question hints enabled/disabled
getFixedQuestionSetTotalWorkingTime()
getShowSolutionAnswersOnly()
Returns if the full solution (including ILIAS content) should be presented to the solution or not.
setShowSolutionPrintview($a_printview=1)
Sets if the the solution printview should be presented to the user or not.
& evalTotalPersonsArray($name_sort_order="asc")
Returns all persons who started the test.
& evalStatistical($active_id)
Returns the statistical evaluation of the test for a specified user.
isExecutable($testSession, $user_id, $allowPassIncrease=false)
Checks if the test is executable by the given user.
const SCORE_REPORTING_IMMIDIATLY
& getTestParticipants()
Returns a list of all participants in a test.
getStartingTime()
Returns the starting time of the test.
canEditEctsGrades()
{boolean}
startingTimeReached()
Returns true if the starting time of a test is reached A starting time is not available for self asse...
setAutosave($autosave)
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 _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
const QUESTION_SET_TYPE_FIXED
type setting value for fixed question set
setHighscoreEnabled($a_enabled)
Sets if the highscore feature should be enabled.
duplicateQuestionForTest($question_id)
Takes a question and creates a copy of the question for use in the test.
setRedirectionMode($redirection_mode=0)
hasSingleChoiceQuestions()
Returns TRUE if the test contains single choice results.
setMailNotification($a_notification)
Set mail notification settings.
isActiveTestSubmitted($user_id=null)
returns if the active for user_id has been submitted
setQuestionSetType($questionSetType)
setter for question set type
setReportingDate($reporting_date)
Sets the reporting date of the ilObjTest object.
static lookupQuestionSetType($objId)
lookup-er for question set type
moveQuestionAfterOLD($previous_question_id, $new_question_id)
setCharSelectorDefinition($definition='')
getKiosk()
Returns the kiosk mode.
getResultsForActiveId($active_id)
getShowSolutionDetails()
Returns if the solution details should be presented to the user or not.
setAuthor($author="")
Sets the authors name of the ilObjTest object.
setQuestionOrderAndObligations($orders, $obligations)
isTestQuestion($questionId)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
getAuthor()
Gets the authors name of the ilObjTest object.
getAnswerFeedbackPoints()
Returns 1 if answer specific feedback as reached points is activated.
randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id=0, $qpls="", $pass=null)
Returns a random selection of questions.
setIntroductionEnabled($introductionEnabled)
getProcessingTimeInSeconds($active_id="")
Returns the processing time for the test in seconds.
getFixedQuestionSetTotalPoints()
static lookupLastTestPassAccess($activeId, $passIndex)
inviteGroup($group_id)
Invites all users of a group to a test.
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test.
read()
read object data from db into object
getHighscorePercentage()
Gets if the percentage column should be shown.
const SCORE_REPORTING_FINISHED
addDefaults($a_name)
Adds the defaults of this test to the test defaults.
getCustomStyles()
Return the available custom styles.
setCertificateVisibility($a_value)
Sets the visibility settings of the certificate.
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
setListOfQuestionsEnd($a_value=true)
Sets if the the list of questions as the end page of the test.
getTestParticipantsForManualScoring($filter=null)
static _getMCScoring($active_id)
Gets the scoring type for multiple choice questions.
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)
& 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)
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.
setSpecificAnswerFeedback($specific_answer_feedback)
& processCSVRow($row, $quoteAll=false, $separator=";")
Processes an array as a CSV row and converts the array values to correct CSV values.
setMailNotificationType($a_type)
setTitleOutput($title_output=0)
Sets the status of the title output.
isOfferingQuestionHintsEnabled()
returns the fact wether offering hints is enabled or not
& getGroupData($ids)
getCompleteWorkingTime($user_id)
Returns the complete working time in seconds a user worked on the test.
static buildExamId($active_id, $pass, $test_obj_id=null)
& getQuestionsOfTest($active_id)
Retrieves all the assigned questions for all test passes of a test participant.
setPassWaiting($pass_waiting)
removeQuestions($removeQuestionIds)
getForceJS()
Gets whether JavaScript should be forced for tests.
removeTestResults(ilTestParticipantData $participantData)
applyDefaults($test_defaults)
Applies given test defaults to this test.
disinviteUser($user_id)
Disinvites a user from a test.
setAnswerFeedbackPoints($answer_feedback_points=0)
Sets the answer specific feedback of reached points for the test.
getExportDirectory()
Get the location of the export directory for the test.
getInstantFeedbackOptionsAsArray()
setStartingTimeEnabled($starting_time_enabled)
setECTSGrades(array $a_ects_grades)
{}
static lookupQuestionSetTypeByActiveId($active_id)
returns the question set type of test relating to passed active id
& getQuestionsOfPass($active_id, $pass)
Retrieves all the assigned questions for a test participant in a given test pass.
deliverPDFfromHTML($content, $title=null)
Delivers a PDF file from XHTML.
getImagePathWeb()
Returns the web image path for web accessable images of a test The image path is under the web access...
static _getWorkingTimeOfParticipantForPass($active_id, $pass)
Returns the complete working time in seconds for a test participant.
static isQuestionObligationPossible($questionId)
checks wether the obligation for question with given id is possible or not
setActivationLimited($a_value)
_isComplete($obj_id)
Returns true, if a test is complete for use.
isShowExamIdInTestResultsEnabled()
setPoolUsage($usage)
areObligationsEnabled()
returns the fact wether obligations are enabled or not
const DEFAULT_PROCESSING_TIME_MINUTES
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
create()
create test object
setShowSolutionSuggested($a_solution=false)
Set to TRUE, if the suggested solution should be shown in the solution.
getEndingTime()
Returns the ending time of the test.
static _getAvailableTests($use_object_id=false)
Returns the available tests for the active user.
setShowKioskModeTitle($a_title=false)
Set to true, if the full test title should be shown in kiosk mode.
setHighscoreOwnTable($a_own_table)
Sets if the table with the own ranking should be shown.
saveCertificateVisibility($a_value)
Saves the visibility settings of the certificate.
setShowGradingMarkEnabled($showGradingMarkEnabled)
getCompleteWorkingTimeOfParticipant($active_id)
Returns the complete working time in seconds for a test participant.
setStartingTime($starting_time=null)
Sets the starting time in database timestamp format for the test.
evalTotalPersons()
Returns the number of persons who started the test.
setEnableExamview($enable_examview)
static $isSkillManagementGloballyActivated
getScoreReporting()
Gets the score reporting of the ilObjTest object.
getMailNotification()
Get mail notification settings.
setSignSubmission($sign_submission)
setEnableArchiving($enable_archiving)
& _evalResultsOverview($test_id)
Creates an associated array with the results of all participants of a test.
setResultFilterTaxIds($resultFilterTaxIds)
isInstantFeedbackAnswerFixationEnabled()
& getQuestionTitles()
Returns the titles of the test questions in question sequence.
getAllRTEContent()
Returns the content of all RTE enabled text areas in the test.
_getVisitTimeOfParticipant($test_id, $active_id)
Returns the first and last visit of a participant.
getExportSettingsSingleChoiceShort()
setShowCancel($a_value=1)
Sets the cancel test button status.
getECTSGrades()
{array}
getMarkSchemaForeignId()
{int}
addQTIMaterial(&$a_xml_writer, $a_material)
Creates a QTI material tag from a plain text or xhtml text.
& getAllQuestions($pass=null)
Returns all questions of a test in test order.
static _getUserIdFromActiveId($active_id)
isPluginActive($a_pname)
Checks wheather or not a question plugin with a given name is active.
& evalTotalParticipantsArray($name_sort_order="asc")
Returns all participants who started the test.
setShowSolutionAnswersOnly($a_full=true)
Set to true, if the full solution (including the ILIAS content pages) should be shown in the solution...
setAutosaveIval($autosave_ival)
getAnonymity()
Returns the anonymity status of the test.
deliverPDFfromFO($fo, $title=null)
Delivers a PDF file from a XSL-FO string.
static hasObligations($test_id)
returns the fact wether the test with given test id contains questions markes as obligatory or not
setTestFinalBroken($testFinalBroken)
setResultsPresentation($a_results_presentation=3)
Sets the combined results presentation value.
removeQuestion($question_id)
Removes a question from the test object.
setLimitUsersEnabled($limitUsersEnabled)
toXML()
Returns a QTI xml representation of the test.
& getRoleData($ids)
static lookupPassResultsUpdateTimestamp($active_id, $pass)
hasAnyTestResult(ilTestSession $testSession)
isSingleChoiceTest()
Returns TRUE if the test contains single choice results only.
& evalResultsOverviewOfParticipant($active_id)
Creates an associated array with the results for a given participant of a test.
getShowCancel()
Returns wheather the cancel test button is shown or not.
getCertificateVisibility()
Returns the visibility settings of the certificate.
setHighscoreWTime($a_wtime)
Sets if the workingtime of the scores should be shown.
setNrOfTries($nr_of_tries=0)
Sets the nr of tries for the test.
getTestStyleLocation($mode="output")
get full style sheet file name (path inclusive) of current user
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
getHighscoreScore()
Gets if the score column should be shown.
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 manual feedback for a question in a test.
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.
createRandomSolutions($number)
getECTSFX()
{float|null}
setExportSettings($a_settings)
setEndingTime($ending_time=null)
Sets the ending time in database timestamp format for the test.
getStartingTimeOfParticipants()
Note, this function should only be used if absolutely necessary, since it perform joins on tables tha...
addExtraTime($active_id, $minutes)
getAccessFilteredParticipantList()
static getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
cleanupMediaobjectUsage()
Cleans up the media objects for all text fields in a test which are using an RTE field.
setScoreReporting($score_reporting=0)
Sets the score reporting of the ilObjTest object.
isTestFinishedToViewResults($active_id, $currentpass)
Returns true if an active user completed a test pass and did not start a new pass.
static ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run=false)
exportFileItems($a_target_dir, &$expLog)
export files of file itmes
hasNrOfTriesRestriction()
returns if the numbers of tries have to be checked
static _lookupTestObjIdForQuestionId($a_q_id)
Get test Object ID for question ID.
setCustomStyle($a_customStyle=null)
Set the custom style.
const SCORE_REPORTING_DISABLED
setTmpCopyWizardCopyId($tmpCopyWizardCopyId)
getVisitTimeOfParticipant($active_id)
Returns the first and last visit of a participant.
setAccessFilteredParticipantList($accessFilteredParticipantList)
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename
getShowFinalStatement()
Returns whether the final statement should be shown or not.
questionMoveUp($question_id)
Moves a question up in order.
getProcessingTime()
Returns the processing time for the test.
setSequenceSettings($sequence_settings=0)
SEQUENCE SETTING = POSTPONING ENABLED !!
isForceInstantFeedbackEnabled()
& getCompleteWorkingTimeOfParticipants()
Returns the complete working time in seconds for all test participants.
getIntroduction()
Gets the introduction text of the ilObjTest object.
getAnswerFeedback()
Returns 1 if generic answer feedback is activated.
const HIGHSCORE_SHOW_TOP_TABLE
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd)
setShowMarker($a_value=1)
Sets the marker button status.
static _lookupName($a_user_id)
lookup user name
static _lookupClientIP($a_user_id)
Lookup client ip.
Class ilObjectActivation.
setTimingType($a_type)
Set timing type.
static getItem($a_ref_id)
Get item data.
static getInstanceByRefId($a_ref_id, $stop_on_error=true)
get an instance of an Ilias object by reference id
static getInstance($a_obj_id)
Class ilObject Basic functions for all objects.
getType()
get object type @access public
getOwner()
get object owner
static _lookupObjId($a_id)
setOfflineStatus($a_status)
Set offline status.
static _lookupTitle($a_id)
lookup object title
setTitle($a_title)
set object title
deleteMetaData()
delete meta data entry
static _lookupDescription($a_id)
lookup object description
updateMetaData()
update meta data entry
setDescription($a_desc)
set object description
getOfflineStatus()
Get offline status.
getRefId()
get reference id @access public
getDescription()
get object description
cloneMetaData($target_obj)
Copy meta data.
getId()
get object id @access public
static _prepareCloneSelection($a_ref_ids, $new_type, $show_path=true)
Prepare copy wizard object selection.
static _lookupOwner($a_id)
lookup object owner
getTitle()
get object title @access public
static collectFileItems($a_page, $a_domdoc)
Get all file items that are used within the page.
static getPluginObject(string $a_ctype, string $a_cname, string $a_slot_id, string $a_pname)
getPresentationMaterial()
{ilQTIPresentationMaterial|null}
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
static _cleanupMediaObjectUsage($a_text, $a_usage_type, $a_usage_id)
Synchronises appearances of media objects in $a_text with media object usage table.
static factory($a_package, $a_timeout=0)
Creates an ilRpcClient instance to our ilServer.
ILIAS Setting Class.
special template class to simplify handling of ITX/PEAR
Base Exception for all Exceptions relating to Modules/Test.
Class ilTestMailNotification.
Class ilTestScoring.
Test sequence handler.
Test session handler.
static getDataDir()
get data directory (outside webspace)
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static insertInstIntoID($a_value)
inserts installation id into ILIAS id
static prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free,...
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
static deliverData($a_data, $a_filename, $mime="application/octet-stream", $charset="")
deliver data for download via browser.
static _getObjectsByOperations($a_obj_type, $a_operation, $a_usr_id=0, $limit=0)
Get all objects of a specific type and check access This function is not recursive,...
static ilTempnam($a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
static removeTrailingPathSeparators($path)
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms @access public
static makeDir($a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
XML writer class.
xmlHeader()
Writes xml header @access public.
$login
Definition: cron.php:13
$key
Definition: croninfo.php:18
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
$i
Definition: disco.tpl.php:19
$tests
Definition: bench.php:104
$html
Definition: example_001.php:87
global $ilBench
Definition: ilias.php:18
global $ilCtrl
Definition: ilias.php:18
const SCORE_BEST_PASS
const SCORE_ZERO_POINTS_WHEN_UNANSWERED
const COUNT_PARTIAL_SOLUTIONS
const TEST_FIXED_SEQUENCE
Test constants.
const SCORE_CUT_QUESTION
const SCORE_LAST_PASS
const INVITATION_OFF
xslt_error(&$proc)
xslt_free(&$proc)
xslt_create()
Interface ilDBInterface.
$config
Definition: bootstrap.php:15
$time
Definition: cron.php:21
$index
Definition: metadata.php:60
$keys
$files
Definition: metarefresh.php:49
$row
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
update($pash, $contents, Config $config)
redirection script todo: (a better solution should control the processing via a xml file)
global $ilSetting
Definition: privfeed.php:17
$query
if(isset($_REQUEST['delete'])) $list
Definition: registry.php:41
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res
$datasets
Definition: showstats.php:85
global $ilDB
$results
Definition: svg-scanner.php:47
$values
$mobs
$ilUser
Definition: imgupload.php:18
$data
Definition: bench.php:6
$a_type
Definition: workflow.php:92
$rows
Definition: xhr_table.php:10