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 
4 require_once 'Services/Object/classes/class.ilObject.php';
5 require_once 'Modules/Test/classes/inc.AssessmentConstants.php';
6 require_once 'Modules/Test/interfaces/interface.ilMarkSchemaAware.php';
7 require_once 'Modules/Test/interfaces/interface.ilEctsGradesEnabled.php';
8 require_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 
61  private $questionSetType = self::QUESTION_SET_TYPE_FIXED;
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 
116  public $questions;
117 
122 
129  protected $introduction;
130 
136  public $mark_schema;
137 
146 
157 
166 
173 
183 
190 
197  public $nr_of_tries;
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 
294  public $mc_scoring;
295 
302 
310 
317 
324 
331 
335  protected $passwordEnabled;
336 
342  protected $password;
343 
348 
354  protected $allowedUsers;
355 
362 
369 
375  public $anonymity;
376 
382  public $show_cancel;
383 
389  public $show_marker;
390 
397 
404 
410  public $testSession;
411 
418 
425 
432 
438  private $_showinfo;
439 
445  private $_forcejs = true;
446 
452  private $_customStyle;
453 
454  protected $mailnotification;
455 
456  protected $mailnottype;
457 
458  protected $exportsettings;
459 
460  protected $poolUsage;
461 
462  private $template_id;
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 
511  protected $enable_examview;
512 
515 
518 
520  protected $enable_archiving;
521 
525  private $redirection_mode = 0;
526 
530  private $redirection_url = null;
531 
534 
537 
539  protected $sign_submission;
540 
543 
546 
551 
556 
561 
566 
571 
575  protected $testFinalBroken;
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 
714  public function getTitleFilenameCompliant()
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 
1005  public function hasSingleChoiceQuestions()
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);
1857  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc($data->introduction, 1));
1858  $this->setShowInfo($data->showinfo);
1859  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc($data->finalstatement, 1));
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()) {
2453  case self::SCORE_REPORTING_FINISHED:
2454  case self::SCORE_REPORTING_IMMIDIATLY:
2455  case self::SCORE_REPORTING_DATE:
2456  case self::SCORE_REPORTING_AFTER_PASSED:
2457 
2458  return true;
2459 
2460  case self::SCORE_REPORTING_DISABLED:
2461  default:
2462 
2463  return false;
2464  }
2465  }
2466 
2474  public function getInstantFeedbackSolution()
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 
2498  public function getGenericAnswerFeedback()
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 
2917  public function getProcessingTimeAsArray()
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 
2935  public function getProcessingTimeAsMinutes()
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 
2943  return self::DEFAULT_PROCESSING_TIME_MINUTES;
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 
2970  public function getSecondsUntilEndingTime()
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  {
3106  if ($use_previous_answers) {
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  {
3119  return $this->redirection_mode;
3120  }
3121  public function setRedirectionUrl($redirection_url = null)
3122  {
3123  $this->redirection_url = $redirection_url;
3124  }
3125  public function getRedirectionUrl()
3126  {
3127  return $this->redirection_url;
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  {
3218  return $this->passwordEnabled;
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 
3695  public function &getQuestionTitlesAndIndexes()
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 
5200  public function &_evalResultsOverview($test_id)
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":
5707  $this->setInstantFeedbackSolution(1);
5708  break;
5709  default:
5710  $this->setInstantFeedbackSolution(0);
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);
5736  $this->setListOfQuestionsSettings(7);
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 
6606  protected function buildIso8601PeriodFromUnixtimeForExportCompatibility($unix_timestamp)
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) {
7071  $obj_id = ilObject::_lookupObjId($ref_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 
7430  public function getInvitedParticipantList()
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 
7442  public function getActiveParticipantList()
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) {
7736  $obj_id = ilObject::_lookupObjId($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 
8636  public function getListOfQuestionsSettings()
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 
8834  public function getShowSolutionPrintview()
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 
8864  public function getShowSolutionAnswersOnly()
8865  {
8866  if (($this->results_presentation & 16) > 0) {
8867  return true;
8868  } else {
8869  return false;
8870  }
8871  }
8872 
8879  public function getShowSolutionSignature()
8880  {
8881  if (($this->results_presentation & 32) > 0) {
8882  return true;
8883  } else {
8884  return false;
8885  }
8886  }
8887 
8892  public function getShowSolutionSuggested()
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  {
9098  return $this->limitUsersEnabled;
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 
9129  public function checkMaximumAllowedUsers()
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 
9329  public function getCertificateVisibility()
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 
10327  public function getAggregatedResultsData()
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  {
10415  return $this->mailnotification;
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";
10500  $testSession = new ilTestSession();
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 {
10637  if ($this->getExportSettingsSingleChoiceShort()) {
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 (
10711  $this->getSpecificAnswerFeedback() || $this->getGenericAnswerFeedback() ||
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);
10747  $this->setInstantFeedbackSolution(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  {
10942  return $this->oldOnlineStatus;
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():
11244  return self::HIGHSCORE_SHOW_ALL_TABLES;
11245  break;
11246 
11247  case $this->getHighscoreTopTable():
11248  return self::HIGHSCORE_SHOW_TOP_TABLE;
11249  break;
11250 
11251  case $this->getHighscoreOwnTable():
11252  default:
11253  return self::HIGHSCORE_SHOW_OWN_TABLE;
11254  break;
11255  }
11256  }
11257 
11261  public function setHighscoreMode($mode)
11262  {
11263  switch ($mode) {
11264  case self::HIGHSCORE_SHOW_ALL_TABLES:
11265  $this->setHighscoreTopTable(1);
11266  $this->setHighscoreOwnTable(1);
11267  break;
11268 
11269  case self::HIGHSCORE_SHOW_TOP_TABLE:
11270  $this->setHighscoreTopTable(1);
11271  $this->setHighscoreOwnTable(0);
11272  break;
11273 
11274  case self::HIGHSCORE_SHOW_OWN_TABLE:
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 
11295  public function getSpecificAnswerFeedback()
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 
11393  return !self::hasObligations($test_id);
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
11461 
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  {
11490  return $this->show_examview_pdf;
11491  }
11492 
11497  {
11498  $this->enable_examview = $enable_examview;
11499  }
11500 
11504  public function getEnableExamview()
11505  {
11506  return $this->enable_examview;
11507  }
11508 
11509  #endregion
11510 
11512  {
11513  $this->activation_starting_time = $starting_time;
11514  }
11515 
11516  public function setActivationEndingTime($ending_time = null)
11517  {
11518  $this->activation_ending_time = $ending_time;
11519  }
11520 
11521  public function getActivationStartingTime()
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  {
11654  return $this->enable_archiving;
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  {
11762  return $this->sign_submission;
11763  }
11764 
11768  public function setCharSelectorAvailability($availability)
11769  {
11770  $this->char_selector_availability = (int) $availability;
11771  }
11772 
11777  {
11778  return (int) $this->char_selector_availability;
11779  }
11780 
11784  public function setCharSelectorDefinition($definition = '')
11785  {
11786  $this->char_selector_definition = $definition;
11787  }
11788 
11792  public function getCharSelectorDefinition()
11793  {
11795  }
11796 
11797 
11804  {
11805  $this->questionSetType = $questionSetType;
11806  }
11807 
11813  public function getQuestionSetType()
11814  {
11815  return $this->questionSetType;
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  {
11850  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED;
11851  }
11852 
11858  public function isRandomTest()
11859  {
11860  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_RANDOM;
11861  }
11862 
11868  public function isDynamicTest()
11869  {
11870  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC;
11871  }
11872 
11880  public static function _lookupRandomTest($a_obj_id)
11881  {
11882  return self::lookupQuestionSetType($a_obj_id) == self::QUESTION_SET_TYPE_RANDOM;
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 
11997  return self::$isSkillManagementGloballyActivated;
11998  }
11999 
12001  {
12002  $this->showGradingStatusEnabled = $showGradingStatusEnabled;
12003  }
12004 
12005  public function isShowGradingStatusEnabled()
12006  {
12008  }
12009 
12011  {
12012  $this->showGradingMarkEnabled = $showGradingMarkEnabled;
12013  }
12014 
12015 
12016  public function isShowGradingMarkEnabled()
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  {
12125  return $this->testFinalBroken;
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 }
setAllowedUsers($a_allowed_users)
static _getUserIdFromActiveId($active_id)
setAnswerFeedback($answer_feedback=0)
Sets the generic feedback for the test Use setGenericAnswerFeedback instead.
setECTSFX($a_ects_fx)
{}
saveCertificateVisibility($a_value)
Saves the visibility settings of the certificate.
static _lookupName($a_user_id)
lookup user name
xslt_create()
getExportDirectory()
Get the location of the export directory for the test.
& getWorkedQuestions($active_id, $pass=null)
Gets the id&#39;s of all questions a user already worked through.
setHighscoreTopTable($a_top_table)
Sets if the top-rankings table should be shown.
setPassScoring($a_pass_scoring=SCORE_LAST_PASS)
Sets the pass scoring.
setSkillServiceEnabled($skillServiceEnabled)
getListOfQuestionsDescription()
Returns TRUE if the list of questions should be presented with the question descriptions.
setOldOnlineStatus($oldOnlineStatus)
buildStatisticsAccessFilteredParticipantList()
getScoreReporting()
Gets the score reporting of the ilObjTest object.
getTimeExtensionsOfParticipants()
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms public
isHTML($a_text)
Checks if a given string contains HTML or not.
const SCORE_REPORTING_DISABLED
inviteRole($role_id)
Invites all users of a role to a test.
static _getWorkingTimeOfParticipantForPass($active_id, $pass)
Returns the complete working time in seconds for a test participant.
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.
setMailNotification($a_notification)
Set mail notification settings.
setAutosave($autosave)
isDynamicTest()
Returns the fact wether this test is a dynamic question set test or not.
static deliverData($a_data, $a_filename, $mime="application/octet-stream", $charset="")
deliver data for download via browser.
setEnableExamview($enable_examview)
isTestFinished($active_id)
returns if the active for user_id has been submitted
static getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
static _getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
setPassword($a_password=null)
Sets the password for test access.
& processCSVRow($row, $quoteAll=false, $separator=";")
Processes an array as a CSV row and converts the array values to correct CSV values.
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
static _getOriginalId($question_id)
Returns the original id of a question.
createMetaData()
Create meta data entry.
static getPluginObject(string $a_ctype, string $a_cname, string $a_slot_id, string $a_pname)
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
setPassDeletionAllowed($passDeletionAllowed)
setter for the test setting passDeletionAllowed
if(isset($_REQUEST['delete'])) $list
Definition: registry.php:41
getECTSOutput()
{int|bool}
_getTitleOutput($active_id)
Returns the value of the title_output status.
setOnline($a_online=true)
getFixedParticipants()
Returns the fixed participants status.
static _getObjectIDFromTestID($test_id)
Returns the ILIAS test object id for a given test id.
setShowExamIdInTestPassEnabled($show_exam_id_in_test_pass_enabled)
setForceInstantFeedbackEnabled($forceInstantFeedbackEnabled)
deliverPDFfromFO($fo, $title=null)
Delivers a PDF file from a XSL-FO string.
getReportingDate()
Gets the reporting date of the ilObjTest object.
static _includeClass($question_type, $gui=0)
Include the php class file for a given question type.
static _updateTestResultCache($active_id, ilAssQuestionProcessLocker $processLocker=null)
Move this to a proper place.
getCustomStyle()
Get the custom style.
getResultsPresentation()
Returns the combined results presentation value.
const DEFAULT_PROCESSING_TIME_MINUTES
$followupQuestionAnswerFixationEnabled
static allObligationsAnswered($test_id, $active_id, $pass)
checks wether all questions marked as obligatory were answered within the test pass with given testId...
setShowKioskModeTitle($a_title=false)
Set to true, if the full test title should be shown in kiosk mode.
logAction($logtext="", $question_id="")
Logs an action into the Test&Assessment log.
getProcessingTimeAsMinutes()
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static sumTimesInISO8601FormatH_i_s_Extended($time1, $time2)
isPassDeletionAllowed()
getter for the test setting passDeletionAllowed
static _getParticipantData($active_id)
Retrieves a participant name from active id.
_buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
Builds a user name for the output depending on test type and existence of the user.
removeTestResultsByUserIds($userIds)
setShowExamviewPdf($show_examview_pdf)
$files
Definition: metarefresh.php:49
setShowPassDetails($a_details=1)
Sets if the pass details should be shown when a test is not finished.
const IL_CAL_DATETIME
& createQuestionGUI($question_type, $question_id=-1)
Creates a question GUI instance of a given question type.
isShowExamIdInTestPassEnabled()
setQuestionOrderAndObligations($orders, $obligations)
setRedirectionMode($redirection_mode=0)
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
setQuestionSetType($questionSetType)
setter for question set type
Class ilObjTestGUI.
setECTSOutput($a_ects_output)
{}
setActivationEndingTime($ending_time=null)
getTestStyleLocation($mode="output")
get full style sheet file name (path inclusive) of current user
static _prepareCloneSelection($a_ref_ids, $new_type, $show_path=true)
Prepare copy wizard object selection.
$_SESSION["AccountId"]
static _getQuestionType($question_id)
Returns the question type of a question with a given id.
checkQuestionParent($questionId)
static _getSolutionMaxPass($question_id, $active_id)
Returns the maximum pass a users question solution.
$config
Definition: bootstrap.php:15
$result
static _lookupTestObjIdForQuestionId($a_q_id)
Get test Object ID for question ID.
saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
Checks if the test is complete and saves the status in the database.
setReportingDate($reporting_date)
Sets the reporting date of the ilObjTest object.
getQuestionTitle($title, $nr=null)
Returns the title of a test question and checks if the title output is allowed.
setShowSolutionDetails($a_details=1)
Sets if the the solution details should be presented to the user or not.
canShowCertificate($testSession, $user_id, $active_id)
Checks whether the certificate button could be shown on the info page or not.
getMailNotification()
Get mail notification settings.
& evalStatistical($active_id)
Returns the statistical evaluation of the test for a specified user.
& getInvitedUsers($user_id="", $order="login, lastname, firstname")
Returns a list of all invited users in a test.
setCertificateVisibility($a_value)
Sets the visibility settings of the certificate.
getEnableProcessingTime()
Returns the state of the processing time (enabled/disabled)
getProcessingTimeAsArray()
Returns the processing time for the test.
const QUESTION_SET_TYPE_RANDOM
type setting value for random question set
getListOfQuestionsStart()
Returns if the list of questions should be presented as the first page of the test.
global $DIC
Definition: saml.php:7
static _lookupRandomTest($a_obj_id)
Returns the fact wether the test with passed obj id is a random questions test or not...
& getParticipants()
Returns all persons who started the test.
const SCORE_LAST_PASS
getCompleteWorkingTimeOfParticipant($active_id)
Returns the complete working time in seconds for a test participant.
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
Class ilFileDataMail.
loadFromDb()
loads the question set config for current test from the database
setResultFilterTaxIds($resultFilterTaxIds)
getCertificateVisibility()
Returns the visibility settings of the certificate.
loadFromDb()
Loads a ilObjTest object from a database.
setShuffleQuestions($a_shuffle)
Sets the status of the shuffle_questions variable.
setFixedParticipants($a_value=1)
Sets the fixed participants status.
fromXML(ilQTIAssessment $assessment)
Receives parameters from a QTI parser and creates a valid ILIAS test object.
getPresentationMaterial()
{ilQTIPresentationMaterial|null}
getShowSolutionFeedback()
Returns if the feedback should be presented to the solution or not.
setTmpCopyWizardCopyId($tmpCopyWizardCopyId)
updateMetaData()
update meta data entry
xslt_free(&$proc)
static _getPassScoring($active_id)
Gets the pass scoring type.
static lookupPassResultsUpdateTimestamp($active_id, $pass)
& getExistingQuestions($pass=null)
Get the id&#39;s of the questions which are already part of the test.
setInstantFeedbackOptionsByArray($options)
setCharSelectorDefinition($definition='')
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...
getShowKioskModeParticipant()
Returns the status of the kiosk mode participant.
setHighscoreMode($mode)
static $isSkillManagementGloballyActivated
setHighscoreScore($a_score)
Sets if the actual score should be displayed.
const SCORE_REPORTING_AFTER_PASSED
static factory($a_package, $a_timeout=0)
Creates an ilRpcClient instance to our ilServer.
insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly=false)
Insert a question in the list of questions.
getQuestionSetTypeTranslation(ilLanguage $lng, $questionSetType)
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
getTestId()
Gets the database id of the additional test data.
setHighscoreWTime($a_wtime)
Sets if the workingtime of the scores should be shown.
& evalTotalPersonsArray($name_sort_order="asc")
Returns all persons who started the test.
_isComplete($obj_id)
Returns true, if a test is complete for use.
Class ilTestMailNotification.
static getItem($a_ref_id)
Get item data.
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, instead it parses the serialized rbac_pa entries.
getListOfQuestionsSettings()
Returns the settings for the list of questions options in the test properties This could contain one ...
getOfflineStatus()
Get offline status.
getShowInfo()
Gets whether the complete information page is shown or the required data only.
& getQuestionTitlesAndIndexes()
Returns the titles of the test questions in question sequence.
isNewRandomTest()
Checks wheather the test is a new random test (using tst_rnd_cpy) or an old one.
$factory
Definition: metadata.php:43
getJavaScriptOutput()
Returns if Javascript should be chosen for drag & drop actions for the active user.
setPassWaiting($pass_waiting)
getECTSGrade($passed_array, $reached_points, $max_points)
{Returns the ECTS grade for a number of reached points.An array with the points of all users who pass...
getShowSolutionAnswersOnly()
Returns if the full solution (including ILIAS content) should be presented to the solution or not...
XML writer class.
& createTestSequence($active_id, $pass, $shuffle)
static getPoolQuestionChangeListener(ilDBInterface $db, $poolObjId)
setFinalStatement($a_statement="")
Sets the final statement text of the ilObjTest object.
& _evalResultsOverview($test_id)
Creates an associated array with the results of all participants of a test.
& getQuestionsOfTest($active_id)
Retrieves all the assigned questions for all test passes of a test participant.
Question page object.
setScoreCutting($a_score_cutting=SCORE_CUT_QUESTION)
Sets the type of score cutting.
sendAdvancedNotification($active_id)
getXMLZip()
Get zipped xml file for test.
setResetProcessingTime($reset=0)
Sets wheather the processing time should be reset or not.
setCharSelectorAvailability($availability)
setShowMarker($a_value=1)
Sets the marker button status.
inviteUser($user_id, $client_ip="")
Invites a user to a test.
setParticipantAccessFilter($participantAccessFilter)
static _lookupTitle($a_id)
lookup object title
getAnonymity()
Returns the anonymity status of the test.
getFixedQuestionSetTotalWorkingTime()
toXML()
Returns a QTI xml representation of the test.
getQuestionCount()
Returns the number of questions in the test.
setEndingTimeEnabled($ending_time_enabled)
setActivationLimited($a_value)
TableGUI class for evaluation of all users.
$index
Definition: metadata.php:60
setSpecificAnswerFeedback($specific_answer_feedback)
getShuffleQuestions()
Returns the status of the shuffle_questions variable.
static _lookupClientIP($a_user_id)
Lookup client ip.
setTestId($a_id)
Sets the test ID.
create()
create test object
isPreviousSolutionReuseEnabled($activeId)
isShowExamIdInTestResultsEnabled()
_getVisitTimeOfParticipant($test_id, $active_id)
Returns the first and last visit of a participant.
& getTestParticipants()
Returns a list of all participants in a test.
getCompleteWorkingTime($user_id)
Returns the complete working time in seconds a user worked on the test.
getShowSolutionDetails()
Returns if the solution details should be presented to the user or not.
getImagePathWeb()
Returns the web image path for web accessable images of a test The image path is under the web access...
const IL_CAL_UNIX
startingTimeReached()
Returns true if the starting time of a test is reached A starting time is not available for self asse...
static _removeUsage($a_mob_id, $a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
Remove usage of mob in another container.
$keys
questionMoveDown($question_id)
Moves a question down in order.
getOwner()
get object owner
static _saveTempFileAsMediaObject($name, $tmp_name, $upload=true)
Create new media object and update page in db and return new media object.
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
isSingleChoiceTest()
Returns TRUE if the test contains single choice results only.
getActiveIdOfUser($user_id="", $anonymous_id="")
Gets the active id of a given user.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
setShowGradingStatusEnabled($showGradingStatusEnabled)
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
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...
& getGroupData($ids)
static formatDate(ilDateTime $date, $a_skip_day=false, $a_include_wd=false, $include_seconds=false)
Format a date public.
getPassed($active_id)
setRedirectionUrl($redirection_url=null)
static _getBestPass($active_id)
Retrieves the best pass of a given user for a given test.
$total
Definition: Utf8Test.php:87
static _lookupAnonymity($a_obj_id)
Returns the anonymity status of a test with a given object id.
setEndingTime($ending_time=null)
Sets the ending time in database timestamp format for the test.
getShowSolutionListComparison()
setQuestionSetSolved($value, $question_id, $user_id)
sets question solved state to value for given user_id
Base Exception for all Exceptions relating to Modules/Test.
setListOfQuestionsStart($a_value=true)
Sets if the the list of questions as the start page of the test.
loadQuestions($active_id="", $pass=null)
Load the test question id&#39;s from the database.
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
setMailNotificationType($a_type)
setTitle($a_title)
set object title
startWorkingTime($active_id, $pass)
Write the initial entry for the tests working time to the database.
isTestQuestion($questionId)
setObligationsEnabled($obligationsEnabled=true)
sets obligations enabled/disabled
setHighscoreOwnTable($a_own_table)
Sets if the table with the own ranking should be shown.
setTitleOutput($title_output=0)
Sets the status of the title output.
disinviteUser($user_id)
Disinvites a user from a test.
Test sequence handler.
setShowSolutionPrintview($a_printview=1)
Sets if the the solution printview should be presented to the user or not.
areObligationsEnabled()
returns the fact wether obligations are enabled or not
& getQuestionTitles()
Returns the titles of the test questions in question sequence.
& evalResultsOverview()
Creates an associated array with the results of all participants of a test.
getSequenceSettings()
SEQUENCE SETTING = POSTPONING ENABLED !!
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
global $ilCtrl
Definition: ilias.php:18
isMaxProcessingTimeReached($starting_time, $active_id)
Returns whether the maximum processing time for a test is reached or not.
& _getCompleteWorkingTimeOfParticipants($test_id)
Returns the complete working time in seconds for all test participants.
isRandomTest()
Returns the fact wether this test is a random questions test or not.
setTestFinalBroken($testFinalBroken)
getHighscorePercentage()
Gets if the percentage column should be shown.
isFixedTest()
Returns the fact wether this test is a fixed question set test or not.
checkMarks()
{boolean|string True or an error string which can be used for display purposes}
setPoolUsage($usage)
setShowKioskModeParticipant($a_participant=false)
Set to true, if the participant&#39;s name should be shown in kiosk mode.
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
$time
Definition: cron.php:21
updateWorkingTime($times_id)
Update the working time of a test when a question is answered.
getFixedQuestionSetTotalPoints()
$a_type
Definition: workflow.php:92
isExecutable($testSession, $user_id, $allowPassIncrease=false)
Checks if the test is executable by the given user.
$instantFeedbackAnswerFixationEnabled
xslt_error(&$proc)
exportFileItems($a_target_dir, &$expLog)
export files of file itmes
static _getLogLanguage()
retrieve the log language for assessment logging
setSignSubmission($sign_submission)
static completeMissingPluginName($questionTypeData)
getImportMapping()
get array of (two) new created questions for import id
static _getMaxPass($active_id)
Retrieves the maximum pass of a given user for a given test in which the user answered at least one q...
setProcessingTimeByMinutes($minutes)
addDefaults($a_name)
Adds the defaults of this test to the test defaults.
getCountSystem()
Gets the count system for the calculation of points.
const SCORE_REPORTING_IMMIDIATLY
getIntroduction()
Gets the introduction text of the ilObjTest object.
hasAnyTestResult(ilTestSession $testSession)
getMarkSchemaForeignId()
{int}
setNrOfTries($nr_of_tries=0)
Sets the nr of tries for the test.
setScoreReporting($score_reporting=0)
Sets the score reporting of the ilObjTest object.
__construct($a_id=0, $a_call_by_reference=true)
Constructor.
removeTestResults(ilTestParticipantData $participantData)
setStartingTime($starting_time=null)
Sets the starting time in database timestamp format for the test.
setAnswerFeedbackPoints($answer_feedback_points=0)
Sets the answer specific feedback of reached points for the test.
getHighscoreHints()
Gets, if the column with the number of requested hints should be shown.
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
getAccessFilteredParticipantList()
setShowCancel($a_value=1)
Sets the cancel test button status.
getQuestiontext($question_id)
Returns the question text for a given question.
static _getInstance($a_copy_id)
Get instance of copy wizard options.
getShowKioskModeTitle()
Returns the status of the kiosk mode title.
buildName($user_id, $firstname, $lastname, $title)
Builds a user name for the output depending on test type and existence of the user.
& getTestDefaults($test_defaults_id)
Returns the test defaults for a given id.
setLimitUsersEnabled($limitUsersEnabled)
setAutosaveIval($autosave_ival)
setExportSettingsSingleChoiceShort($a_settings)
setCustomStyle($a_customStyle=null)
Set the custom style.
getVisitTimeOfParticipant($active_id)
Returns the first and last visit of a participant.
getListOfQuestions()
Returns if the list of questions should be presented to the user or not.
QTIMaterialToString($a_material)
Reads an QTI material tag an creates a text string.
setProcessingTime($processing_time="00:00:00")
Sets the processing time for the test.
foreach($_POST as $key=> $value) $res
setCountSystem($a_count_system=COUNT_PARTIAL_SOLUTIONS)
Sets the count system for the calculation of points.
createRandomSolutions($number)
getAllTestResults($participants, $prepareForCSV=true)
returns all test results for all participants
getResetProcessingTime()
Returns wheather the processing time should be reset or not.
setShowSolutionSuggested($a_solution=false)
Set to TRUE, if the suggested solution should be shown in the solution.
getHighscoreAnon()
Gets if the highscores should be anonymized per setting.
$mobs
getTestParticipantsForManualScoring($filter=null)
$datasets
Definition: showstats.php:85
setExportSettings($a_settings)
saveToDb($properties_only=false)
Saves a ilObjTest object to a database.
static _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
removeQuestion($question_id)
Removes a question from the test object.
getId()
get object id public
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 ...
getInstantFeedbackOptionsAsArray()
static _addLog($user_id, $object_id, $logtext, $question_id="", $original_id="", $test_only=false, $test_ref_id=null)
Add an assessment log entry.
setHighscoreTopNum($a_top_num)
Sets the number of entries which are to be shown in the top-rankings table.
canShowEctsGrades()
{boolean}
setActivationVisibility($a_value)
hasQuestionsWithoutQuestionpool()
evalTotalPersons()
Returns the number of persons who started the test.
hasSingleChoiceQuestions()
Returns TRUE if the test contains single choice results.
static _getScoreCutting($active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test...
getStartingTimeOfUser($active_id, $pass=null)
Returns the unix timestamp of the time a user started a test.
getShowMarker()
Returns wheather the marker button is shown or not.
sendSimpleNotification($active_id)
getShowSolutionPrintview()
Returns if the solution printview should be presented to the user or not.
const SCORE_ZERO_POINTS_WHEN_UNANSWERED
getAnswerFeedback()
Returns 1 if generic answer feedback is activated.
$tests
Definition: bench.php:104
$values
hasNrOfTriesRestriction()
returns if the numbers of tries have to be checked
getTitleOutput()
Returns the value of the title_output status.
addExtraTime($active_id, $minutes)
const COUNT_PARTIAL_SOLUTIONS
const SCORE_CUT_QUESTION
getAuthor()
Gets the authors name of the ilObjTest object.
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
& getRoleData($ids)
static _lookupDescription($a_id)
lookup object description
randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id=0, $qpls="", $pass=null)
Returns a random selection of questions.
getUsePreviousAnswers()
Returns if the previous answers should be shown for a learner.
getShowPassDetails()
Returns if the pass details should be shown when a test is not finished.
static getManualFeedback($active_id, $question_id, $pass)
Retrieves the manual feedback for a question in a test.
isTestFinishedToViewResults($active_id, $currentpass)
Returns true if an active user completed a test pass and did not start a new pass.
getShowFinalStatement()
Returns whether the final statement should be shown or not.
static ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run=false)
addQTIMaterial(&$a_xml_writer, $a_material)
Creates a QTI material tag from a plain text or xhtml text.
setTemplate($template_id)
questionMoveUp($question_id)
Moves a question up in order.
static _lookupObjId($a_id)
const NEWS_NOTICE
special template class to simplify handling of ITX/PEAR
setShowInfo($a_info=1)
Set whether the complete information page is shown or the required data only.
static collectFileItems($a_page, $a_domdoc)
Get all file items that are used within the page.
getEvaluationAdditionalFields()
Gets additional user fields that should be shown in the user evaluation.
& getAllQuestions($pass=null)
Returns all questions of a test in test order.
setShowSolutionFeedback($a_feedback=true)
Sets if the the feedback should be presented to the user in the solution or not.
isSkillServiceToBeConsidered()
exportXMLMetaData(&$a_xml_writer)
export content objects meta data to xml (see ilias_co.dtd)
static _getCountSystem($active_id)
Gets the count system for the calculation of points.
setInstantFeedbackSolution($instant_feedback=0)
Sets the instant feedback for the solution.
setListOfQuestions($a_value=true)
Sets if the the list of questions should be presented to the user or not.
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
buildIso8601PeriodFromUnixtimeForExportCompatibility($unix_timestamp)
setAllowedUsersTimeGap($a_allowed_users_time_gap)
getTitle()
get object title public
applyDefaults($test_defaults)
Applies given test defaults to this test.
getDescription()
get object description
getProcessingTime()
Returns the processing time for the test.
const IL_COMP_MODULE
Date and time handling
isOfferingQuestionHintsEnabled()
returns the fact wether offering hints is enabled or not
removeTestActives($activeIds)
exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export media objects to xml (see ilias_co.dtd)
$ilUser
Definition: imgupload.php:18
hasRandomQuestionsForPass($active_id, $pass)
Checkes wheather a random test has already created questions for a given pass or not.
redirection script todo: (a better solution should control the processing via a xml file) ...
cloneMetaData($target_obj)
Copy meta data.
xmlHeader()
Writes xml header public.
getAnsweredQuestionCount($active_id, $pass=null)
Retrieves the number of answered questions for a given user in a given test.
isBestSolutionPrintedWithResult()
static isSkillManagementGloballyActivated()
getAnswerFeedbackPoints()
Returns 1 if answer specific feedback as reached points is activated.
static _lookupOwner($a_id)
lookup object owner
createExportDirectory()
creates data directory for export files (data_dir/tst_data/tst_<id>/export, depending on data directo...
getStartTestLabel($active_id)
Returns the "Start the Test" label for the Info page.
setAccessFilteredParticipantList($accessFilteredParticipantList)
setECTSGrades(array $a_ects_grades)
{}
Class ilObjMediaObject.
Test session handler.
removeTestResultsFromSoapLpAdministration($userIds)
getMarkSchema()
{ASS_MarkSchema}
$query
getAggregatedResultsData()
Returns the aggregated test results.
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
getStartingTime()
Returns the starting time of the test.
getStartingTimeOfParticipants()
Note, this function should only be used if absolutely necessary, since it perform joins on tables tha...
setAnonymity($a_value=0)
Sets the anonymity status of the test.
static lookupLastTestPassAccess($activeId, $passIndex)
getShowSolutionSignature()
Returns if the signature field should be shown in the test results.
getAllRTEContent()
Returns the content of all RTE enabled text areas in the test.
static removeTrailingPathSeparators($path)
Class ilTestScoring.
static isQuestionObligationPossible($questionId)
checks wether the obligation for question with given id is possible or not
static _lookupFinishedUserTests($a_user_id)
Gather all finished tests for user.
pcArrayShuffle($array)
Shuffles the values of a given array.
getType()
get object type public
const INVITATION_OFF
static _getTestIDFromObjectID($object_id)
Returns the ILIAS test id for a given object id.
getInstantFeedbackSolution()
Returns 1 if the correct solution will be shown after answering a question.
getFinalStatement()
Gets the final statement.
setKiosk($kiosk=0)
Sets the kiosk mode for the test.
removeQuestionFromSequences($questionId, $activeIds, ilTestReindexedSequencePositionMap $reindexedSequencePositionMap)
isHighscoreAnon()
Gets if the highscores should be displayed anonymized.
inviteGroup($group_id)
Invites all users of a group to a test.
setUsePreviousAnswers($use_previous_answers=1)
Sets the status of the visibility of previous learner answers.
$default
Definition: build.php:20
$filename
Definition: buildRTE.php:89
setTimingType($a_type)
Set timing type.
isAnyInstantFeedbackOptionEnabled()
static makeDir($a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
setResultsPresentation($a_results_presentation=3)
Sets the combined results presentation value.
const SCORE_REPORTING_FINISHED
$row
isInstantFeedbackAnswerFixationEnabled()
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
static _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
{Returns the ECTS grade for a number of reached points.The points reached in the test The maximum num...
$rows
Definition: xhr_table.php:10
const TEST_FIXED_SEQUENCE
Test constants.
update($pash, $contents, Config $config)
getPassword()
Returns the password for test access.
getNrOfTries()
Returns the nr of tries for the test.
duplicateQuestionForTest($question_id)
Takes a question and creates a copy of the question for use in the test.
setForceJS($a_js=1)
Set whether JavaScript should be forced for tests.
setPostponingEnabled($postponingEnabled)
static hasObligations($test_id)
returns the fact wether the test with given test id contains questions markes as obligatory or not ...
setHighscoreHints($a_hints)
Sets if the number of requested hints should be shown.
isForceInstantFeedbackEnabled()
setEnableProcessingTime($enable=0)
Sets the processing time enabled or disabled.
static ilTempnam($a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
& getTotalPointsPassedArray()
Returns an array with the total points of all users who passed the test This array could be used for ...
static _getSuggestedSolutionOutput($question_id)
Returns the output of the suggested solution.
getQuestionDataset($question_id)
Returns the dataset for a given question id.
_getLastAccess($active_id)
getResultsForActiveId($active_id)
setResultsPresentationOptionsByArray($options)
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.
setEnabledViewMode($mode)
getQuestionSetType()
getter for question set type
const SCORE_REPORTING_DATE
setHighscoreAchievedTS($a_achieved_ts)
Sets if the date and time of the scores achievement should be displayed.
getGenericAnswerFeedback()
Returns 1 if generic answer feedback is to be shown.
setShowSolutionListComparison($a_comparison=false)
Set to TRUE, if the list of answers should be shown prior to finish the test.
setEnableArchiving($enable_archiving)
getEstimatedWorkingTime()
Returns the estimated working time for the test calculated from the working time of the contained que...
isSingleChoiceTestWithoutShuffle()
Returns TRUE if the test contains single choice results and no shuffle only.
$show_exam_id_in_test_pass_enabled
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.
getEndingTime()
Returns the ending time of the test.
setPasswordEnabled($passwordEnabled)
setShowExamviewHtml($show_examview_html)
getAvailableQuestions($arrFilter, $completeonly=0)
Calculates the available questions for a test.
& getUserData($ids)
Returns a data of all users specified by id list.
static getDataDir()
get data directory (outside webspace)
getTextAnswer($active_id, $question_id, $pass=null)
Returns the text answer of a given user for a given question.
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test...
setKioskMode($a_kiosk=false)
Sets the kiosk mode for the test.
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename
getCustomStyles()
Return the available custom styles.
const HIGHSCORE_SHOW_TOP_TABLE
cleanupMediaobjectUsage()
Cleans up the media objects for all text fields in a test which are using an RTE field.
_lookupRandomTestFromActiveId($active_id)
Returns the random status of a test with a given object id.
static _getManualScoring()
Retrieve the manual scoring settings.
deleteTest()
Deletes the test and all related objects, files and database entries.
global $ilSetting
Definition: privfeed.php:17
setShowSolutionAnswersOnly($a_full=true)
Set to true, if the full solution (including the ILIAS content pages) should be shown in the solution...
static _getAvailableTests($use_object_id=false)
Returns the available tests for the active user.
setOfferingQuestionHintsEnabled($offeringQuestionHintsEnabled)
sets offering question hints enabled/disabled
getExtraTime($active_id)
setOfflineStatus($a_status)
Set offline status.
moveQuestions($move_questions, $target_index, $insert_mode)
Move questions to another position.
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd)
$results
Definition: svg-scanner.php:47
recalculateScores($preserve_manscoring=false)
getECTSGrades()
{array}
static _getMCScoring($active_id)
Gets the scoring type for multiple choice questions.
& evalTotalParticipantsArray($name_sort_order="asc")
Returns all participants who started the test.
$print_best_solution_with_result
setPrintBestSolutionWithResult($status)
getKioskMode()
Returns the kiosk mode.
const HIGHSCORE_SHOW_OWN_TABLE
setMCScoring($a_mc_scoring=SCORE_ZERO_POINTS_WHEN_UNANSWERED)
Sets the multiple choice scoring.
getExportSettingsSingleChoiceShort()
global $ilBench
Definition: ilias.php:18
global $ilDB
deleteDefaults($test_default_id)
Deletes the defaults for a test.
update()
update object data
endingTimeReached()
Returns true if the ending time of a test is reached An ending time is not available for self assessm...
& 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...
getECTSFX()
{float|null}
const QUESTION_SET_TYPE_FIXED
type setting value for fixed question set
isActiveTestSubmitted($user_id=null)
returns if the active for user_id has been submitted
setHighscoreAnon($a_anon)
Sets if the highscores should be anonymized.
modifyExportIdentifier($a_tag, $a_param, $a_value)
Returns the installation id for a given identifier.
setFollowupQuestionAnswerFixationEnabled($followupQuestionAnswerFixationEnabled)
saveAuthorToMetadata($a_author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
$i
Definition: disco.tpl.php:19
getRefId()
get reference id public
getQuestionType($question_id)
Returns the question type of a question with a given id.
static buildExamId($active_id, $pass, $test_obj_id=null)
static getInstanceByRefId($a_ref_id, $stop_on_error=true)
get an instance of an Ilias object by reference id
static insertInstIntoID($a_value)
inserts installation id into ILIAS id
Class ilObjGroup.
setGenericAnswerFeedback($generic_answer_feedback=0)
Sets if the generic feedback is to be shown in the test.
removeTestResultsByActiveIds($activeIds)
setShowExamIdInTestResultsEnabled($show_exam_id_in_test_results_enabled)
getSecondsUntilEndingTime()
Returns the seconds left from the actual time until the ending time.
deleteMetaData()
delete meta data entry
& getCompleteWorkingTimeOfParticipants()
Returns the complete working time in seconds for all test participants.
& getCompleteEvaluationData($withStatistics=true, $filterby="", $filtertext="")
static getGuiClassNameByQuestionType($questionType)
canEditEctsGrades()
{boolean}
getProcessingTimeInSeconds($active_id="")
Returns the processing time for the test in seconds.
language handling
static _cleanupMediaObjectUsage($a_text, $a_usage_type, $a_usage_id)
Synchronises appearances of media objects in $a_text with media object usage table.
setDescription($a_desc)
set object description
getShowCancel()
Returns wheather the cancel test button is shown or not.
canShowTestResults(ilTestSession $testSession)
$login
Definition: cron.php:13
setIntroduction($introduction="")
Sets the introduction text of the ilObjTest object.
getNrOfResultsForPass($active_id, $pass)
Calculates the number of user results for a specific test pass.
setClientIP($user_id, $client_ip)
static recursive_dirscan($dir, &$arr)
Recursively scans a given directory and writes path and filename into referenced array.
const NEWS_USERS
A class defining mark schemas for assessment test objects.
canShowSolutionPrintview($user_id=null)
Calculates if a user may see the solution printview of his/her test results.
getHighscoreScore()
Gets if the score column should be shown.
setActivationStartingTime($starting_time=null)
static getTestObjIdsWithActiveForUserId($userId)
getListOfQuestionsEnd()
Returns if the list of questions should be presented as the last page of the test.
isPluginActive($a_pname)
Checks wheather or not a question plugin with a given name is active.
isFollowupQuestionAnswerFixationEnabled()
txt($a_topic, $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
setHighscoreEnabled($a_enabled)
Sets if the highscore feature should be enabled.
static _exists($a_id, $a_reference=false, $a_type=null)
checks wether a lm content object with specified id exists or not
static isParticipantsLastPassActive($testRefId, $userId)
& evalResultsOverviewOfParticipant($active_id)
Creates an associated array with the results for a given participant of a test.
saveQuestionsToDb()
Saves the test questions to the database.
getMCScoring()
Gets the scoring type for multiple choice questions.
setShowGradingMarkEnabled($showGradingMarkEnabled)
getHighscoreEnabled()
Gets the setting which determines if the highscore feature is enabled.
setAuthor($author="")
Sets the authors name of the ilObjTest object.
getKiosk()
Returns the kiosk mode.
moveQuestionAfterOLD($previous_question_id, $new_question_id)
setInstantFeedbackAnswerFixationEnabled($instantFeedbackAnswerFixationEnabled)
moveQuestionAfter($question_to_move, $question_before)
setHighscorePercentage($a_percentage)
Sets if the percentages of the scores pass should be shown.
setIntroductionEnabled($introductionEnabled)
static _getUsePreviousAnswers($active_id, $user_active_user_setting=false)
Returns if the previous results should be hidden for a learner.
static lookupQuestionSetType($objId)
lookup-er for question set type
static lookupQuestionSetTypeByActiveId($active_id)
returns the question set type of test relating to passed active id
const QUESTION_SET_TYPE_DYNAMIC
type setting value for dynamic question set (continues testing mode)
deliverPDFfromHTML($content, $title=null)
Delivers a PDF file from XHTML.
static getInstance($a_obj_id)
getDetailedTestResults($participants)
returns all test results for all participants
const HIGHSCORE_SHOW_ALL_TABLES
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
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.
isNrOfTriesReached($tries)
returns if number of tries are reached
removeQuestions($removeQuestionIds)
exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
export page objects to xml (see ilias_co.dtd)
& getQuestionsOfPass($active_id, $pass)
Retrieves all the assigned questions for a test participant in a given test pass. ...
setListOfQuestionsDescription($a_value=true)
Sets the show_summary attribute to TRUE if the list of questions should be presented with the questio...
getForceJS()
Gets whether JavaScript should be forced for tests.
Class ilObjectActivation.
$key
Definition: croninfo.php:18
isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
Returns true, if a test is complete for use and can be set online.
static getFeedbackClassNameByQuestionType($questionType)
static _getQuestionTitle($question_id)
Returns the question title of a question with a given id.
setShowFinalStatement($show=0)
Sets whether the final statement should be shown or not.
$html
Definition: example_001.php:87
static deleteRequestsByActiveIds($activeIds)
Deletes all hint requests relating to a testactive included in given active ids.
setSequenceSettings($sequence_settings=0)
SEQUENCE SETTING = POSTPONING ENABLED !!
reindexFixedQuestionOrdering()
setListOfQuestionsSettings($a_value=0)
Sets the settings for the list of questions options in the test properties This could contain one of ...
const SCORE_BEST_PASS
setListOfQuestionsEnd($a_value=true)
Sets if the the list of questions as the end page of the test.
static _setImportDirectory($a_import_dir=null)
set import directory
static _getTestDefaults($test_defaults_id)
read()
read object data from db into object
for($i=6; $i< 13; $i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
setShowSolutionSignature($a_signature=false)
Set to TRUE, if the signature field should be shown in the solution.
userLookupFullName($user_id, $overwrite_anonymity=false, $sorted_order=false, $suffix="")
Returns the full name of a test user according to the anonymity status.
static _getActiveIdOfUser($user_id="", $test_id="")
Gets the active id of the tst_active table for the active user.
setStartingTimeEnabled($starting_time_enabled)
getHighscoreTopNum($a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
static _getImportDirectory()
Get the import directory location of the test.
$test
Definition: Utf8Test.php:84
& 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.
$data
Definition: bench.php:6
$show_exam_id_in_test_results_enabled
getImagePath()
Returns the image path for web accessable images of a test The image path is under the CLIENT_WEB_DIR...
static lookupExamId($active_id, $pass)
evalTotalStartedAverageTime($activeIdsFilter=null)
Returns the average processing time for all started tests.
getPassScoring()
Gets the pass scoring type.