ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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 
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 
469  private $online = null;
470 
471  protected $oldOnlineStatus = null;
472 
477 
484 
490  private $obligationsEnabled = null;
491 
493 
495 
497 
498  protected $autosave;
499 
500  protected $autosave_ival;
501 
508  private $passDeletionAllowed = null;
509 
515  private $participantDataExist = null;
516 
518  protected $enable_examview;
519 
522 
525 
527  protected $enable_archiving;
528 
532  private $redirection_mode = 0;
533 
537  private $redirection_url = null;
538 
541 
544 
546  protected $sign_submission;
547 
550 
553 
558 
563 
568 
573 
577  protected $testFinalBroken;
578 
583 
587  protected $pass_waiting = "00:000:00:00:00";
588  #endregion
589 
598  public function __construct($a_id = 0, $a_call_by_reference = true)
599  {
600  global $ilUser, $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 = REPORT_AFTER_TEST;
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->instantFeedbackAnswerFixationEnabled = false;
700 
701  $this->testFinalBroken = false;
702 
703  $this->tmpCopyWizardCopyId = null;
704 
705  parent::__construct($a_id, $a_call_by_reference);
706  }
707 
713  public function getTitleFilenameCompliant()
714  {
715  require_once 'Services/Utilities/classes/class.ilUtil.php';
716  return ilUtil::getASCIIFilename($this->getTitle());
717  }
718 
722  public function getTmpCopyWizardCopyId()
723  {
725  }
726 
731  {
732  $this->tmpCopyWizardCopyId = $tmpCopyWizardCopyId;
733  }
734 
738  public function create()
739  {
740  parent::create();
741 
742  // meta data will be created by
743  // import parser
744  if (!$a_upload) {
745  $this->createMetaData();
746  }
747  }
748 
755  public function update()
756  {
757  if (!parent::update()) {
758  return false;
759  }
760 
761  // put here object specific stuff
762  $this->updateMetaData();
763  return true;
764  }
765 
771  public function read()
772  {
773  parent::read();
774  $this->loadFromDb();
775  }
776 
777 
784  public function delete()
785  {
786  // always call parent delete function first!!
787  if (!parent::delete()) {
788  return false;
789  }
790 
791  // delet meta data
792  $this->deleteMetaData();
793 
794  //put here your module specific stuff
795  $this->deleteTest();
796 
797  require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentImportFails.php';
798  $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($this->getId());
799  $qsaImportFails->deleteRegisteredImportFails();
800  require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdImportFails.php';
801  $sltImportFails = new ilTestSkillLevelThresholdImportFails($this->getId());
802  $sltImportFails->deleteRegisteredImportFails();
803 
804  return true;
805  }
806 
812  public function deleteTest()
813  {
814  global $tree, $ilDB, $ilPluginAdmin, $lng;
815 
816  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
817  $participantData = new ilTestParticipantData($ilDB, $lng);
818  $participantData->load($this->getTestId());
819  $this->removeTestResults($participantData);
820 
821  $affectedRows = $ilDB->manipulateF(
822  "DELETE FROM tst_mark WHERE test_fi = %s",
823  array('integer'),
824  array($this->getTestId())
825  );
826 
827  $affectedRows = $ilDB->manipulateF(
828  "DELETE FROM tst_tests WHERE test_id = %s",
829  array('integer'),
830  array($this->getTestId())
831  );
832 
833  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
834  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
835  $testQuestionSetConfigFactory->getQuestionSetConfig()->removeQuestionSetRelatedData();
836 
837  // delete export files
838  include_once "./Services/Utilities/classes/class.ilUtil.php";
839  $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
840  $directory = $tst_data_dir . "/tst_" . $this->getId();
841  if (is_dir($directory)) {
842  include_once "./Services/Utilities/classes/class.ilUtil.php";
843  ilUtil::delDir($directory);
844  }
845  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
846  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
847  // remaining usages are not in text anymore -> delete them
848  // and media objects (note: delete method of ilObjMediaObject
849  // checks whether object is used in another context; if yes,
850  // the object is not deleted!)
851  foreach ($mobs as $mob) {
852  ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
853  if (ilObjMediaObject::_exists($mob)) {
854  $mob_obj = new ilObjMediaObject($mob);
855  $mob_obj->delete();
856  }
857  }
858  }
859 
865  public function createExportDirectory()
866  {
867  include_once "./Services/Utilities/classes/class.ilUtil.php";
868  $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
869  ilUtil::makeDir($tst_data_dir);
870  if (!is_writable($tst_data_dir)) {
871  $this->ilias->raiseError("Test Data Directory (" . $tst_data_dir
872  . ") not writeable.", $this->ilias->error_obj->MESSAGE);
873  }
874 
875  // create learning module directory (data_dir/lm_data/lm_<id>)
876  $tst_dir = $tst_data_dir . "/tst_" . $this->getId();
877  ilUtil::makeDir($tst_dir);
878  if (!@is_dir($tst_dir)) {
879  $this->ilias->raiseError("Creation of Test Directory failed.", $this->ilias->error_obj->MESSAGE);
880  }
881  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
882  $export_dir = $tst_dir . "/export";
883  ilUtil::makeDir($export_dir);
884  if (!@is_dir($export_dir)) {
885  $this->ilias->raiseError("Creation of Export Directory failed.", $this->ilias->error_obj->MESSAGE);
886  }
887  }
888 
894  public function getExportDirectory()
895  {
896  include_once "./Services/Utilities/classes/class.ilUtil.php";
897  $export_dir = ilUtil::getDataDir() . "/tst_data" . "/tst_" . $this->getId() . "/export";
898  return $export_dir;
899  }
900 
907  public function getExportFiles($dir)
908  {
909  // quit if import dir not available
910  if (!@is_dir($dir) || !is_writeable($dir)) {
911  return array();
912  }
913 
914  $files = array();
915  foreach (new DirectoryIterator($dir) as $file) {
919  if ($file->isDir()) {
920  continue;
921  }
922 
923  $files[] = $file->getBasename();
924  }
925 
926  sort($files);
927 
928  return $files;
929  }
930 
934  public static function _setImportDirectory($a_import_dir = null)
935  {
936  if (strlen($a_import_dir)) {
937  $_SESSION["tst_import_dir"] = $a_import_dir;
938  } else {
939  unset($_SESSION["tst_import_dir"]);
940  }
941  }
942 
949  public static function _getImportDirectory()
950  {
951  if (strlen($_SESSION["tst_import_dir"])) {
952  return $_SESSION["tst_import_dir"];
953  }
954  return null;
955  }
956 
957  public function getImportDirectory()
958  {
960  }
961 
967  public static function _createImportDirectory()
968  {
969  global $ilias;
970  include_once "./Services/Utilities/classes/class.ilUtil.php";
971  $tst_data_dir = ilUtil::getDataDir() . "/tst_data";
972  ilUtil::makeDir($tst_data_dir);
973 
974  if (!is_writable($tst_data_dir)) {
975  $ilias->raiseError("Test Data Directory (" . $tst_data_dir
976  . ") not writeable.", $ilias->error_obj->FATAL);
977  }
978 
979  // create test directory (data_dir/tst_data/tst_import)
980  $tst_dir = $tst_data_dir . "/tst_import";
981  ilUtil::makeDir($tst_dir);
982  if (!@is_dir($tst_dir)) {
983  $ilias->raiseError("Creation of test import directory failed.", $ilias->error_obj->FATAL);
984  }
985 
986  // assert that this is empty and does not contain old data
987  ilUtil::delDir($tst_dir, true);
988 
989  return $tst_dir;
990  }
991 
998  public function hasSingleChoiceQuestions()
999  {
1000  global $ilDB;
1001 
1002  $result = $ilDB->queryF(
1003  "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",
1004  array('integer'),
1005  array($this->getTestId())
1006  );
1007  $hasSC = false;
1008  while ($row = $ilDB->fetchAssoc($result)) {
1009  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1010  $hasSC = true;
1011  }
1012  }
1013  return $hasSC;
1014  }
1015 
1022  public function isSingleChoiceTest()
1023  {
1024  global $ilDB;
1025 
1026  $result = $ilDB->queryF(
1027  "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",
1028  array('integer'),
1029  array($this->getTestId())
1030  );
1031  if ($result->numRows() == 1) {
1032  $row = $ilDB->fetchAssoc($result);
1033  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0) {
1034  return true;
1035  } else {
1036  return false;
1037  }
1038  }
1039  return false;
1040  }
1041 
1049  {
1050  global $ilDB;
1051 
1052  if (!$this->hasSingleChoiceQuestions()) {
1053  return false;
1054  }
1055 
1056  $result = $ilDB->queryF(
1057  "
1058  SELECT DISTINCT(qpl_qst_sc.shuffle) foundshuffles
1059  FROM qpl_questions,
1060  qpl_qst_sc,
1061  tst_test_result,
1062  qpl_qst_type,
1063  tst_active
1064  WHERE tst_test_result.question_fi = qpl_questions.question_id
1065  AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
1066  AND tst_test_result.active_fi = tst_active.active_id
1067  AND qpl_questions.question_id = qpl_qst_sc.question_fi
1068  AND tst_active.test_fi = %s
1069  AND qpl_qst_type.type_tag = %s
1070  ",
1071  array('integer', 'text'),
1072  array($this->getTestId(), 'assSingleChoice')
1073  );
1074  if ($result->numRows() == 1) {
1075  $row = $ilDB->fetchAssoc($result);
1076  return ($row['foundshuffles'] == 0);
1077  }
1078  return false;
1079  }
1080 
1087  final public function isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
1088  {
1089  if (!count($this->mark_schema->mark_steps)) {
1090  return false;
1091  }
1092 
1093  if (!$testQuestionSetConfig->isQuestionSetConfigured()) {
1094  return false;
1095  }
1096 
1097  return true;
1098  }
1099 
1106  public function _isComplete($obj_id)
1107  {
1108  global $tree, $ilDB, $ilPluginAdmin;
1109 
1110  $test = new ilObjTest($obj_id, false);
1111  $test->loadFromDb();
1112 
1113  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1114  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
1115 
1116  return $test->isComplete($testQuestionSetConfigFactory->getQuestionSetConfig());
1117  }
1118 
1122  public function saveECTSStatus()
1123  {
1127  global $ilDB;
1128 
1129  if ($this->getTestId() > 0) {
1130  $this->setECTSFX(preg_replace('/,/', '.', $this->getECTSFX()));
1131  if (!preg_match('/\d+/', $this->getECTSFX())) {
1132  $this->setECTSFX(null);
1133  }
1134 
1135  $grades = $this->getECTSGrades();
1136  $ilDB->manipulateF(
1137  "UPDATE tst_tests
1138  SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s
1139  WHERE test_id = %s",
1140  array('text', 'float', 'float', 'float', 'float', 'float', 'float', 'integer'),
1141  array(
1142  (int) $this->getECTSOutput(),
1143  $grades['A'], $grades['B'], $grades['C'], $grades['D'], $grades['E'],
1144  $this->getECTSFX(),
1145  $this->getTestId()
1146  )
1147  );
1148  }
1149  }
1150 
1155  public function saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
1156  {
1157  global $ilDB;
1158 
1159  $complete = 0;
1160  if ($this->isComplete($testQuestionSetConfig)) {
1161  $complete = 1;
1162  }
1163  if ($this->getTestId() > 0) {
1164  $ilDB->manipulateF(
1165  "UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1166  array('text', 'integer'),
1167  array($complete, $this->test_id)
1168  );
1169  }
1170  }
1171 
1177  public function getAllRTEContent()
1178  {
1179  $result = array();
1180  array_push($result, $this->getIntroduction());
1181  array_push($result, $this->getFinalStatement());
1182  return $result;
1183  }
1184 
1190  public function cleanupMediaobjectUsage()
1191  {
1192  include_once("./Services/RTE/classes/class.ilRTE.php");
1193  $completecontent = "";
1194  foreach ($this->getAllRTEContent() as $content) {
1195  $completecontent .= $content;
1196  }
1198  $completecontent,
1199  $this->getType() . ":html",
1200  $this->getId()
1201  );
1202  }
1203 
1209  public function saveToDb($properties_only = false)
1210  {
1211  global $tree, $ilDB, $ilPluginAdmin;
1212 
1213  // moved online_status to ilObjectActivation (see below)
1214 
1215  // cleanup RTE images
1216  $this->cleanupMediaobjectUsage();
1217 
1218  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1219  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
1220  $testQuestionSetConfig = $testQuestionSetConfigFactory->getQuestionSetConfig();
1221 
1222  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1223  if ($this->test_id == -1) {
1224  // Create new dataset
1225  $next_id = $ilDB->nextId('tst_tests');
1226 
1227  $ilDB->insert('tst_tests', array(
1228  'test_id' => array('integer', $next_id),
1229  'obj_fi' => array('integer', $this->getId()),
1230  'author' => array('text', $this->getAuthor()),
1231  'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1232  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1233  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1234  'showinfo' => array('integer', $this->getShowInfo()),
1235  'forcejs' => array('integer', $this->getForceJS()),
1236  'customstyle' => array('text', $this->getCustomStyle()),
1237  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1238  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1239  'score_reporting' => array('integer', $this->getScoreReporting()),
1240  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1241  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1242  'answer_feedback' => array('text', $this->getAnswerFeedback()),
1243  'anonymity' => array('text', $this->getAnonymity()),
1244  'show_cancel' => array('text', $this->getShowCancel()),
1245  'show_marker' => array('integer', $this->getShowMarker()),
1246  'fixed_participants' => array('text', $this->getFixedParticipants()),
1247  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1248  'kiosk' => array('integer', $this->getKiosk()),
1249  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1250  'title_output' => array('text', $this->getTitleOutput()),
1251  'processing_time' => array('text', $this->getProcessingTime()),
1252  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1253  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1254  'reporting_date' => array('text', $this->getReportingDate()),
1255  'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1256  'starting_time' => array('integer', $this->getStartingTime()),
1257  'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1258  'ending_time' => array('integer', $this->getEndingTime()),
1259  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1260  'ects_output' => array('text', $this->getECTSOutput()),
1261  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1262  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1263  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1264  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1265  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1266  'ects_fx' => array('float', $this->getECTSFX()),
1267  'count_system' => array('text', $this->getCountSystem()),
1268  'mc_scoring' => array('text', $this->getMCScoring()),
1269  'score_cutting' => array('text', $this->getScoreCutting()),
1270  'pass_scoring' => array('text', $this->getPassScoring()),
1271  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1272  'results_presentation' => array('integer', $this->getResultsPresentation()),
1273  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1274  'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1275  'password' => array('text', $this->getPassword()),
1276  'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1277  'allowedusers' => array('integer', $this->getAllowedUsers()),
1278  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1279  'mailnottype' => array('integer', $this->getMailNotificationType()),
1280  'exportsettings' => array('integer', $this->getExportSettings()),
1281  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1282  'mailnotification' => array('integer', $this->getMailNotification()),
1283  'created' => array('integer', time()),
1284  'tstamp' => array('integer', time()),
1285  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1286  'template_id' => array('integer', $this->getTemplate()),
1287  'pool_usage' => array('integer', $this->getPoolUsage()),
1288  'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1289  'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1290  'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1291  'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1292  'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1293  'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1294  'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1295  'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1296  'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1297  'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1298  'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1299  'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1300  'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1301  'online_status' => array('integer', (int) $this->isOnline()),
1302  'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1303  'autosave' => array('integer', (int) $this->getAutosave()),
1304  'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1305  'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1306  'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1307  'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1308  'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1309  'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1310  'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1311  'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1312  'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1313  'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1314  'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1315  'question_set_type' => array('text', $this->getQuestionSetType()),
1316  'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1317  'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1318  'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1319  'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1320  'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1321  'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1322  'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1323  'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1324  'broken' => array('integer', (int) $this->isTestFinalBroken()),
1325  'pass_waiting' => array('text', (string) $this->getPassWaiting())
1326  ));
1327 
1328  $this->test_id = $next_id;
1329 
1331  $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1332  }
1333  } else {
1334  // Modify existing dataset
1335  $oldrow = array();
1337  $result = $ilDB->queryF(
1338  "SELECT * FROM tst_tests WHERE test_id = %s",
1339  array('integer'),
1340  array($this->test_id)
1341  );
1342  if ($result->numRows() == 1) {
1343  $oldrow = $ilDB->fetchAssoc($result);
1344  }
1345  }
1346 
1347  $ilDB->update(
1348  'tst_tests',
1349  array(
1350  'author' => array('text', $this->getAuthor()),
1351  'intro_enabled' => array('integer', (int) $this->isIntroductionEnabled()),
1352  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1353  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1354  'showinfo' => array('integer', $this->getShowInfo()),
1355  'forcejs' => array('integer', $this->getForceJS()),
1356  'customstyle' => array('text', $this->getCustomStyle()),
1357  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1358  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1359  'score_reporting' => array('integer', $this->getScoreReporting()),
1360  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1361  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1362  'answer_feedback' => array('text', $this->getGenericAnswerFeedback()),
1363  'anonymity' => array('text', $this->getAnonymity()),
1364  'show_cancel' => array('text', $this->getShowCancel()),
1365  'show_marker' => array('integer', $this->getShowMarker()),
1366  'fixed_participants' => array('text', $this->getFixedParticipants()),
1367  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1368  'kiosk' => array('integer', $this->getKiosk()),
1369  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1370  'title_output' => array('text', $this->getTitleOutput()),
1371  'processing_time' => array('text', $this->getProcessingTime()),
1372  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1373  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1374  'reporting_date' => array('text', $this->getReportingDate()),
1375  'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1376  'starting_time' => array('integer', $this->getStartingTime()),
1377  'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1378  'ending_time' => array('integer', $this->getEndingTime()),
1379  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1380  'ects_output' => array('text', $this->getECTSOutput()),
1381  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : null),
1382  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : null),
1383  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : null),
1384  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : null),
1385  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : null),
1386  'ects_fx' => array('float', $this->getECTSFX()),
1387  'count_system' => array('text', $this->getCountSystem()),
1388  'mc_scoring' => array('text', $this->getMCScoring()),
1389  'score_cutting' => array('text', $this->getScoreCutting()),
1390  'pass_scoring' => array('text', $this->getPassScoring()),
1391  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1392  'results_presentation' => array('integer', $this->getResultsPresentation()),
1393  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1394  'password_enabled' => array('integer', (int) $this->isPasswordEnabled()),
1395  'password' => array('text', $this->getPassword()),
1396  'limit_users_enabled' => array('integer', (int) $this->isLimitUsersEnabled()),
1397  'allowedusers' => array('integer', $this->getAllowedUsers()),
1398  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1399  'mailnottype' => array('integer', $this->getMailNotificationType()),
1400  'exportsettings' => array('integer', $this->getExportSettings()),
1401  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1402  'mailnotification' => array('integer', $this->getMailNotification()),
1403  'tstamp' => array('integer', time()),
1404  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1405  'template_id' => array('integer', $this->getTemplate()),
1406  'pool_usage' => array('integer', $this->getPoolUsage()),
1407  'print_bs_with_res' => array('integer', (int) $this->isBestSolutionPrintedWithResult()),
1408  'obligations_enabled' => array('integer', (int) $this->areObligationsEnabled()),
1409  'offer_question_hints' => array('integer', (int) $this->isOfferingQuestionHintsEnabled()),
1410  'highscore_enabled' => array('integer', (int) $this->getHighscoreEnabled()),
1411  'highscore_anon' => array('integer', (int) $this->getHighscoreAnon()),
1412  'highscore_achieved_ts' => array('integer', (int) $this->getHighscoreAchievedTS()),
1413  'highscore_score' => array('integer', (int) $this->getHighscoreScore()),
1414  'highscore_percentage' => array('integer', (int) $this->getHighscorePercentage()),
1415  'highscore_hints' => array('integer', (int) $this->getHighscoreHints()),
1416  'highscore_wtime' => array('integer', (int) $this->getHighscoreWTime()),
1417  'highscore_own_table' => array('integer', (int) $this->getHighscoreOwnTable()),
1418  'highscore_top_table' => array('integer', (int) $this->getHighscoreTopTable()),
1419  'highscore_top_num' => array('integer', (int) $this->getHighscoreTopNum()),
1420  'online_status' => array('integer', (int) $this->isOnline()),
1421  'specific_feedback' => array('integer', (int) $this->getSpecificAnswerFeedback()),
1422  'autosave' => array('integer', (int) $this->getAutosave()),
1423  'autosave_ival' => array('integer', (int) $this->getAutosaveIval()),
1424  'pass_deletion_allowed' => array('integer', (int) $this->isPassDeletionAllowed()),
1425  'enable_examview' => array('integer', (int) $this->getEnableExamview()),
1426  'show_examview_html' => array('integer', (int) $this->getShowExamviewHtml()),
1427  'show_examview_pdf' => array('integer', (int) $this->getShowExamviewPdf()),
1428  'redirection_mode' => array('integer', (int) $this->getRedirectionMode()),
1429  'redirection_url' => array('text', (string) $this->getRedirectionUrl()),
1430  'enable_archiving' => array('integer', (int) $this->getEnableArchiving()),
1431  'examid_in_test_pass' => array('integer', (int) $this->isShowExamIdInTestPassEnabled()),
1432  'examid_in_test_res' => array('integer', (int) $this->isShowExamIdInTestResultsEnabled()),
1433  'sign_submission' => array('integer', (int) $this->getSignSubmission()),
1434  'question_set_type' => array('text', $this->getQuestionSetType()),
1435  'char_selector_availability' => array('integer', (int) $this->getCharSelectorAvailability()),
1436  'char_selector_definition' => array('text', (string) $this->getCharSelectorDefinition()),
1437  'skill_service' => array('integer', (int) $this->isSkillServiceEnabled()),
1438  'result_tax_filters' => array('text', serialize((array) $this->getResultFilterTaxIds())),
1439  'show_grading_status' => array('integer', (int) $this->isShowGradingStatusEnabled()),
1440  'show_grading_mark' => array('integer', (int) $this->isShowGradingMarkEnabled()),
1441  'inst_fb_answer_fixation' => array('integer', (int) $this->isInstantFeedbackAnswerFixationEnabled()),
1442  'force_inst_fb' => array('integer', (int) $this->isForceInstantFeedbackEnabled()),
1443  'broken' => array('integer', (int) $this->isTestFinalBroken()),
1444  'pass_waiting' => array('text', (string) $this->getPassWaiting())
1445  ),
1446  array(
1447  'test_id' => array('integer', (int) $this->getTestId())
1448  )
1449  );
1450 
1451  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1453  $logresult = $ilDB->queryF(
1454  "SELECT * FROM tst_tests WHERE test_id = %s",
1455  array('integer'),
1456  array($this->getTestId())
1457  );
1458  $newrow = array();
1459  if ($logresult->numRows() == 1) {
1460  $newrow = $ilDB->fetchAssoc($logresult);
1461  }
1462  $changed_fields = array();
1463  foreach ($oldrow as $key => $value) {
1464  if (strcmp($oldrow[$key], $newrow[$key]) != 0) {
1465  array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1466  }
1467  }
1468  $changes = join($changed_fields, ", ");
1469  if (count($changed_fields) > 0) {
1470  $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [" . $changes . "]");
1471  }
1472  }
1473  if ($this->evalTotalPersons() > 0) {
1474  // reset the finished status of participants if the nr of test passes did change
1475  if ($this->getNrOfTries() > 0) {
1476  // set all unfinished tests with nr of passes >= allowed passes finished
1477  $aresult = $ilDB->queryF(
1478  "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
1479  array('integer', 'integer', 'integer'),
1480  array($this->getTestId(), $this->getNrOfTries(), 0)
1481  );
1482  while ($row = $ilDB->fetchAssoc($aresult)) {
1483  $ilDB->manipulateF(
1484  "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1485  array('integer', 'timestamp', 'integer'),
1486  array(1, date('Y-m-d H:i:s'), $row["active_id"])
1487  );
1488  }
1489 
1490  // set all finished tests with nr of passes < allowed passes not finished
1491  $aresult = $ilDB->queryF(
1492  "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
1493  array('integer', 'integer', 'integer'),
1494  array($this->getTestId(), $this->getNrOfTries()-1, 1)
1495  );
1496  while ($row = $ilDB->fetchAssoc($aresult)) {
1497  $ilDB->manipulateF(
1498  "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1499  array('integer', 'timestamp', 'integer'),
1500  array(0, null, $row["active_id"])
1501  );
1502  }
1503  } else {
1504  // set all finished tests with nr of passes >= allowed passes not finished
1505  $aresult = $ilDB->queryF(
1506  "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
1507  array('integer', 'integer'),
1508  array($this->getTestId(), 1)
1509  );
1510  while ($row = $ilDB->fetchAssoc($aresult)) {
1511  $ilDB->manipulateF(
1512  "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1513  array('integer', 'timestamp', 'integer'),
1514  array(0, null, $row["active_id"])
1515  );
1516  }
1517  }
1518  }
1519  }
1520 
1521  // news item creation/update/deletion
1522  include_once 'Services/News/classes/class.ilNewsItem.php';
1523  if (!$this->getOldOnlineStatus() && $this->isOnline()) {
1524  global $ilUser;
1525  $newsItem = new ilNewsItem();
1526  $newsItem->setContext($this->getId(), 'tst');
1527  $newsItem->setPriority(NEWS_NOTICE);
1528  $newsItem->setTitle('new_test_online');
1529  $newsItem->setContentIsLangVar(true);
1530  $newsItem->setContent('');
1531  $newsItem->setUserId($ilUser->getId());
1532  $newsItem->setVisibility(NEWS_USERS);
1533  $newsItem->create();
1534  } elseif ($this->getOldOnlineStatus() && !$this->isOnline()) {
1535  ilNewsItem::deleteNewsOfContext($this->getId(), 'tst');
1536  } elseif ($this->isOnline()) {
1537  $newsId = ilNewsItem::getFirstNewsIdForContext($this->getId(), 'tst');
1538  if ($newsId > 0) {
1539  $newsItem = new ilNewsItem($newsId);
1540  $newsItem->setTitle('new_test_online');
1541  $newsItem->setContentIsLangVar(true);
1542  $newsItem->setContent('');
1543  $newsItem->update();
1544  }
1545  }
1546 
1547  // moved activation to ilObjectActivation
1548  if ($this->ref_id) {
1549  include_once "./Services/Object/classes/class.ilObjectActivation.php";
1550  ilObjectActivation::getItem($this->ref_id);
1551 
1552  $item = new ilObjectActivation;
1553  if (!$this->isActivationLimited()) {
1555  } else {
1556  $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
1557  $item->setTimingStart($this->getActivationStartingTime());
1558  $item->setTimingEnd($this->getActivationEndingTime());
1559  $item->toggleVisible($this->getActivationVisibility());
1560  }
1561 
1562  $item->update($this->ref_id);
1563  }
1564 
1565  if (!$properties_only) {
1566  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
1567  $this->saveQuestionsToDb();
1568  }
1569 
1570  $this->mark_schema->saveToDb($this->test_id);
1571  }
1572  }
1573 
1580  public function saveQuestionsToDb()
1581  {
1582  global $ilDB;
1583 
1584  $oldquestions = array();
1585  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1587  $result = $ilDB->queryF(
1588  "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1589  array('integer'),
1590  array($this->getTestId())
1591  );
1592  if ($result->numRows() > 0) {
1593  while ($row = $ilDB->fetchAssoc($result)) {
1594  array_push($oldquestions, $row["question_fi"]);
1595  }
1596  }
1597  }
1598  // workaround for lost obligations
1599  // this method is called if a question is removed
1600  $currentQuestionsObligationsQuery = 'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
1601  $rset = $ilDB->queryF($currentQuestionsObligationsQuery, array('integer'), array($this->getTestId()));
1602  while ($row = $ilDB->fetchAssoc($rset)) {
1603  $obligatoryQuestionState[$row['question_fi']] = $row['obligatory'];
1604  }
1605  // delete existing category relations
1606  $affectedRows = $ilDB->manipulateF(
1607  "DELETE FROM tst_test_question WHERE test_fi = %s",
1608  array('integer'),
1609  array($this->getTestId())
1610  );
1611  // create new category relations
1612  foreach ($this->questions as $key => $value) {
1613  // workaround for import witout obligations information
1614  if (!isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value])) {
1615  $obligatoryQuestionState[$value] = 0;
1616  }
1617 
1618  // insert question
1619  $next_id = $ilDB->nextId('tst_test_question');
1620  $ilDB->insert('tst_test_question', array(
1621  'test_question_id' => array('integer', $next_id),
1622  'test_fi' => array('integer', $this->getTestId()),
1623  'question_fi' => array('integer', $value),
1624  'sequence' => array('integer', $key),
1625  'obligatory' => array('integer', $obligatoryQuestionState[$value]),
1626  'tstamp' => array('integer', time())
1627  ));
1628  }
1629  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1631  $result = $ilDB->queryF(
1632  "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1633  array('integer'),
1634  array($this->getTestId())
1635  );
1636  $newquestions = array();
1637  if ($result->numRows() > 0) {
1638  while ($row = $ilDB->fetchAssoc($result)) {
1639  array_push($newquestions, $row["question_fi"]);
1640  }
1641  }
1642  foreach ($oldquestions as $index => $question_id) {
1643  if (strcmp($newquestions[$index], $question_id) != 0) {
1644  $pos = array_search($question_id, $newquestions);
1645  if ($pos === false) {
1646  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1647  } else {
1648  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1) . " => " . ($pos+1), $question_id);
1649  }
1650  }
1651  }
1652  foreach ($newquestions as $index => $question_id) {
1653  if (array_search($question_id, $oldquestions) === false) {
1654  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1), $question_id);
1655  }
1656  }
1657  }
1658  }
1659 
1665  protected function isNewRandomTest()
1666  {
1667  global $ilDB;
1668  $result = $ilDB->queryF(
1669  'SELECT copy_id FROM tst_rnd_cpy WHERE tst_fi = %s',
1670  array('integer'),
1671  array($this->getTestId())
1672  );
1673  return $result->numRows() > 0;
1674  }
1675 
1688  public function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = null)
1689  {
1690  global $rbacsystem;
1691  global $ilDB;
1692 
1693  // retrieve object id instead of ref id if necessary
1694  if (($questionpool != 0) && (!$use_obj_id)) {
1695  $questionpool = ilObject::_lookupObjId($questionpool);
1696  }
1697 
1698  // get original ids of all existing questions in the test
1699  $result = $ilDB->queryF(
1700  "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",
1701  array("integer"),
1702  array($this->getTestId())
1703  );
1704  $original_ids = array();
1705  $paramtypes = array();
1706  $paramvalues = array();
1707  while ($row = $ilDB->fetchAssoc($result)) {
1708  array_push($original_ids, $row['original_id']);
1709  }
1710 
1711  $available = "";
1712  // get a list of all available questionpools
1713  if (($questionpool == 0) && (!is_array($qpls))) {
1714  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1715  $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())));
1716  if (count($available_pools)) {
1717  $available = " AND " . $ilDB->in('obj_fi', $available_pools, false, 'integer');
1718  } else {
1719  return array();
1720  }
1721  }
1722 
1723  $constraint_qpls = "";
1724  $result_array = array();
1725  if ($questionpool == 0) {
1726  if (is_array($qpls)) {
1727  if (count($qpls) > 0) {
1728  $constraint_qpls = " AND " . $ilDB->in('obj_fi', $qpls, false, 'integer');
1729  }
1730  }
1731  }
1732 
1733  $original_clause = "";
1734  if (count($original_ids)) {
1735  $original_clause = " AND " . $ilDB->in('question_id', $original_ids, true, 'integer');
1736  }
1737 
1738  if ($questionpool == 0) {
1739  $result = $ilDB->queryF(
1740  "SELECT question_id FROM qpl_questions WHERE original_id IS NULL $available $constraint_qpls AND owner > %s AND complete = %s $original_clause",
1741  array('integer', 'text'),
1742  array(0, "1")
1743  );
1744  } else {
1745  $result = $ilDB->queryF(
1746  "SELECT question_id FROM qpl_questions WHERE original_id IS NULL AND obj_fi = %s AND owner > %s AND complete = %s $original_clause",
1747  array('integer','integer', 'text'),
1748  array($questionpool, 0, "1")
1749  );
1750  }
1751  $found_ids = array();
1752  while ($row = $ilDB->fetchAssoc($result)) {
1753  array_push($found_ids, $row['question_id']);
1754  }
1755  $nr_of_questions = ($nr_of_questions > count($found_ids)) ? count($found_ids) : $nr_of_questions;
1756  if ($nr_of_questions == 0) {
1757  return array();
1758  }
1759  $rand_keys = array_rand($found_ids, $nr_of_questions);
1760  $result = array();
1761  if (is_array($rand_keys)) {
1762  foreach ($rand_keys as $key) {
1763  $result[$found_ids[$key]] = $found_ids[$key];
1764  }
1765  } else {
1766  $result[$found_ids[$rand_keys]] = $found_ids[$rand_keys];
1767  }
1768  return $result;
1769  }
1770 
1778  public function getNrOfResultsForPass($active_id, $pass)
1779  {
1780  global $ilDB;
1781 
1782  $result = $ilDB->queryF(
1783  "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1784  array('integer','integer'),
1785  array($active_id, $pass)
1786  );
1787  return $result->numRows();
1788  }
1789 
1800  public function hasRandomQuestionsForPass($active_id, $pass)
1801  {
1802  global $ilDB;
1803  $result = $ilDB->queryF(
1804  "SELECT test_random_question_id FROM tst_test_rnd_qst WHERE active_fi = %s AND pass = %s",
1805  array('integer','integer'),
1806  array($active_id, $pass)
1807  );
1808  return ($result->numRows() > 0) ? true : false;
1809  }
1810 
1814  public function loadFromDb()
1815  {
1816  global $ilDB;
1817 
1818  $result = $ilDB->queryF(
1819  "SELECT * FROM tst_tests WHERE obj_fi = %s",
1820  array('integer'),
1821  array($this->getId())
1822  );
1823  if ($result->numRows() == 1) {
1824  $data = $ilDB->fetchObject($result);
1825  $this->setTestId($data->test_id);
1826  if (strlen($this->getAuthor()) == 0) {
1827  $this->saveAuthorToMetadata($data->author);
1828  }
1829  $this->setAuthor($data->author);
1830  include_once("./Services/RTE/classes/class.ilRTE.php");
1831  $this->setIntroductionEnabled($data->intro_enabled);
1832  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc($data->introduction, 1));
1833  $this->setShowInfo($data->showinfo);
1834  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc($data->finalstatement, 1));
1835  $this->setForceJS($data->forcejs);
1836  $this->setCustomStyle($data->customstyle);
1837  $this->setShowFinalStatement($data->showfinalstatement);
1838  $this->setSequenceSettings($data->sequence_settings);
1839  $this->setScoreReporting($data->score_reporting);
1840  $this->setInstantFeedbackSolution($data->instant_verification);
1841  $this->setAnswerFeedbackPoints($data->answer_feedback_points);
1842  $this->setAnswerFeedback($data->answer_feedback);
1843  $this->setAnonymity($data->anonymity);
1844  $this->setShowCancel($data->show_cancel);
1845  $this->setShowMarker($data->show_marker);
1846  $this->setFixedParticipants($data->fixed_participants);
1847  $this->setNrOfTries($data->nr_of_tries);
1848  $this->setKiosk($data->kiosk);
1849  $this->setUsePreviousAnswers($data->use_previous_answers);
1850  $this->setRedirectionMode($data->redirection_mode);
1851  $this->setRedirectionUrl($data->redirection_url);
1852  $this->setTitleOutput($data->title_output);
1853  $this->setProcessingTime($data->processing_time);
1854  $this->setEnableProcessingTime($data->enable_processing_time);
1855  $this->setResetProcessingTime($data->reset_processing_time);
1856  $this->setReportingDate($data->reporting_date);
1857  $this->setShuffleQuestions($data->shuffle_questions);
1858  $this->setResultsPresentation($data->results_presentation);
1859  $this->setStartingTimeEnabled($data->starting_time_enabled);
1860  $this->setStartingTime($data->starting_time);
1861  $this->setEndingTimeEnabled($data->ending_time_enabled);
1862  $this->setEndingTime($data->ending_time);
1863  $this->setListOfQuestionsSettings($data->show_summary);
1864  $this->setECTSOutput($data->ects_output);
1865  $this->setECTSGrades(
1866  array(
1867  "A" => $data->ects_a,
1868  "B" => $data->ects_b,
1869  "C" => $data->ects_c,
1870  "D" => $data->ects_d,
1871  "E" => $data->ects_e
1872  )
1873  );
1874  $this->setECTSFX($data->ects_fx);
1875  $this->mark_schema->flush();
1876  $this->mark_schema->loadFromDb($this->getTestId());
1877  $this->setCountSystem($data->count_system);
1878  $this->setMCScoring($data->mc_scoring);
1879  $this->setMailNotification($data->mailnotification);
1880  $this->setMailNotificationType($data->mailnottype);
1881  $this->setExportSettings($data->exportsettings);
1882  $this->setScoreCutting($data->score_cutting);
1883  $this->setPasswordEnabled($data->password_enabled);
1884  $this->setPassword($data->password);
1885  $this->setLimitUsersEnabled($data->limit_users_enabled);
1886  $this->setAllowedUsers($data->allowedusers);
1887  $this->setAllowedUsersTimeGap($data->alloweduserstimegap);
1888  $this->setPassScoring($data->pass_scoring);
1889  $this->setObligationsEnabled($data->obligations_enabled);
1890  $this->setOfferingQuestionHintsEnabled($data->offer_question_hints);
1891  $this->setCertificateVisibility($data->certificate_visibility);
1892  $this->setEnabledViewMode($data->enabled_view_mode);
1893  $this->setTemplate($data->template_id);
1894  $this->setPoolUsage($data->pool_usage);
1895  $this->setPrintBestSolutionWithResult((bool) $data->print_bs_with_res);
1896  $this->setHighscoreEnabled((bool) $data->highscore_enabled);
1897  $this->setHighscoreAnon((bool) $data->highscore_anon);
1898  $this->setHighscoreAchievedTS((bool) $data->highscore_achieved_ts);
1899  $this->setHighscoreScore((bool) $data->highscore_score);
1900  $this->setHighscorePercentage((bool) $data->highscore_percentage);
1901  $this->setHighscoreHints((bool) $data->highscore_hints);
1902  $this->setHighscoreWTime((bool) $data->highscore_wtime);
1903  $this->setHighscoreOwnTable((bool) $data->highscore_own_table);
1904  $this->setHighscoreTopTable((bool) $data->highscore_top_table);
1905  $this->setHighscoreTopNum((int) $data->highscore_top_num);
1906  $this->setOnline((bool) $data->online_status);
1907  $this->setOldOnlineStatus((bool) $data->online_status);
1908  $this->setSpecificAnswerFeedback((int) $data->specific_feedback);
1909  $this->setAutosave((bool) $data->autosave);
1910  $this->setAutosaveIval((int) $data->autosave_ival);
1911  $this->setPassDeletionAllowed($data->pass_deletion_allowed);
1912  $this->setEnableExamview((bool) $data->enable_examview);
1913  $this->setShowExamviewHtml((bool) $data->show_examview_html);
1914  $this->setShowExamviewPdf((bool) $data->show_examview_pdf);
1915  $this->setEnableArchiving((bool) $data->enable_archiving);
1916  $this->setShowExamIdInTestPassEnabled((bool) $data->examid_in_test_pass);
1917  $this->setShowExamIdInTestResultsEnabled((bool) $data->examid_in_test_res);
1918  $this->setSignSubmission((bool) $data->sign_submission);
1919  $this->setQuestionSetType($data->question_set_type);
1920  $this->setCharSelectorAvailability((int) $data->char_selector_availability);
1921  $this->setCharSelectorDefinition($data->char_selector_definition);
1922  $this->setSkillServiceEnabled((bool) $data->skill_service);
1923  $this->setResultFilterTaxIds(strlen($data->result_tax_filters) ? unserialize($data->result_tax_filters) : array());
1924  $this->setShowGradingStatusEnabled((bool) $data->show_grading_status);
1925  $this->setShowGradingMarkEnabled((bool) $data->show_grading_mark);
1926  $this->setInstantFeedbackAnswerFixationEnabled((bool) $data->inst_fb_answer_fixation);
1927  $this->setForceInstantFeedbackEnabled((bool) $data->force_inst_fb);
1928  $this->setTestFinalBroken((bool) $data->broken);
1929  $this->setPassWaiting($data->pass_waiting);
1930  $this->loadQuestions();
1931  }
1932 
1933  // moved activation to ilObjectActivation
1934  if ($this->ref_id) {
1935  include_once "./Services/Object/classes/class.ilObjectActivation.php";
1936  $activation = ilObjectActivation::getItem($this->ref_id);
1937  switch ($activation["timing_type"]) {
1939  $this->setActivationLimited(true);
1940  $this->setActivationStartingTime($activation["timing_start"]);
1941  $this->setActivationEndingTime($activation["timing_end"]);
1942  $this->setActivationVisibility($activation["visible"]);
1943  break;
1944 
1945  default:
1946  $this->setActivationLimited(false);
1947  break;
1948  }
1949  }
1950  }
1951 
1958  public function loadQuestions($active_id = "", $pass = null)
1959  {
1960  global $ilUser;
1961  global $ilDB;
1962 
1963  $this->questions = array();
1964  if ($this->isRandomTest()) {
1965  if (strcmp($active_id, "") == 0) {
1966  $active_id = $this->getActiveIdOfUser($ilUser->getId());
1967  }
1968  if (is_null($pass)) {
1969  $pass = self::_getPass($active_id);
1970  }
1971  $result = $ilDB->queryF(
1972  "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",
1973  array('integer', 'integer'),
1974  array($active_id, $pass)
1975  );
1976  // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
1977  // is only one test pass (pass = 0) in tst_test_rnd_qst while with ILIAS 3.8 there are questions for every test pass.
1978  // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
1979  // no questions are present for a newer pass.
1980  if ($result->numRows() == 0) {
1981  $result = $ilDB->queryF(
1982  "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",
1983  array('integer'),
1984  array($active_id)
1985  );
1986  }
1987  } else {
1988  $result = $ilDB->queryF(
1989  "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",
1990  array('integer'),
1991  array($this->test_id)
1992  );
1993  }
1994  $index = 1;
1995  while ($data = $ilDB->fetchAssoc($result)) {
1996  $this->questions[$index++] = $data["question_fi"];
1997  }
1998  }
1999 
2003  public function isIntroductionEnabled()
2004  {
2006  }
2007 
2012  {
2013  $this->introductionEnabled = $introductionEnabled;
2014  }
2015 
2022  public function getIntroduction()
2023  {
2024  return (strlen($this->introduction)) ? $this->introduction : null;
2025  }
2026 
2034  public function setIntroduction($introduction = "")
2035  {
2036  $this->introduction = $introduction;
2037  }
2038 
2039 
2047  public function setFinalStatement($a_statement = "")
2048  {
2049  $this->_finalstatement = $a_statement;
2050  }
2051 
2059  public function setShowInfo($a_info = 1)
2060  {
2061  $this->_showinfo = ($a_info) ? 1 : 0;
2062  }
2063 
2071  public function setForceJS($a_js = 1)
2072  {
2073  $this->_forcejs = ($a_js) ? 1 : 0;
2074  }
2075 
2083  public function setCustomStyle($a_customStyle = null)
2084  {
2085  $this->_customStyle = $a_customStyle;
2086  }
2087 
2095  public function getCustomStyle()
2096  {
2097  return (strlen($this->_customStyle)) ? $this->_customStyle : null;
2098  }
2099 
2107  public function getCustomStyles()
2108  {
2109  $css_path = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2110  $css_path = str_replace("ta.css", "customstyles", $css_path) . "/";
2111  $customstyles = array();
2112  if (is_dir($css_path)) {
2113  $results = array();
2114  include_once "./Services/Utilities/classes/class.ilFileUtils.php";
2116  if (is_array($results["file"])) {
2117  foreach ($results["file"] as $filename) {
2118  if (strpos($filename, ".css")) {
2119  array_push($customstyles, $filename);
2120  }
2121  }
2122  }
2123  }
2124  return $customstyles;
2125  }
2126 
2134  public function getTestStyleLocation($mode = "output")
2135  {
2136  if (strlen($this->getCustomStyle())) {
2137  $default = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2138  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $default);
2139  if (file_exists($custom)) {
2140  $custom = ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2141  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $custom);
2142  return $custom;
2143  } else {
2144  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2145  }
2146  } else {
2147  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2148  }
2149  }
2150 
2158  public function setShowFinalStatement($show = 0)
2159  {
2160  $this->_showfinalstatement = ($show) ? 1 : 0;
2161  }
2162 
2169  public function getFinalStatement()
2170  {
2171  return (strlen($this->_finalstatement)) ? $this->_finalstatement : null;
2172  }
2173 
2181  public function getShowInfo()
2182  {
2183  return ($this->_showinfo) ? 1 : 0;
2184  }
2185 
2193  public function getForceJS()
2194  {
2195  return ($this->_forcejs) ? 1 : 0;
2196  }
2197 
2205  public function getShowFinalStatement()
2206  {
2207  return ($this->_showfinalstatement) ? 1 : 0;
2208  }
2209 
2217  public function getTestId()
2218  {
2219  return $this->test_id;
2220  }
2221 
2225  public function getECTSOutput()
2226  {
2227  return ($this->ects_output) ? 1 : 0;
2228  }
2229 
2233  public function setECTSOutput($a_ects_output)
2234  {
2235  $this->ects_output = $a_ects_output ? 1 : 0;
2236  }
2237 
2241  public function getECTSFX()
2242  {
2243  return (strlen($this->ects_fx)) ? $this->ects_fx : null;
2244  }
2245 
2249  public function setECTSFX($a_ects_fx)
2250  {
2251  $this->ects_fx = $a_ects_fx;
2252  }
2253 
2257  public function getECTSGrades()
2258  {
2259  return $this->ects_grades;
2260  }
2261 
2265  public function setECTSGrades(array $a_ects_grades)
2266  {
2267  $this->ects_grades = $a_ects_grades;
2268  }
2269 
2275  public function getSequenceSettings()
2276  {
2277  return ($this->sequence_settings) ? $this->sequence_settings : 0;
2278  }
2279 
2286  {
2287  $this->sequence_settings = $sequence_settings;
2288  }
2289 
2293  public function isPostponingEnabled()
2294  {
2295  return (bool) $this->getSequenceSettings();
2296  }
2297 
2301  public function setPostponingEnabled($postponingEnabled)
2302  {
2303  $this->setSequenceSettings((int) $postponingEnabled);
2304  }
2305 
2314  {
2315  $this->score_reporting = $score_reporting;
2316  }
2317 
2325  public function setInstantFeedbackSolution($instant_feedback = 0)
2326  {
2327  switch ($instant_feedback) {
2328  case 1:
2329  $this->instant_verification = 1;
2330  break;
2331  default:
2332  $this->instant_verification = 0;
2333  break;
2334  }
2335  }
2336 
2345  {
2346  switch ($answer_feedback) {
2347  case 1:
2348  $this->answer_feedback = 1;
2349  break;
2350  default:
2351  $this->answer_feedback = 0;
2352  break;
2353  }
2354  }
2355 
2361  public function setGenericAnswerFeedback($generic_answer_feedback = 0)
2362  {
2363  switch ($generic_answer_feedback) {
2364  case 1:
2365  $this->answer_feedback = 1;
2366  break;
2367  default:
2368  $this->answer_feedback = 0;
2369  break;
2370  }
2371  }
2372 
2381  {
2382  switch ($answer_feedback_points) {
2383  case 1:
2384  $this->answer_feedback_points = 1;
2385  break;
2386  default:
2387  $this->answer_feedback_points = 0;
2388  break;
2389  }
2390  }
2391 
2397  {
2398  if (!$reporting_date) {
2399  $this->reporting_date = '';
2400  $this->setECTSOutput(false);
2401  } else {
2402  $this->reporting_date = $reporting_date;
2403  }
2404  }
2405 
2410 
2418  public function getScoreReporting()
2419  {
2420  return ($this->score_reporting) ? $this->score_reporting : 0;
2421  }
2422 
2423  public function isScoreReportingEnabled()
2424  {
2425  return $this->getScoreReporting() > 0 && $this->getScoreReporting() < 4;
2426  }
2427 
2435  public function getInstantFeedbackSolution()
2436  {
2437  return ($this->instant_verification) ? $this->instant_verification : 0;
2438  }
2439 
2448  public function getAnswerFeedback()
2449  {
2450  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2451  }
2452 
2459  public function getGenericAnswerFeedback()
2460  {
2461  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2462  }
2463 
2471  public function getAnswerFeedbackPoints()
2472  {
2473  return ($this->answer_feedback_points) ? $this->answer_feedback_points : 0;
2474  }
2475 
2483  public function getCountSystem()
2484  {
2485  return ($this->count_system) ? $this->count_system : 0;
2486  }
2487 
2495  public static function _getCountSystem($active_id)
2496  {
2497  global $ilDB;
2498  $result = $ilDB->queryF(
2499  "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",
2500  array('integer'),
2501  array($active_id)
2502  );
2503  if ($result->numRows()) {
2504  $row = $ilDB->fetchAssoc($result);
2505  return $row["count_system"];
2506  }
2507  return false;
2508  }
2509 
2517  public function getMCScoring()
2518  {
2519  return ($this->mc_scoring) ? $this->mc_scoring : 0;
2520  }
2521 
2529  public function getScoreCutting()
2530  {
2531  return ($this->score_cutting) ? $this->score_cutting : 0;
2532  }
2533 
2541  public function getPassScoring()
2542  {
2543  return ($this->pass_scoring) ? $this->pass_scoring : 0;
2544  }
2545 
2553  public static function _getPassScoring($active_id)
2554  {
2555  global $ilDB;
2556  $result = $ilDB->queryF(
2557  "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",
2558  array('integer'),
2559  array($active_id)
2560  );
2561  if ($result->numRows()) {
2562  $row = $ilDB->fetchAssoc($result);
2563  return $row["pass_scoring"];
2564  }
2565  return 0;
2566  }
2567 
2575  public static function _getMCScoring($active_id)
2576  {
2577  global $ilDB;
2578  $result = $ilDB->queryF(
2579  "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",
2580  array('integer'),
2581  array($active_id)
2582  );
2583  if ($result->numRows()) {
2584  $row = $ilDB->fetchAssoc($result);
2585  return $row["mc_scoring"];
2586  }
2587  return false;
2588  }
2589 
2597  public static function _getScoreCutting($active_id)
2598  {
2599  global $ilDB;
2600  $result = $ilDB->queryF(
2601  "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",
2602  array('integer'),
2603  array($active_id)
2604  );
2605  if ($result->numRows()) {
2606  $row = $ilDB->fetchAssoc($result);
2607  return $row["score_cutting"];
2608  }
2609  return false;
2610  }
2611 
2619  public function getReportingDate()
2620  {
2621  return (strlen($this->reporting_date)) ? $this->reporting_date : null;
2622  }
2623 
2631  public function getNrOfTries()
2632  {
2633  return ($this->nr_of_tries) ? $this->nr_of_tries : 0;
2634  }
2635 
2643  public function getKiosk()
2644  {
2645  return ($this->_kiosk) ? $this->_kiosk : 0;
2646  }
2647 
2648 
2656  public function setKiosk($kiosk = 0)
2657  {
2658  $this->_kiosk = $kiosk;
2659  }
2660 
2668  public function getKioskMode()
2669  {
2670  if (($this->_kiosk & 1) > 0) {
2671  return true;
2672  } else {
2673  return false;
2674  }
2675  }
2676 
2684  public function setKioskMode($a_kiosk = false)
2685  {
2686  if ($a_kiosk) {
2687  $this->_kiosk = $this->_kiosk | 1;
2688  } else {
2689  if ($this->getKioskMode()) {
2690  $this->_kiosk = $this->_kiosk ^ 1;
2691  }
2692  }
2693  }
2694 
2702  public function getShowKioskModeTitle()
2703  {
2704  if (($this->_kiosk & 2) > 0) {
2705  return true;
2706  } else {
2707  return false;
2708  }
2709  }
2710 
2717  public function setShowKioskModeTitle($a_title = false)
2718  {
2719  if ($a_title) {
2720  $this->_kiosk = $this->_kiosk | 2;
2721  } else {
2722  if ($this->getShowKioskModeTitle()) {
2723  $this->_kiosk = $this->_kiosk ^ 2;
2724  }
2725  }
2726  }
2727 
2736  {
2737  if (($this->_kiosk & 4) > 0) {
2738  return true;
2739  } else {
2740  return false;
2741  }
2742  }
2743 
2750  public function setShowKioskModeParticipant($a_participant = false)
2751  {
2752  if ($a_participant) {
2753  $this->_kiosk = $this->_kiosk | 4;
2754  } else {
2755  if ($this->getShowKioskModeParticipant()) {
2756  $this->_kiosk = $this->_kiosk ^ 4;
2757  }
2758  }
2759  }
2760 
2768  public function getUsePreviousAnswers()
2769  {
2770  return ($this->use_previous_answers) ? $this->use_previous_answers : 0;
2771  }
2772 
2780  public function getTitleOutput()
2781  {
2782  return ($this->title_output) ? $this->title_output : 0;
2783  }
2784 
2793  public function _getTitleOutput($active_id)
2794  {
2795  global $ilDB;
2796 
2797  $result = $ilDB->queryF(
2798  "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",
2799  array('integer'),
2800  array($active_id)
2801  );
2802  if ($result->numRows()) {
2803  $row = $ilDB->fetchAssoc($result);
2804  return $row["title_output"];
2805  }
2806  return 0;
2807  }
2808 
2809  // hey: prevPassSolutions - serious (nonstatic) identifier, for use in high level controller gui
2810  public function isPreviousSolutionReuseEnabled($activeId)
2811  {
2812  // checks if allowed in general and if enabled by participant
2813  return self::_getUsePreviousAnswers($activeId, true);
2814  }
2815  // hey.
2816 
2826  public static function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
2827  {
2828  global $ilDB;
2829  global $ilUser;
2830 
2832 
2833  $result = $ilDB->queryF(
2834  "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",
2835  array("integer"),
2836  array($active_id)
2837  );
2838  if ($result->numRows()) {
2839  $row = $ilDB->fetchAssoc($result);
2840  $use_previous_answers = $row["use_previous_answers"];
2841  }
2842 
2843  if ($use_previous_answers == 1) {
2844  if ($user_active_user_setting) {
2845  $res = $ilUser->getPref("tst_use_previous_answers");
2846  if ($res !== false) {
2848  }
2849  }
2850  }
2851  return $use_previous_answers;
2852  }
2853 
2861  public function getProcessingTime()
2862  {
2863  return (strlen($this->processing_time)) ? $this->processing_time : null;
2864  }
2865 
2872  public function getProcessingTimeAsArray()
2873  {
2874  if (strlen($this->processing_time)) {
2875  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2876  if ((int) $matches[1]+(int) $matches[2]+(int) $matches[3] == 0) {
2877  return $this->getEstimatedWorkingTime();
2878  } else {
2879  return array(
2880  'hh' => $matches[1],
2881  'mm' => $matches[2],
2882  'ss' => $matches[3],
2883  );
2884  }
2885  }
2886  }
2887  return $this->getEstimatedWorkingTime();
2888  }
2889 
2890  public function getProcessingTimeAsMinutes()
2891  {
2892  if (strlen($this->processing_time)) {
2893  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches)) {
2894  return ($matches[1] * 60) + $matches[2];
2895  }
2896  }
2897 
2898  return self::DEFAULT_PROCESSING_TIME_MINUTES;
2899  }
2900 
2908  public function getProcessingTimeInSeconds($active_id = "")
2909  {
2910  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches)) {
2911  $extratime = $this->getExtraTime($active_id) * 60;
2912  return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
2913  } else {
2914  return 0;
2915  }
2916  }
2917 
2925  public function getSecondsUntilEndingTime()
2926  {
2927  if ($this->getEndingTime() != 0) {
2928  $ending = $this->getEndingTime();
2929  $now = time();
2930  return $ending - $now;
2931  } else {
2932  return 0;
2933  }
2934  }
2935 
2943  public function getEnableProcessingTime()
2944  {
2945  return ($this->enable_processing_time) ? $this->enable_processing_time : 0;
2946  }
2947 
2955  public function getResetProcessingTime()
2956  {
2957  return ($this->reset_processing_time) ? $this->reset_processing_time : 0;
2958  }
2959 
2963  public function isStartingTimeEnabled()
2964  {
2966  }
2967 
2972  {
2973  $this->starting_time_enabled = $starting_time_enabled;
2974  }
2975 
2983  public function getStartingTime()
2984  {
2985  return ($this->starting_time != 0) ? $this->starting_time : 0;
2986  }
2987 
2995  public function setStartingTime($starting_time = null)
2996  {
2997  $this->starting_time = $starting_time;
2998  }
2999 
3003  public function isEndingTimeEnabled()
3004  {
3006  }
3007 
3012  {
3013  $this->ending_time_enabled = $ending_time_enabled;
3014  }
3015 
3023  public function getEndingTime()
3024  {
3025  return ($this->ending_time != 0) ? $this->ending_time : 0;
3026  }
3027 
3035  public function setEndingTime($ending_time = null)
3036  {
3037  $this->ending_time = $ending_time;
3038  }
3039 
3047  public function setNrOfTries($nr_of_tries = 0)
3048  {
3049  $this->nr_of_tries = $nr_of_tries;
3050  }
3051 
3060  {
3061  if ($use_previous_answers) {
3062  $this->use_previous_answers = 1;
3063  } else {
3064  $this->use_previous_answers = 0;
3065  }
3066  }
3067 
3069  {
3070  $this->redirection_mode = $redirection_mode;
3071  }
3072  public function getRedirectionMode()
3073  {
3074  return $this->redirection_mode;
3075  }
3076  public function setRedirectionUrl($redirection_url = null)
3077  {
3078  $this->redirection_url = $redirection_url;
3079  }
3080  public function getRedirectionUrl()
3081  {
3082  return $this->redirection_url;
3083  }
3084 
3092  public function setTitleOutput($title_output = 0)
3093  {
3094  switch ($title_output) {
3095  case 1:
3096  $this->title_output = 1;
3097  break;
3098  case 2:
3099  $this->title_output = 2;
3100  break;
3101  default:
3102  $this->title_output = 0;
3103  break;
3104  }
3105  }
3106 
3114  public function setProcessingTime($processing_time = "00:00:00")
3115  {
3116  $this->processing_time = $processing_time;
3117  }
3118 
3119  public function setProcessingTimeByMinutes($minutes)
3120  {
3121  $this->processing_time = sprintf("%02d:%02d:00", floor($minutes/60), $minutes%60);
3122  }
3123 
3131  public function setEnableProcessingTime($enable = 0)
3132  {
3133  if ($enable) {
3134  $this->enable_processing_time = "1";
3135  } else {
3136  $this->enable_processing_time = "0";
3137  }
3138  }
3139 
3147  public function setResetProcessingTime($reset = 0)
3148  {
3149  if ($reset) {
3150  $this->reset_processing_time = 1;
3151  } else {
3152  $this->reset_processing_time = 0;
3153  }
3154  }
3155 
3163  public function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3164  {
3165  $this->count_system = $a_count_system;
3166  }
3167 
3171  public function isPasswordEnabled()
3172  {
3173  return $this->passwordEnabled;
3174  }
3175 
3180  {
3181  $this->passwordEnabled = $passwordEnabled;
3182  }
3183 
3191  public function getPassword()
3192  {
3193  return (strlen($this->password)) ? $this->password : null;
3194  }
3195 
3203  public function setPassword($a_password = null)
3204  {
3205  $this->password = $a_password;
3206  }
3207 
3215  public function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3216  {
3217  $this->score_cutting = $a_score_cutting;
3218  }
3219 
3227  public function setMCScoring($a_mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED)
3228  {
3229  $this->mc_scoring = $a_mc_scoring;
3230  }
3231 
3239  public function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3240  {
3241  switch ($a_pass_scoring) {
3242  case SCORE_BEST_PASS:
3243  $this->pass_scoring = SCORE_BEST_PASS;
3244  break;
3245  default:
3246  $this->pass_scoring = SCORE_LAST_PASS;
3247  break;
3248  }
3249  }
3250 
3254  public function getPassWaiting()
3255  {
3256  return $this->pass_waiting;
3257  }
3258 
3263  {
3264  $this->pass_waiting = $pass_waiting;
3265  }
3269  public function isPassWaitingEnabled()
3270  {
3271  if (array_sum(explode(':', $this->getPassWaiting())) > 0) {
3272  return true;
3273  }
3274  return false;
3275  }
3276 
3280  public function removeQuestions($removeQuestionIds)
3281  {
3282  foreach ($removeQuestionIds as $value) {
3283  $this->removeQuestion($value);
3284  }
3285 
3287  }
3288 
3296  public function removeQuestion($question_id)
3297  {
3298  $question =&ilObjTest::_instanciateQuestion($question_id);
3299  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3301  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3302  }
3303  $question->delete($question_id);
3304  }
3305 
3315  {
3316  $this->removeTestResultsByUserIds($userIds);
3317 
3318  $ilDB = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['ilDB'];
3319  $lng = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['lng'] : $GLOBALS['lng'];
3320 
3321  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3322  $participantData = new ilTestParticipantData($ilDB, $lng);
3323  $participantData->setUserIds($userIds);
3324  $participantData->load($this->getTestId());
3325 
3326  $this->removeTestActives($participantData->getActiveIds());
3327  }
3328 
3329  public function removeTestResults(ilTestParticipantData $participantData)
3330  {
3331  if (count($participantData->getAnonymousActiveIds())) {
3332  $this->removeTestResultsByActiveIds($participantData->getAnonymousActiveIds());
3333  }
3334 
3335  if (count($participantData->getUserIds())) {
3336  /* @var ilTestLP $testLP */
3337  require_once 'Services/Object/classes/class.ilObjectLP.php';
3338  $testLP = ilObjectLP::getInstance($this->getId());
3339  $testLP->setTestObject($this);
3340  $testLP->resetLPDataForUserIds($participantData->getUserIds(), false);
3341  }
3342 
3343  if (count($participantData->getActiveIds())) {
3344  $this->removeTestActives($participantData->getActiveIds());
3345  }
3346  }
3347 
3348  public function removeTestResultsByUserIds($userIds)
3349  {
3350  global $ilDB, $lng;
3351 
3352  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3353  $participantData = new ilTestParticipantData($ilDB, $lng);
3354  $participantData->setUserIds($userIds);
3355  $participantData->load($this->getTestId());
3356 
3357  $IN_userIds = $ilDB->in('usr_id', $participantData->getUserIds(), false, 'integer');
3358  $ilDB->manipulateF(
3359  "DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
3360  array('text'),
3361  array("tst_password_" . $this->getTestId())
3362  );
3363 
3364  if (count($participantData->getActiveIds())) {
3365  $this->removeTestResultsByActiveIds($participantData->getActiveIds());
3366  }
3367  }
3368 
3369  public function removeTestResultsByActiveIds($activeIds)
3370  {
3371  global $ilDB;
3372 
3373  $IN_activeIds = $ilDB->in('active_fi', $activeIds, false, 'integer');
3374 
3375  $ilDB->manipulate("DELETE FROM tst_solutions WHERE $IN_activeIds");
3376  $ilDB->manipulate("DELETE FROM tst_qst_solved WHERE $IN_activeIds");
3377  $ilDB->manipulate("DELETE FROM tst_test_result WHERE $IN_activeIds");
3378  $ilDB->manipulate("DELETE FROM tst_pass_result WHERE $IN_activeIds");
3379  $ilDB->manipulate("DELETE FROM tst_result_cache WHERE $IN_activeIds");
3380  $ilDB->manipulate("DELETE FROM tst_sequence WHERE $IN_activeIds");
3381  $ilDB->manipulate("DELETE FROM tst_times WHERE $IN_activeIds");
3382 
3383  if ($this->isRandomTest()) {
3384  $ilDB->manipulate("DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
3385  } elseif ($this->isDynamicTest()) {
3386  $ilDB->manipulate("DELETE FROM tst_seq_qst_tracking WHERE $IN_activeIds");
3387  $ilDB->manipulate("DELETE FROM tst_seq_qst_answstatus WHERE $IN_activeIds");
3388  $ilDB->manipulate("DELETE FROM tst_seq_qst_postponed WHERE $IN_activeIds");
3389  $ilDB->manipulate("DELETE FROM tst_seq_qst_checked WHERE $IN_activeIds");
3390  }
3391 
3392  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3393 
3394  foreach ($activeIds as $active_id) {
3395  // remove file uploads
3396  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id")) {
3397  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3398  }
3399 
3401  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3402  }
3403  }
3404 
3405  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3407  }
3408 
3409  public function removeTestActives($activeIds)
3410  {
3411  global $ilDB;
3412 
3413  $IN_activeIds = $ilDB->in('active_id', $activeIds, false, 'integer');
3414  $ilDB->manipulate("DELETE FROM tst_active WHERE $IN_activeIds");
3415  }
3416 
3424  public function questionMoveUp($question_id)
3425  {
3426  global $ilDB;
3427 
3428  // Move a question up in sequence
3429  $result = $ilDB->queryF(
3430  "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3431  array('integer', 'integer'),
3432  array($this->getTestId(), $question_id)
3433  );
3434  $data = $ilDB->fetchObject($result);
3435  if ($data->sequence > 1) {
3436  // OK, it's not the top question, so move it up
3437  $result = $ilDB->queryF(
3438  "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3439  array('integer','integer'),
3440  array($this->getTestId(), $data->sequence - 1)
3441  );
3442  $data_previous = $ilDB->fetchObject($result);
3443  // change previous dataset
3444  $affectedRows = $ilDB->manipulateF(
3445  "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3446  array('integer','integer'),
3447  array($data->sequence, $data_previous->test_question_id)
3448  );
3449  // move actual dataset up
3450  $affectedRows = $ilDB->manipulateF(
3451  "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3452  array('integer','integer'),
3453  array($data->sequence - 1, $data->test_question_id)
3454  );
3455  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3457  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence-1), $question_id);
3458  }
3459  }
3460  $this->loadQuestions();
3461  }
3462 
3470  public function questionMoveDown($question_id)
3471  {
3472  global $ilDB;
3473 
3474  // Move a question down in sequence
3475  $result = $ilDB->queryF(
3476  "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3477  array('integer','integer'),
3478  array($this->getTestId(), $question_id)
3479  );
3480  $data = $ilDB->fetchObject($result);
3481  $result = $ilDB->queryF(
3482  "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3483  array('integer','integer'),
3484  array($this->getTestId(), $data->sequence + 1)
3485  );
3486  if ($result->numRows() == 1) {
3487  // OK, it's not the last question, so move it down
3488  $data_next = $ilDB->fetchObject($result);
3489  // change next dataset
3490  $affectedRows = $ilDB->manipulateF(
3491  "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3492  array('integer','integer'),
3493  array($data->sequence, $data_next->test_question_id)
3494  );
3495  // move actual dataset down
3496  $affectedRows = $ilDB->manipulateF(
3497  "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3498  array('integer','integer'),
3499  array($data->sequence + 1, $data->test_question_id)
3500  );
3501  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3503  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence+1), $question_id);
3504  }
3505  }
3506  $this->loadQuestions();
3507  }
3508 
3516  public function duplicateQuestionForTest($question_id)
3517  {
3518  global $ilUser;
3519  $question =&ilObjTest::_instanciateQuestion($question_id);
3520  $duplicate_id = $question->duplicate(true, null, null, null, $this->getId());
3521 
3522  return $duplicate_id;
3523  }
3524 
3533  public function insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly = false)
3534  {
3535  global $ilDB;
3536  #var_dump($question_id);
3537  if ($linkOnly) {
3538  $duplicate_id = $question_id;
3539  } else {
3540  $duplicate_id = $this->duplicateQuestionForTest($question_id);
3541  }
3542 
3543  // get maximum sequence index in test
3544  $result = $ilDB->queryF(
3545  "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
3546  array('integer'),
3547  array($this->getTestId())
3548  );
3549  $sequence = 1;
3550 
3551  if ($result->numRows() == 1) {
3552  $data = $ilDB->fetchObject($result);
3553  $sequence = $data->seq + 1;
3554  }
3555 
3556  $next_id = $ilDB->nextId('tst_test_question');
3557  $affectedRows = $ilDB->manipulateF(
3558  "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
3559  array('integer', 'integer','integer','integer','integer'),
3560  array($next_id, $this->getTestId(), $duplicate_id, $sequence, time())
3561  );
3562  if ($affectedRows == 1) {
3563  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3565  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3566  }
3567  }
3568  // remove test_active entries, because test has changed
3569  $affectedRows = $ilDB->manipulateF(
3570  "DELETE FROM tst_active WHERE test_fi = %s",
3571  array('integer'),
3572  array($this->getTestId())
3573  );
3574  $this->loadQuestions();
3575  $this->saveCompleteStatus($testQuestionSetConfig);
3576  return $duplicate_id;
3577  }
3578 
3586  public function &getQuestionTitles()
3587  {
3588  $titles = array();
3589  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3590  global $ilDB;
3591  $result = $ilDB->queryF(
3592  "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",
3593  array('integer'),
3594  array($this->getTestId())
3595  );
3596  while ($row = $ilDB->fetchAssoc($result)) {
3597  array_push($titles, $row["title"]);
3598  }
3599  }
3600  return $titles;
3601  }
3602 
3610  public function &getQuestionTitlesAndIndexes()
3611  {
3612  $titles = array();
3613  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
3614  global $ilDB;
3615  $result = $ilDB->queryF(
3616  "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",
3617  array('integer'),
3618  array($this->getTestId())
3619  );
3620  while ($row = $ilDB->fetchAssoc($result)) {
3621  $titles[$row['question_id']] = $row["title"];
3622  }
3623  }
3624  return $titles;
3625  }
3626 
3627  // fau: testNav - add number parameter (to show if title should not be shown)
3637  public function getQuestionTitle($title, $nr = null)
3638  {
3639  if ($this->getTitleOutput() == 2) {
3640  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC) {
3641  // avoid legacy setting combination: ctm without question titles
3642  return $title;
3643  } elseif (isset($nr)) {
3644  return $this->lng->txt("ass_question") . ' ' . $nr;
3645  } else {
3646  return $this->lng->txt("ass_question");
3647  }
3648  } else {
3649  return $title;
3650  }
3651  }
3652  // fau.
3653 
3662  public function getQuestionDataset($question_id)
3663  {
3664  global $ilDB;
3665 
3666  $result = $ilDB->queryF(
3667  "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",
3668  array('integer'),
3669  array($question_id)
3670  );
3671  $row = $ilDB->fetchObject($result);
3672  return $row;
3673  }
3674 
3681  public function &getExistingQuestions($pass = null)
3682  {
3683  global $ilUser;
3684  global $ilDB;
3685 
3686  $existing_questions = array();
3687  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3688  if ($this->isRandomTest()) {
3689  if (is_null($pass)) {
3690  $pass = 0;
3691  }
3692  $result = $ilDB->queryF(
3693  "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",
3694  array('integer','integer'),
3695  array($active_id, $pass)
3696  );
3697  } else {
3698  $result = $ilDB->queryF(
3699  "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",
3700  array('integer'),
3701  array($this->getTestId())
3702  );
3703  }
3704  while ($data = $ilDB->fetchObject($result)) {
3705  if ($data->original_id === null) {
3706  continue;
3707  }
3708 
3709  array_push($existing_questions, $data->original_id);
3710  }
3711  return $existing_questions;
3712  }
3713 
3721  public function getQuestionType($question_id)
3722  {
3723  global $ilDB;
3724 
3725  if ($question_id < 1) {
3726  return -1;
3727  }
3728  $result = $ilDB->queryF(
3729  "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",
3730  array('integer'),
3731  array($question_id)
3732  );
3733  if ($result->numRows() == 1) {
3734  $data = $ilDB->fetchObject($result);
3735  return $data->type_tag;
3736  } else {
3737  return "";
3738  }
3739  }
3740 
3747  public function startWorkingTime($active_id, $pass)
3748  {
3749  global $ilDB;
3750 
3751  $next_id = $ilDB->nextId('tst_times');
3752  $affectedRows = $ilDB->manipulateF(
3753  "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
3754  array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'),
3755  array($next_id, $active_id, strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"), $pass, time())
3756  );
3757  return $next_id;
3758  }
3759 
3766  public function updateWorkingTime($times_id)
3767  {
3768  global $ilDB;
3769 
3770  $affectedRows = $ilDB->manipulateF(
3771  "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
3772  array('timestamp', 'integer', 'integer'),
3773  array(strftime("%Y-%m-%d %H:%M:%S"), time(), $times_id)
3774  );
3775  }
3776 
3783  public function &getWorkedQuestions($active_id, $pass = null)
3784  {
3785  global $ilUser;
3786  global $ilDB;
3787 
3788  if (is_null($pass)) {
3789  $result = $ilDB->queryF(
3790  "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3791  array('integer','integer'),
3792  array($active_id, 0)
3793  );
3794  } else {
3795  $result = $ilDB->queryF(
3796  "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3797  array('integer','integer'),
3798  array($active_id, $pass)
3799  );
3800  }
3801  $result_array = array();
3802  while ($row = $ilDB->fetchAssoc($result)) {
3803  array_push($result_array, $row["question_fi"]);
3804  }
3805  return $result_array;
3806  }
3807 
3816  public function isTestFinishedToViewResults($active_id, $currentpass)
3817  {
3818  $num = ilObjTest::lookupPassResultsUpdateTimestamp($active_id, $currentpass);
3819  return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ? true : false;
3820  }
3821 
3828  public function &getAllQuestions($pass = null)
3829  {
3830  global $ilUser;
3831  global $ilDB;
3832 
3833  $result_array = array();
3834  if ($this->isRandomTest()) {
3835  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3836  $this->loadQuestions($active_id, $pass);
3837  if (count($this->questions) == 0) {
3838  return $result_array;
3839  }
3840  if (is_null($pass)) {
3841  $pass = self::_getPass($active_id);
3842  }
3843  $result = $ilDB->queryF(
3844  "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'),
3845  array('integer','integer'),
3846  array($active_id, $pass)
3847  );
3848  } else {
3849  if (count($this->questions) == 0) {
3850  return $result_array;
3851  }
3852  $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'));
3853  }
3854  while ($row = $ilDB->fetchAssoc($result)) {
3855  $result_array[$row["question_id"]] = $row;
3856  }
3857  return $result_array;
3858  }
3859 
3868  public function getActiveIdOfUser($user_id = "", $anonymous_id = "")
3869  {
3870  global $ilDB;
3871  global $ilUser;
3872 
3873  if (!$user_id) {
3874  $user_id = $ilUser->getId();
3875  }
3876  if (($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()]))) {
3877  $result = $ilDB->queryF(
3878  "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3879  array('integer','integer','text'),
3880  array($user_id, $this->test_id, $_SESSION["tst_access_code"][$this->getTestId()])
3881  );
3882  } elseif (strlen($anonymous_id)) {
3883  $result = $ilDB->queryF(
3884  "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3885  array('integer','integer','text'),
3886  array($user_id, $this->test_id, $anonymous_id)
3887  );
3888  } else {
3889  if ($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) {
3890  return null;
3891  }
3892  $result = $ilDB->queryF(
3893  "SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
3894  array('integer','integer'),
3895  array($user_id, $this->test_id)
3896  );
3897  }
3898  if ($result->numRows()) {
3899  $row = $ilDB->fetchAssoc($result);
3900  return $row["active_id"];
3901  } else {
3902  return 0;
3903  }
3904  }
3905 
3914  public static function _getActiveIdOfUser($user_id = "", $test_id = "")
3915  {
3916  global $ilDB;
3917  global $ilUser;
3918 
3919  if (!$user_id) {
3920  $user_id = $ilUser->id;
3921  }
3922  if (!$test_id) {
3923  return "";
3924  }
3925  $result = $ilDB->queryF(
3926  "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
3927  array('integer', 'integer'),
3928  array($user_id, $test_id)
3929  );
3930  if ($result->numRows()) {
3931  $row = $ilDB->fetchAssoc($result);
3932  return $row["active_id"];
3933  } else {
3934  return "";
3935  }
3936  }
3937 
3944  public function pcArrayShuffle($array)
3945  {
3946  $keys = array_keys($array);
3947  shuffle($keys);
3948  $result = array();
3949  foreach ($keys as $key) {
3950  $result[$key] = $array[$key];
3951  }
3952  return $result;
3953  }
3954 
3962  public function &getTestResult($active_id, $pass = null, $ordered_sequence = false, $considerHiddenQuestions = true, $considerOptionalQuestions = true)
3963  {
3964  global $tree, $ilDB, $lng, $ilPluginAdmin;
3965 
3966  $results = $this->getResultsForActiveId($active_id);
3967 
3968  if (is_null($pass)) {
3969  $pass = $results['pass'];
3970  }
3971 
3972  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
3973  $testSessionFactory = new ilTestSessionFactory($this);
3974  $testSession = $testSessionFactory->getSession($active_id);
3975 
3976  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
3977  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
3978  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $pass);
3979 
3980  if ($this->isDynamicTest()) {
3981  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
3982  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
3983  $dynamicQuestionSetConfig->loadFromDb();
3984 
3985  $testSequence->loadFromDb($dynamicQuestionSetConfig);
3986  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
3987 
3988  $sequence = $testSequence->getUserSequenceQuestions();
3989  } else {
3990  $testSequence->setConsiderHiddenQuestionsEnabled($considerHiddenQuestions);
3991  $testSequence->setConsiderOptionalQuestionsEnabled($considerOptionalQuestions);
3992 
3993  $testSequence->loadFromDb();
3994  $testSequence->loadQuestions();
3995 
3996  if ($ordered_sequence) {
3997  $sequence = $testSequence->getOrderedSequenceQuestions();
3998  } else {
3999  $sequence = $testSequence->getUserSequenceQuestions();
4000  }
4001  }
4002 
4003  $arrResults = array();
4004 
4005  $query = "
4006  SELECT tst_test_result.question_fi,
4007  tst_test_result.points reached,
4008  tst_test_result.hint_count requested_hints,
4009  tst_test_result.hint_points hint_points,
4010  tst_test_result.answered answered
4011 
4012  FROM tst_test_result
4013 
4014  LEFT JOIN tst_solutions
4015  ON tst_solutions.active_fi = tst_test_result.active_fi
4016  AND tst_solutions.question_fi = tst_test_result.question_fi
4017 
4018  WHERE tst_test_result.active_fi = %s
4019  AND tst_test_result.pass = %s
4020  ";
4021 
4022  $solutionresult = $ilDB->queryF(
4023  $query,
4024  array('integer', 'integer'),
4025  array($active_id, $pass)
4026  );
4027 
4028  while ($row = $ilDB->fetchAssoc($solutionresult)) {
4029  $arrResults[ $row['question_fi'] ] = $row;
4030  }
4031 
4032  $numWorkedThrough = count($arrResults);
4033 
4034  require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4035 
4036  $IN_question_ids = $ilDB->in('qpl_questions.question_id', $sequence, false, 'integer');
4037 
4038  $query = "
4039  SELECT qpl_questions.*,
4040  qpl_qst_type.type_tag,
4041  qpl_sol_sug.question_fi has_sug_sol
4042 
4043  FROM qpl_qst_type,
4044  qpl_questions
4045 
4046  LEFT JOIN qpl_sol_sug
4047  ON qpl_sol_sug.question_fi = qpl_questions.question_id
4048 
4049  WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi
4050  AND $IN_question_ids
4051  ";
4052 
4053  $result = $ilDB->query($query);
4054 
4055  $unordered = array();
4056 
4057  $key = 1;
4058 
4059  $obligationsAnswered = true;
4060 
4061  while ($row = $ilDB->fetchAssoc($result)) {
4062  $percentvalue = (
4063  $row['points'] ? $arrResults[ $row['question_id'] ]['reached'] / $row['points'] : 0
4064  );
4065 
4066  if ($percentvalue < 0) {
4067  $percentvalue = 0.0;
4068  }
4069 
4070  $data = array(
4071  "nr" => "$key",
4072  "title" => ilUtil::prepareFormOutput($row['title']),
4073  "max" => round($row['points'], 2),
4074  "reached" => round($arrResults[$row['question_id']]['reached'], 2),
4075  'requested_hints' => $arrResults[$row['question_id']]['requested_hints'],
4076  'hint_points' => $arrResults[$row['question_id']]['hint_points'],
4077  "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4078  "solution" => ($row['has_sug_sol']) ? assQuestion::_getSuggestedSolutionOutput($row['question_id']) : '',
4079  "type" => $row["type_tag"],
4080  "qid" => $row['question_id'],
4081  "original_id" => $row["original_id"],
4082  "workedthrough" => isset($arrResults[$row['question_id']]) ? 1 : 0,
4083  'answered' => $arrResults[$row['question_id']]['answered']
4084  );
4085 
4086  if (!$arrResults[ $row['question_id'] ]['answered']) {
4087  $obligationsAnswered = false;
4088  }
4089 
4090  $unordered[ $row['question_id'] ] = $data;
4091 
4092  $key++;
4093  }
4094 
4095  $numQuestionsTotal = count($unordered);
4096 
4097  $pass_max = 0;
4098  $pass_reached = 0;
4099  $pass_requested_hints = 0;
4100  $pass_hint_points = 0;
4101  $key = 1;
4102 
4103  $found = array();
4104 
4105  foreach ($sequence as $qid) {
4106  // building pass point sums based on prepared data
4107  // for question that exists in users qst sequence
4108  $pass_max += round($unordered[$qid]['max'], 2);
4109  $pass_reached += round($unordered[$qid]['reached'], 2);
4110  $pass_requested_hints += $unordered[$qid]['requested_hints'];
4111  $pass_hint_points += $unordered[$qid]['hint_points'];
4112 
4113  // pickup prepared data for question
4114  // that exists in users qst sequence
4115  $unordered[$qid]['nr'] = $key;
4116  array_push($found, $unordered[$qid]);
4117 
4118  // increment key counter
4119  $key++;
4120  }
4121 
4122  $unordered = null;
4123 
4124  if ($this->getScoreCutting() == 1) {
4125  if ($results['reached_points'] < 0) {
4126  $results['reached_points'] = 0;
4127  }
4128 
4129  if ($pass_reached < 0) {
4130  $pass_reached = 0;
4131  }
4132  }
4133 
4134  $found['pass']['total_max_points'] = $pass_max;
4135  $found['pass']['total_reached_points'] = $pass_reached;
4136  $found['pass']['total_requested_hints'] = $pass_requested_hints;
4137  $found['pass']['total_hint_points'] = $pass_hint_points;
4138  $found['pass']['percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
4139  $found['pass']['obligationsAnswered'] = $obligationsAnswered;
4140  $found['pass']['num_workedthrough'] = $numWorkedThrough;
4141  $found['pass']['num_questions_total'] = $numQuestionsTotal;
4142 
4143  $found["test"]["total_max_points"] = $results['max_points'];
4144  $found["test"]["total_reached_points"] = $results['reached_points'];
4145  $found["test"]["total_requested_hints"] = $results['hint_count'];
4146  $found["test"]["total_hint_points"] = $results['hint_points'];
4147  $found["test"]["result_pass"] = $results['pass'];
4148  $found['test']['result_tstamp'] = $results['tstamp'];
4149  $found['test']['obligations_answered'] = $results['obligations_answered'];
4150 
4151  if ((!$total_reached_points) or (!$total_max_points)) {
4152  $percentage = 0.0;
4153  } else {
4154  $percentage = ($total_reached_points / $total_max_points) * 100.0;
4155 
4156  if ($percentage < 0) {
4157  $percentage = 0.0;
4158  }
4159  }
4160 
4161  $found["test"]["passed"] = $results['passed'];
4162 
4163  return $found;
4164  }
4165 
4172  public function evalTotalPersons()
4173  {
4174  global $ilDB;
4175 
4176  $result = $ilDB->queryF(
4177  "SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
4178  array('integer'),
4179  array($this->getTestId())
4180  );
4181  $row = $ilDB->fetchAssoc($result);
4182  return $row["total"];
4183  }
4184 
4191  public function getCompleteWorkingTime($user_id)
4192  {
4193  global $ilDB;
4194 
4195  $result = $ilDB->queryF(
4196  "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",
4197  array('integer','integer'),
4198  array($this->getTestId(), $user_id)
4199  );
4200  $time = 0;
4201  while ($row = $ilDB->fetchAssoc($result)) {
4202  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4203  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4204  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4205  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4206  $time += ($epoch_2 - $epoch_1);
4207  }
4208  return $time;
4209  }
4210 
4218  {
4219  return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4220  }
4221 
4230  {
4231  global $ilDB;
4232 
4233  $result = $ilDB->queryF(
4234  "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",
4235  array('integer'),
4236  array($test_id)
4237  );
4238  $time = 0;
4239  $times = array();
4240  while ($row = $ilDB->fetchAssoc($result)) {
4241  if (!array_key_exists($row["active_fi"], $times)) {
4242  $times[$row["active_fi"]] = 0;
4243  }
4244  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4245  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4246  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4247  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4248  $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4249  }
4250  return $times;
4251  }
4252 
4259  public function getCompleteWorkingTimeOfParticipant($active_id)
4260  {
4261  global $ilDB;
4262 
4263  $result = $ilDB->queryF(
4264  "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",
4265  array('integer','integer'),
4266  array($this->getTestId(), $active_id)
4267  );
4268  $time = 0;
4269  while ($row = $ilDB->fetchAssoc($result)) {
4270  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4271  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4272  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4273  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4274  $time += ($epoch_2 - $epoch_1);
4275  }
4276  return $time;
4277  }
4278 
4285  public static function _getWorkingTimeOfParticipantForPass($active_id, $pass)
4286  {
4287  global $ilDB;
4288 
4289  $result = $ilDB->queryF(
4290  "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4291  array('integer','integer'),
4292  array($active_id, $pass)
4293  );
4294  $time = 0;
4295  while ($row = $ilDB->fetchAssoc($result)) {
4296  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4297  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4298  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4299  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4300  $time += ($epoch_2 - $epoch_1);
4301  }
4302  return $time;
4303  }
4304 
4312  public function getVisitTimeOfParticipant($active_id)
4313  {
4314  return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4315  }
4316 
4325  public function _getVisitTimeOfParticipant($test_id, $active_id)
4326  {
4327  global $ilDB;
4328 
4329  $result = $ilDB->queryF(
4330  "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",
4331  array('integer','integer'),
4332  array($test_id, $active_id)
4333  );
4334  $firstvisit = 0;
4335  $lastvisit = 0;
4336  while ($row = $ilDB->fetchAssoc($result)) {
4337  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4338  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4339  if ($firstvisit == 0 || $epoch_1 < $firstvisit) {
4340  $firstvisit = $epoch_1;
4341  }
4342  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4343  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4344  if ($epoch_2 > $lastvisit) {
4345  $lastvisit = $epoch_2;
4346  }
4347  }
4348  return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4349  }
4350 
4357  public function &evalStatistical($active_id)
4358  {
4359  global $ilDB;
4360  // global $ilBench;
4361  $pass = ilObjTest::_getResultPass($active_id);
4362  $test_result =&$this->getTestResult($active_id, $pass);
4363  $result = $ilDB->queryF(
4364  "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
4365  array('integer'),
4366  array($active_id)
4367  );
4368  $times = array();
4369  $first_visit = 0;
4370  $last_visit = 0;
4371  while ($row = $ilDB->fetchObject($result)) {
4372  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4373  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4374  if (!$first_visit) {
4375  $first_visit = $epoch_1;
4376  }
4377  if ($epoch_1 < $first_visit) {
4378  $first_visit = $epoch_1;
4379  }
4380  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4381  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4382  if (!$last_visit) {
4383  $last_visit = $epoch_2;
4384  }
4385  if ($epoch_2 > $last_visit) {
4386  $last_visit = $epoch_2;
4387  }
4388  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4389  }
4390  $max_time = 0;
4391  foreach ($times as $key => $value) {
4392  $max_time += $value;
4393  }
4394  if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"])) {
4395  $percentage = 0.0;
4396  } else {
4397  $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4398  if ($percentage < 0) {
4399  $percentage = 0.0;
4400  }
4401  }
4402  $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4403  $first_date = getdate($first_visit);
4404  $last_date = getdate($last_visit);
4405  $qworkedthrough = 0;
4406  foreach ($test_result as $key => $value) {
4407  if (preg_match("/\d+/", $key)) {
4408  $qworkedthrough += $value["workedthrough"];
4409  }
4410  }
4411  if (!$qworkedthrough) {
4412  $atimeofwork = 0;
4413  } else {
4414  $atimeofwork = $max_time / $qworkedthrough;
4415  }
4416 
4417  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4418 
4419  $result_mark = "";
4420  $passed = "";
4421 
4422  if ($mark_obj) {
4423  $result_mark = $mark_obj->getShortName();
4424 
4425  if ($mark_obj->getPassed() && $obligationsAnswered) {
4426  $passed = 1;
4427  } else {
4428  $passed = 0;
4429  }
4430  }
4431  $percent_worked_through = 0;
4432  if (count($this->questions)) {
4433  $percent_worked_through = $qworkedthrough / count($this->questions);
4434  }
4435  $result_array = array(
4436  "qworkedthrough" => $qworkedthrough,
4437  "qmax" => count($this->questions),
4438  "pworkedthrough" => $percent_worked_through,
4439  "timeofwork" => $max_time,
4440  "atimeofwork" => $atimeofwork,
4441  "firstvisit" => $first_date,
4442  "lastvisit" => $last_date,
4443  "resultspoints" => $test_result["test"]["total_reached_points"],
4444  "maxpoints" => $test_result["test"]["total_max_points"],
4445  "resultsmarks" => $result_mark,
4446  "passed" => $passed,
4447  "distancemedian" => "0"
4448  );
4449  foreach ($test_result as $key => $value) {
4450  if (preg_match("/\d+/", $key)) {
4451  $result_array[$key] = $value;
4452  }
4453  }
4454  return $result_array;
4455  }
4456 
4464  public function &getTotalPointsPassedArray()
4465  {
4466  $totalpoints_array = array();
4467  $all_users =&$this->evalTotalParticipantsArray();
4468  foreach ($all_users as $active_id => $user_name) {
4469  $test_result =&$this->getTestResult($active_id);
4470  $reached = $test_result["test"]["total_reached_points"];
4471  $total = $test_result["test"]["total_max_points"];
4472  $percentage = $total != 0 ? $reached/$total : 0;
4473  $mark = $this->mark_schema->getMatchingMark($percentage*100.0);
4474 
4475  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4476 
4477  if ($mark) {
4478  if ($mark->getPassed() && $obligationsAnswered) {
4479  array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4480  }
4481  }
4482  }
4483  return $totalpoints_array;
4484  }
4485 
4491  public function &getParticipants()
4492  {
4493  global $ilDB;
4494  $result = $ilDB->queryF(
4495  "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",
4496  array('integer'),
4497  array($this->getTestId())
4498  );
4499  $persons_array = array();
4500  while ($row = $ilDB->fetchAssoc($result)) {
4501  $name = $this->lng->txt("anonymous");
4502  $fullname = $this->lng->txt("anonymous");
4503  $login = "";
4504  if (!$this->getAnonymity()) {
4505  if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4506  $name = $this->lng->txt("deleted_user");
4507  $fullname = $this->lng->txt("deleted_user");
4508  $login = $this->lng->txt("unknown");
4509  } else {
4510  $login = $row["login"];
4511  if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4512  $name = $this->lng->txt("anonymous");
4513  $fullname = $this->lng->txt("anonymous");
4514  } else {
4515  $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4516  $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4517  }
4518  }
4519  }
4520  $persons_array[$row["active_id"]] = array(
4521  "name" => $name,
4522  "fullname" => $fullname,
4523  "login" => $login
4524  );
4525  }
4526  return $persons_array;
4527  }
4528 
4535  public function &evalTotalPersonsArray($name_sort_order = "asc")
4536  {
4537  global $ilDB;
4538  $result = $ilDB->queryF(
4539  "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),
4540  array('integer'),
4541  array($this->getTestId())
4542  );
4543  $persons_array = array();
4544  while ($row = $ilDB->fetchAssoc($result)) {
4545  if ($this->getAnonymity()) {
4546  $persons_array[$row["active_id"]] = $this->lng->txt("anonymous");
4547  } else {
4548  if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4549  $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4550  } else {
4551  if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4552  $persons_array[$row["active_id"]] = $row["lastname"];
4553  } else {
4554  $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4555  }
4556  }
4557  }
4558  }
4559  return $persons_array;
4560  }
4561 
4568  public function &evalTotalParticipantsArray($name_sort_order = "asc")
4569  {
4570  global $ilDB;
4571  $result = $ilDB->queryF(
4572  "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),
4573  array('integer'),
4574  array($this->getTestId())
4575  );
4576  $persons_array = array();
4577  while ($row = $ilDB->fetchAssoc($result)) {
4578  if ($this->getAnonymity()) {
4579  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("anonymous"));
4580  } else {
4581  if (strlen($row["firstname"] . $row["lastname"] . $row["title"]) == 0) {
4582  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4583  } else {
4584  if ($row["user_fi"] == ANONYMOUS_USER_ID) {
4585  $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4586  } else {
4587  $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4588  }
4589  }
4590  }
4591  }
4592  return $persons_array;
4593  }
4594 
4601  public function evalTotalFinished()
4602  {
4603  global $ilDB;
4604 
4605  $result = $ilDB->queryF(
4606  "SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s AND submitted = %s",
4607  array('integer', 'integer'),
4608  array($this->getTestId(), 1)
4609  );
4610  $row = $ilDB->fetchAssoc($result);
4611  return $row["total"];
4612  }
4613 
4620  public function &getQuestionsOfTest($active_id)
4621  {
4622  global $ilDB;
4623  if ($this->isRandomTest()) {
4624  $ilDB->setLimit($this->getQuestionCount(), 0);
4625  $result = $ilDB->queryF(
4626  "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4627  "tst_test_rnd_qst.pass, qpl_questions.points " .
4628  "FROM tst_test_rnd_qst, qpl_questions " .
4629  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4630  "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4631  array('integer'),
4632  array($active_id)
4633  );
4634  } else {
4635  $result = $ilDB->queryF(
4636  "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4637  "qpl_questions.points " .
4638  "FROM tst_test_question, tst_active, qpl_questions " .
4639  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4640  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4641  array('integer'),
4642  array($active_id)
4643  );
4644  }
4645  $qtest = array();
4646  if ($result->numRows()) {
4647  while ($row = $ilDB->fetchAssoc($result)) {
4648  array_push($qtest, $row);
4649  }
4650  }
4651  return $qtest;
4652  }
4653 
4660  public function &getQuestionsOfPass($active_id, $pass)
4661  {
4662  global $ilDB;
4663  if ($this->isRandomTest()) {
4664  $ilDB->setLimit($this->getQuestionCount(), 0);
4665  $result = $ilDB->queryF(
4666  "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4667  "qpl_questions.points " .
4668  "FROM tst_test_rnd_qst, qpl_questions " .
4669  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4670  "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
4671  "ORDER BY tst_test_rnd_qst.sequence",
4672  array('integer', 'integer'),
4673  array($active_id, $pass)
4674  );
4675  } else {
4676  $result = $ilDB->queryF(
4677  "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4678  "qpl_questions.points " .
4679  "FROM tst_test_question, tst_active, qpl_questions " .
4680  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4681  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4682  array('integer'),
4683  array($active_id)
4684  );
4685  }
4686  $qpass = array();
4687  if ($result->numRows()) {
4688  while ($row = $ilDB->fetchAssoc($result)) {
4689  array_push($qpass, $row);
4690  }
4691  }
4692  return $qpass;
4693  }
4694 
4695  public function getUnfilteredEvaluationData()
4696  {
4698  global $DIC;
4699 
4700  $ilDB = $DIC->database();
4701 
4702  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
4703  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
4704  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
4705 
4706  $data = new ilTestEvaluationData($this);
4707 
4708  $query = "
4709  SELECT tst_test_result.*,
4710  qpl_questions.original_id,
4711  qpl_questions.title questiontitle,
4712  qpl_questions.points maxpoints
4713 
4714  FROM tst_test_result, qpl_questions, tst_active
4715 
4716  WHERE tst_active.active_id = tst_test_result.active_fi
4717  AND qpl_questions.question_id = tst_test_result.question_fi
4718  AND tst_active.test_fi = %s
4719 
4720  ORDER BY tst_active.active_id ASC, tst_test_result.pass ASC, tst_test_result.tstamp DESC
4721  ";
4722 
4723  $result = $ilDB->queryF(
4724  $query,
4725  array('integer'),
4726  array($this->getTestId())
4727  );
4728 
4729  $pass = null;
4730  $checked = array();
4731  $datasets = 0;
4732  $questionData = [];
4733 
4734  while ($row = $ilDB->fetchAssoc($result)) {
4735  $participantObject = $data->getParticipant($row["active_fi"]);
4736 
4737  if (!($participantObject instanceof ilTestEvaluationUserData)) {
4738  continue;
4739  }
4740 
4741  $passObject = $participantObject->getPass($row["pass"]);
4742 
4743  if (!($passObject instanceof ilTestEvaluationPassData)) {
4744  continue;
4745  }
4746 
4747  $passObject->addAnsweredQuestion(
4748  $row["question_fi"],
4749  $row["maxpoints"],
4750  $row["points"],
4751  $row['answered'],
4752  null,
4753  $row['manual']
4754  );
4755  }
4756 
4757  foreach (array_keys($data->getParticipants()) as $active_id) {
4758  if ($this->isRandomTest()) {
4759  for ($testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++) {
4760  $ilDB->setLimit($this->getQuestionCount(), 0);
4761 
4762  $query = "
4763  SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, qpl_questions.original_id,
4764  tst_test_rnd_qst.pass, qpl_questions.points, qpl_questions.title
4765  FROM tst_test_rnd_qst, qpl_questions
4766  WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
4767  AND tst_test_rnd_qst.pass = %s
4768  AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence
4769  ";
4770 
4771  $result = $ilDB->queryF(
4772  $query,
4773  array('integer','integer'),
4774  array($testpass, $active_id)
4775  );
4776 
4777  if ($result->numRows()) {
4778  while ($row = $ilDB->fetchAssoc($result)) {
4779  $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
4780 
4781  $data->getParticipant($active_id)->addQuestion(
4782  $row["original_id"],
4783  $row["question_fi"],
4784  $row["points"],
4785  $row["sequence"],
4786  $tpass
4787  );
4788 
4789  $data->addQuestionTitle($row["question_fi"], $row["title"]);
4790  }
4791  }
4792  }
4793  } elseif ($this->isDynamicTest()) {
4794  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4795  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4796  require_once 'Modules/Test/classes/class.ilTestDynamicQuestionSetFilterSelection.php';
4797 
4798  $lastPass = $data->getParticipant($active_id)->getLastPass();
4799  for ($testpass = 0; $testpass <= $lastPass; $testpass++) {
4800  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4801  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig(
4802  $DIC->repositoryTree(),
4803  $DIC->database(),
4804  $DIC['ilPluginAdmin'],
4805  $this
4806  );
4807  $dynamicQuestionSetConfig->loadFromDb();
4808 
4809  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4810  $testSequenceFactory = new ilTestSequenceFactory($DIC->database(), $DIC->language(), $DIC['ilPluginAdmin'], $this);
4811  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $testpass);
4812 
4813  $testSequence->loadFromDb($dynamicQuestionSetConfig);
4814  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4815 
4816  $sequence = (array) $testSequence->getUserSequenceQuestions();
4817 
4818  $questionsIdsToRequest = array_diff(array_values($sequence), array_values($questionData));
4819  if (count($questionsIdsToRequest) > 0) {
4820  $questionIdsCondition = ' ' . $DIC->database()->in('question_id', array_values($questionsIdsToRequest), false, 'integer') . ' ';
4821 
4822  $res = $DIC->database()->queryF(
4823  "
4824  SELECT *
4825  FROM qpl_questions
4826  WHERE {$questionIdsCondition}",
4827  array('integer'),
4828  array($active_id)
4829  );
4830  while ($row = $DIC->database()->fetchAssoc($res)) {
4831  $questionData[$row['question_id']] = $row;
4832  $data->addQuestionTitle($row['question_id'], $row['title']);
4833  }
4834  }
4835 
4836  foreach ($sequence as $questionId) {
4837  if (!isset($questionData[$questionId])) {
4838  continue;
4839  }
4840 
4841  $row = $questionData[$questionId];
4842 
4843  $data->getParticipant(
4844  $active_id
4845  )->addQuestion(
4846  $row['original_id'],
4847  $row['question_id'],
4848  $row['points'],
4849  null,
4850  $testpass
4851  );
4852  }
4853  }
4854  } else {
4855  $query = "
4856  SELECT tst_test_question.sequence, tst_test_question.question_fi,
4857  qpl_questions.points, qpl_questions.title, qpl_questions.original_id
4858  FROM tst_test_question, tst_active, qpl_questions
4859  WHERE tst_test_question.question_fi = qpl_questions.question_id
4860  AND tst_active.active_id = %s
4861  AND tst_active.test_fi = tst_test_question.test_fi
4862  ORDER BY tst_test_question.sequence
4863  ";
4864 
4865  $result = $ilDB->queryF(
4866  $query,
4867  array('integer'),
4868  array($active_id)
4869  );
4870 
4871  if ($result->numRows()) {
4872  $questionsbysequence = array();
4873 
4874  while ($row = $ilDB->fetchAssoc($result)) {
4875  $questionsbysequence[$row["sequence"]] = $row;
4876  }
4877 
4878  $seqresult = $ilDB->queryF(
4879  "SELECT * FROM tst_sequence WHERE active_fi = %s",
4880  array('integer'),
4881  array($active_id)
4882  );
4883 
4884  while ($seqrow = $ilDB->fetchAssoc($seqresult)) {
4885  $questionsequence = unserialize($seqrow["sequence"]);
4886 
4887  foreach ($questionsequence as $sidx => $seq) {
4888  $data->getParticipant($active_id)->addQuestion(
4889  $questionsbysequence[$seq]["original_id"],
4890  $questionsbysequence[$seq]["question_fi"],
4891  $questionsbysequence[$seq]["points"],
4892  $sidx + 1,
4893  $seqrow["pass"]
4894  );
4895 
4896  $data->addQuestionTitle(
4897  $questionsbysequence[$seq]["question_fi"],
4898  $questionsbysequence[$seq]["title"]
4899  );
4900  }
4901  }
4902  }
4903  }
4904  }
4905 
4906  if ($this->getECTSOutput()) {
4907  $passed_array =&$this->getTotalPointsPassedArray();
4908  }
4909 
4910  foreach (array_keys($data->getParticipants()) as $active_id) {
4911  $tstUserData = $data->getParticipant($active_id);
4912 
4913  $percentage = $tstUserData->getReachedPointsInPercent();
4914 
4915  $obligationsAnswered = $tstUserData->areObligationsAnswered();
4916 
4917  $mark = $this->mark_schema->getMatchingMark($percentage);
4918 
4919  if (is_object($mark)) {
4920  $tstUserData->setMark($mark->getShortName());
4921  $tstUserData->setMarkOfficial($mark->getOfficialName());
4922 
4923  $tstUserData->setPassed(
4924  $mark->getPassed() && $tstUserData->areObligationsAnswered()
4925  );
4926  }
4927 
4928  if ($this->getECTSOutput()) {
4929  $ects_mark = $this->getECTSGrade(
4930  $passed_array,
4931  $tstUserData->getReached(),
4932  $tstUserData->getMaxPoints()
4933  );
4934 
4935  $tstUserData->setECTSMark($ects_mark);
4936  }
4937 
4938  $visitingTime =&$this->getVisitTimeOfParticipant($active_id);
4939 
4940  $tstUserData->setFirstVisit($visitingTime["firstvisit"]);
4941  $tstUserData->setLastVisit($visitingTime["lastvisit"]);
4942  }
4943 
4944  return $data;
4945  }
4946 
4947  public static function _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
4948  {
4949  global $ilDB;
4950 
4952 
4953  switch ($questionSetType) {
4955 
4956  $res = $ilDB->queryF(
4957  "
4958  SELECT COUNT(qpl_questions.question_id) qcount,
4959  SUM(qpl_questions.points) qsum
4960  FROM tst_active
4961  INNER JOIN tst_tests
4962  ON tst_tests.test_id = tst_active.test_fi
4963  INNER JOIN tst_dyn_quest_set_cfg
4964  ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
4965  INNER JOIN qpl_questions
4966  ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
4967  AND qpl_questions.original_id IS NULL
4968  AND qpl_questions.complete = %s
4969  WHERE tst_active.active_id = %s
4970  ",
4971  array('integer', 'integer'),
4972  array(1, $active_id)
4973  );
4974 
4975  break;
4976 
4978 
4979  $res = $ilDB->queryF(
4980  "
4981  SELECT tst_test_rnd_qst.pass,
4982  COUNT(tst_test_rnd_qst.question_fi) qcount,
4983  SUM(qpl_questions.points) qsum
4984 
4985  FROM tst_test_rnd_qst,
4986  qpl_questions
4987 
4988  WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
4989  AND tst_test_rnd_qst.active_fi = %s
4990  AND pass = %s
4991 
4992  GROUP BY tst_test_rnd_qst.active_fi,
4993  tst_test_rnd_qst.pass
4994  ",
4995  array('integer', 'integer'),
4996  array($active_id, $pass)
4997  );
4998 
4999  break;
5000 
5002 
5003  $res = $ilDB->queryF(
5004  "
5005  SELECT COUNT(tst_test_question.question_fi) qcount,
5006  SUM(qpl_questions.points) qsum
5007 
5008  FROM tst_test_question,
5009  qpl_questions,
5010  tst_active
5011 
5012  WHERE tst_test_question.question_fi = qpl_questions.question_id
5013  AND tst_test_question.test_fi = tst_active.test_fi
5014  AND tst_active.active_id = %s
5015 
5016  GROUP BY tst_test_question.test_fi
5017  ",
5018  array('integer'),
5019  array($active_id)
5020  );
5021 
5022  break;
5023 
5024  default:
5025 
5026  throw new ilTestException("not supported question set type: $questionSetType");
5027  }
5028 
5029  $row = $ilDB->fetchAssoc($res);
5030 
5031  if (is_array($row)) {
5032  return array("count" => $row["qcount"], "points" => $row["qsum"]);
5033  }
5034 
5035  return array("count" => 0, "points" => 0);
5036  }
5037 
5038  public function &getCompleteEvaluationData($withStatistics = true, $filterby = "", $filtertext = "")
5039  {
5040  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5041  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5042  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5043  $data = $this->getUnfilteredEvaluationData();
5044  if ($withStatistics) {
5045  $data->calculateStatistics();
5046  }
5047  $data->setFilter($filterby, $filtertext);
5048  return $data;
5049  }
5050 
5057  public function &evalResultsOverview()
5058  {
5059  return $this->_evalResultsOverview($this->getTestId());
5060  }
5061 
5068  public function &_evalResultsOverview($test_id)
5069  {
5070  global $ilDB;
5071 
5072  $result = $ilDB->queryF(
5073  "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5074  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5075  "qpl_questions.points maxpoints " .
5076  "FROM tst_test_result, qpl_questions, tst_active " .
5077  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5078  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5079  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5080  "AND tst_active.test_fi = %s " .
5081  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5082  array('integer'),
5083  array($test_id)
5084  );
5085  $overview = array();
5086  while ($row = $ilDB->fetchAssoc($result)) {
5087  if (!array_key_exists($row["active_fi"], $overview)) {
5088  $overview[$row["active_fi"]] = array();
5089  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5090  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5091  $overview[$row["active_fi"]]["title"] = $row["title"];
5092  $overview[$row["active_fi"]]["login"] = $row["login"];
5093  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5094  $overview[$row["active_fi"]]["started"] = $row["started"];
5095  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5096  }
5097  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5098  $overview[$row["active_fi"]][$row["pass"]] = array();
5099  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5100  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5101  }
5102  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5103  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5104  }
5105  return $overview;
5106  }
5107 
5115  public function &evalResultsOverviewOfParticipant($active_id)
5116  {
5117  global $ilDB;
5118 
5119  $result = $ilDB->queryF(
5120  "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5121  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5122  "qpl_questions.points maxpoints " .
5123  "FROM tst_test_result, qpl_questions, tst_active " .
5124  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5125  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5126  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5127  "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5128  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5129  array('integer', 'integer'),
5130  array($this->getTestId(), $active_id)
5131  );
5132  $overview = array();
5133  while ($row = $ilDB->fetchAssoc($result)) {
5134  if (!array_key_exists($row["active_fi"], $overview)) {
5135  $overview[$row["active_fi"]] = array();
5136  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5137  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5138  $overview[$row["active_fi"]]["title"] = $row["title"];
5139  $overview[$row["active_fi"]]["login"] = $row["login"];
5140  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5141  $overview[$row["active_fi"]]["started"] = $row["started"];
5142  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5143  }
5144  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]])) {
5145  $overview[$row["active_fi"]][$row["pass"]] = array();
5146  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5147  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5148  }
5149  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5150  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5151  }
5152  return $overview;
5153  }
5154 
5166  public function buildName($user_id, $firstname, $lastname, $title)
5167  {
5168  $name = "";
5169  if (strlen($firstname . $lastname . $title) == 0) {
5170  $name = $this->lng->txt("deleted_user");
5171  } else {
5172  if ($user_id == ANONYMOUS_USER_ID) {
5173  $name = $lastname;
5174  } else {
5175  $name = trim($lastname . ", " . $firstname . " " . $title);
5176  }
5177  if ($this->getAnonymity()) {
5178  $name = $this->lng->txt("anonymous");
5179  }
5180  }
5181  return $name;
5182  }
5183 
5196  public function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5197  {
5198  global $lng;
5199  $name = "";
5200  if (strlen($firstname . $lastname . $title) == 0) {
5201  $name = $lng->txt("deleted_user");
5202  } else {
5203  if ($user_id == ANONYMOUS_USER_ID) {
5204  $name = $lastname;
5205  } else {
5206  $name = trim($lastname . ", " . $firstname . " " . $title);
5207  }
5208  if ($is_anonymous) {
5209  $name = $lng->txt("anonymous");
5210  }
5211  }
5212  return $name;
5213  }
5214 
5222  {
5223  global $ilDB;
5224 
5225  $result = $ilDB->queryF(
5226  "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi",
5227  array('integer'),
5228  array($this->getTestId())
5229  );
5230  $times = array();
5231  while ($row = $ilDB->fetchObject($result)) {
5232  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5233  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5234  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5235  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5236  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5237  }
5238  $max_time = 0;
5239  $counter = 0;
5240  foreach ($times as $key => $value) {
5241  $max_time += $value;
5242  $counter++;
5243  }
5244  if ($counter) {
5245  $average_time = round($max_time / $counter);
5246  } else {
5247  $average_time = 0;
5248  }
5249  return $average_time;
5250  }
5251 
5258  public function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = false, $with_questioncount = false, $permission = "read")
5259  {
5260  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5261  return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5262  }
5263 
5270  public function getEstimatedWorkingTime()
5271  {
5272  $time_in_seconds = 0;
5273  foreach ($this->questions as $question_id) {
5274  $question =&ilObjTest::_instanciateQuestion($question_id);
5275  $est_time = $question->getEstimatedWorkingTime();
5276  $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5277  }
5278  $hours = (int) ($time_in_seconds / 3600) ;
5279  $time_in_seconds = $time_in_seconds - ($hours * 3600);
5280  $minutes = (int) ($time_in_seconds / 60);
5281  $time_in_seconds = $time_in_seconds - ($minutes * 60);
5282  $result = array("hh" => $hours, "mm" => $minutes, "ss" => $time_in_seconds);
5283  return $result;
5284  }
5285 
5292  public function getImagePath()
5293  {
5294  return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5295  }
5296 
5303  public function getImagePathWeb()
5304  {
5305  include_once "./Services/Utilities/classes/class.ilUtil.php";
5306  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
5307  return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir);
5308  }
5309 
5318  public function &createQuestionGUI($question_type, $question_id = -1)
5319  {
5320  if ((!$question_type) and ($question_id > 0)) {
5321  $question_type = $this->getQuestionType($question_id);
5322  }
5323 
5324  if (!strlen($question_type)) {
5325  return null;
5326  }
5327 
5328  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5329  assQuestion::_includeClass($question_type, 1);
5330 
5331  $question_type_gui = assQuestion::getGuiClassNameByQuestionType($question_type);
5332  $question = new $question_type_gui();
5333 
5334  if ($question_id > 0) {
5335  $question->object->loadFromDb($question_id);
5336 
5337  global $ilCtrl, $ilDB, $ilUser, $lng;
5338 
5339  $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
5340  $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
5341 
5342  $assSettings = new ilSetting('assessment');
5343  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
5344  $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
5345  $processLockerFactory->setQuestionId($question->object->getId());
5346  $processLockerFactory->setUserId($ilUser->getId());
5347  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
5348  $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
5349  $question->object->setProcessLocker($processLockerFactory->getLocker());
5350  }
5351 
5352  return $question;
5353  }
5354 
5364  public static function _instanciateQuestion($question_id)
5365  {
5366  if (strcmp($question_id, "") != 0) {
5367  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5368  return assQuestion::_instanciateQuestion($question_id);
5369  }
5370  }
5371 
5380  public function moveQuestions($move_questions, $target_index, $insert_mode)
5381  {
5382  $this->questions = array_values($this->questions);
5383  $array_pos = array_search($target_index, $this->questions);
5384  if ($insert_mode == 0) {
5385  $part1 = array_slice($this->questions, 0, $array_pos);
5386  $part2 = array_slice($this->questions, $array_pos);
5387  } elseif ($insert_mode == 1) {
5388  $part1 = array_slice($this->questions, 0, $array_pos + 1);
5389  $part2 = array_slice($this->questions, $array_pos + 1);
5390  }
5391  foreach ($move_questions as $question_id) {
5392  if (!(array_search($question_id, $part1) === false)) {
5393  unset($part1[array_search($question_id, $part1)]);
5394  }
5395  if (!(array_search($question_id, $part2) === false)) {
5396  unset($part2[array_search($question_id, $part2)]);
5397  }
5398  }
5399  $part1 = array_values($part1);
5400  $part2 = array_values($part2);
5401  $new_array = array_values(array_merge($part1, $move_questions, $part2));
5402  $this->questions = array();
5403  $counter = 1;
5404  foreach ($new_array as $question_id) {
5405  $this->questions[$counter] = $question_id;
5406  $counter++;
5407  }
5408  $this->saveQuestionsToDb();
5409  }
5410 
5411 
5419  public function startingTimeReached()
5420  {
5421  if ($this->isStartingTimeEnabled() && $this->getStartingTime() != 0) {
5422  $now = time();
5423  if ($now < $this->getStartingTime()) {
5424  return false;
5425  }
5426  }
5427  return true;
5428  }
5429 
5437  public function endingTimeReached()
5438  {
5439  if ($this->isEndingTimeEnabled() && $this->getEndingTime() != 0) {
5440  $now = time();
5441  if ($now > $this->getEndingTime()) {
5442  return true;
5443  }
5444  }
5445  return false;
5446  }
5447 
5453  public function getAvailableQuestions($arrFilter, $completeonly = 0)
5454  {
5455  $pluginAdmin = $GLOBALS['DIC'] ? $GLOBALS['DIC']['ilPluginAdmin'] : $GLOBALS['ilPluginAdmin'];
5456  $lng = $GLOBALS['DIC'] ? $GLOBALS['DIC']['lng'] : $GLOBALS['lng'];
5457  global $ilUser;
5458  global $ilDB;
5459 
5460  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5461  $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = true, $equal_points = false, $could_be_offline = false, $showPath = false, $with_questioncount = false));
5462  $available = "";
5463  if (count($available_pools)) {
5464  $available = " AND " . $ilDB->in('qpl_questions.obj_fi', $available_pools, false, 'integer');
5465  } else {
5466  return array();
5467  }
5468  if ($completeonly) {
5469  $available .= " AND qpl_questions.complete = " . $ilDB->quote("1", 'text');
5470  }
5471 
5472  $where = "";
5473  if (is_array($arrFilter)) {
5474  if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title'])) {
5475  $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
5476  }
5477  if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description'])) {
5478  $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
5479  }
5480  if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author'])) {
5481  $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
5482  }
5483  if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type'])) {
5484  $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
5485  }
5486  if (array_key_exists('qpl', $arrFilter) && strlen($arrFilter['qpl'])) {
5487  $where .= " AND " . $ilDB->like('object_data.title', 'text', "%%" . $arrFilter['qpl'] . "%%");
5488  }
5489  }
5490 
5491  $original_ids =&$this->getExistingQuestions();
5492  $original_clause = " qpl_questions.original_id IS NULL";
5493  if (count($original_ids)) {
5494  $original_clause = " qpl_questions.original_id IS NULL AND " . $ilDB->in('qpl_questions.question_id', $original_ids, true, 'integer');
5495  }
5496 
5497  $query_result = $ilDB->query("
5498  SELECT qpl_questions.*, qpl_questions.tstamp,
5499  qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,
5500  object_data.title parent_title
5501  FROM qpl_questions, qpl_qst_type, object_data
5502  WHERE $original_clause $available
5503  AND object_data.obj_id = qpl_questions.obj_fi
5504  AND qpl_questions.tstamp > 0
5505  AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
5506  $where
5507  ");
5508  $rows = array();
5509  $types = $this->getQuestionTypeTranslations();
5510  if ($query_result->numRows()) {
5511  while ($row = $ilDB->fetchAssoc($query_result)) {
5513 
5514  if (!$row['plugin']) {
5515  $row[ 'ttype' ] = $lng->txt($row[ "type_tag" ]);
5516 
5517  $rows[] = $row;
5518  continue;
5519  }
5520 
5521  if (!$pluginAdmin->isActive(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name'])) {
5522  continue;
5523  }
5524 
5525  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name']);
5526  $row[ 'ttype' ] = $pl->getQuestionTypeTranslation();
5527 
5528  $rows[] = $row;
5529  }
5530  }
5531  return $rows;
5532  }
5533 
5538  public function fromXML(ilQTIAssessment $assessment)
5539  {
5540  unset($_SESSION["import_mob_xhtml"]);
5541 
5542  $this->setDescription($assessment->getComment());
5543  $this->setTitle($assessment->getTitle());
5544 
5545  $this->setIntroductionEnabled(false);
5546  foreach ($assessment->objectives as $objectives) {
5547  foreach ($objectives->materials as $material) {
5548  $intro = $this->QTIMaterialToString($material);
5549  $this->setIntroduction($intro);
5550  $this->setIntroductionEnabled(strlen($intro) > 0);
5551  }
5552  }
5553 
5554  if (
5555  $assessment->getPresentationMaterial() &&
5556  $assessment->getPresentationMaterial()->getFlowMat(0) &&
5557  $assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)
5558  ) {
5559  $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)));
5560  }
5561 
5562  foreach ($assessment->assessmentcontrol as $assessmentcontrol) {
5563  switch ($assessmentcontrol->getSolutionswitch()) {
5564  case "Yes":
5565  $this->setInstantFeedbackSolution(1);
5566  break;
5567  default:
5568  $this->setInstantFeedbackSolution(0);
5569  break;
5570  }
5571  }
5572 
5573  $this->setStartingTimeEnabled(false);
5574  $this->setEndingTimeEnabled(false);
5575  $this->setPasswordEnabled(false);
5576  $this->setLimitUsersEnabled(false);
5577 
5578  foreach ($assessment->qtimetadata as $metadata) {
5579  switch ($metadata["label"]) {
5580  case "test_type":
5581  // for old tests with a test type
5582  $type = $metadata["entry"];
5583  switch ($type) {
5584  case 1:
5585  // assessment
5586  $this->setAnonymity(1);
5587  break;
5588  case 2:
5589  // self assessment
5590  break;
5591  case 4:
5592  // online exam
5593  $this->setFixedParticipants(1);
5594  $this->setListOfQuestionsSettings(7);
5595  $this->setShowSolutionPrintview(1);
5596  break;
5597  case 5:
5598  // varying random test
5599  break;
5600  }
5601  break;
5602  case "sequence_settings":
5603  $this->setSequenceSettings($metadata["entry"]);
5604  break;
5605  case "solution_details":
5606  $this->setShowSolutionDetails((int) $metadata["entry"]);
5607  break;
5608  case "print_bs_with_res":
5609  $this->setPrintBestSolutionWithResult((int) $metadata["entry"]);
5610  break;
5611  case "author":
5612  $this->setAuthor($metadata["entry"]);
5613  break;
5614  case "nr_of_tries":
5615  $this->setNrOfTries($metadata["entry"]);
5616  break;
5617  case "pass_waiting":
5618  $this->setPassWaiting($metadata["entry"]);
5619  break;
5620  case "kiosk":
5621  $this->setKiosk($metadata["entry"]);
5622  break;
5623  case "showfinalstatement":
5624  $this->setShowFinalStatement($metadata["entry"]);
5625  break;
5626  case "showinfo":
5627  $this->setShowInfo($metadata["entry"]);
5628  break;
5629  case "forcejs":
5630  $this->setForceJS($metadata["entry"]);
5631  break;
5632  case "customstyle":
5633  $this->setCustomStyle($metadata["entry"]);
5634  break;
5635 
5636  case "highscore_enabled":
5637  $this->setHighscoreEnabled($metadata["entry"]);
5638  break;
5639 
5640  case "highscore_anon":
5641  $this->setHighscoreAnon($metadata["entry"]);
5642  break;
5643 
5644  case "highscore_achieved_ts":
5645  $this->setHighscoreAchievedTS($metadata["entry"]);
5646  break;
5647 
5648  case "highscore_score":
5649  $this->setHighscoreScore($metadata["entry"]);
5650  break;
5651 
5652  case "highscore_percentage":
5653  $this->setHighscorePercentage($metadata["entry"]);
5654  break;
5655 
5656  case "highscore_hints":
5657  $this->setHighscoreHints($metadata["entry"]);
5658  break;
5659 
5660  case "highscore_wtime":
5661  $this->setHighscoreWTime($metadata["entry"]);
5662  break;
5663 
5664  case "highscore_own_table":
5665  $this->setHighscoreOwnTable($metadata["entry"]);
5666  break;
5667 
5668  case "highscore_top_table":
5669  $this->setHighscoreTopTable($metadata["entry"]);
5670  break;
5671 
5672  case "highscore_top_num":
5673  $this->setHighscoreTopNum($metadata["entry"]);
5674  break;
5675 
5676  case "hide_previous_results":
5677  if ($metadata["entry"] == 0) {
5678  $this->setUsePreviousAnswers(1);
5679  } else {
5680  $this->setUsePreviousAnswers(0);
5681  }
5682  break;
5683  case "use_previous_answers":
5684  $this->setUsePreviousAnswers($metadata["entry"]);
5685  break;
5686  case "answer_feedback":
5687  $this->setAnswerFeedback($metadata["entry"]);
5688  break;
5689  case "hide_title_points":
5690  $this->setTitleOutput($metadata["entry"]);
5691  break;
5692  case "title_output":
5693  $this->setTitleOutput($metadata["entry"]);
5694  break;
5695  case "question_set_type":
5696  $this->setQuestionSetType($metadata["entry"]);
5697  break;
5698  case "random_test":
5699  if ($metadata["entry"]) {
5700  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
5701  } else {
5702  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
5703  }
5704  break;
5705  case "results_presentation":
5706  $this->setResultsPresentation($metadata["entry"]);
5707  break;
5708  case "reset_processing_time":
5709  $this->setResetProcessingTime($metadata["entry"]);
5710  break;
5711  case "instant_verification":
5712  $this->setInstantFeedbackSolution($metadata["entry"]);
5713  break;
5714  case "instant_feedback_answer_fixation":
5715  $this->setInstantFeedbackAnswerFixationEnabled((bool) $metadata["entry"]);
5716  break;
5717  case "force_instant_feedback":
5718  $this->setForceInstantFeedbackEnabled((bool) $metadata["entry"]);
5719  break;
5720  case "answer_feedback_points":
5721  $this->setAnswerFeedbackPoints($metadata["entry"]);
5722  break;
5723  case "anonymity":
5724  $this->setAnonymity($metadata["entry"]);
5725  break;
5726  case "use_pool":
5727  $this->setPoolUsage((int) $metadata["entry"]);
5728  break;
5729  case "show_cancel":
5730  $this->setShowCancel($metadata["entry"]);
5731  break;
5732  case "show_marker":
5733  $this->setShowMarker($metadata["entry"]);
5734  break;
5735  case "fixed_participants":
5736  $this->setFixedParticipants($metadata["entry"]);
5737  break;
5738  case "score_reporting":
5739  $this->setScoreReporting($metadata["entry"]);
5740  break;
5741  case "shuffle_questions":
5742  $this->setShuffleQuestions($metadata["entry"]);
5743  break;
5744  case "count_system":
5745  $this->setCountSystem($metadata["entry"]);
5746  break;
5747  case "mc_scoring":
5748  $this->setMCScoring($metadata["entry"]);
5749  break;
5750  case "mailnotification":
5751  $this->setMailNotification($metadata["entry"]);
5752  break;
5753  case "mailnottype":
5754  $this->setMailNotificationType($metadata["entry"]);
5755  break;
5756  case "exportsettings":
5757  $this->setExportSettings($metadata['entry']);
5758  break;
5759  case "score_cutting":
5760  $this->setScoreCutting($metadata["entry"]);
5761  break;
5762  case "password":
5763  $this->setPassword($metadata["entry"]);
5764  $this->setPasswordEnabled(strlen($metadata["entry"]) > 0);
5765  break;
5766  case "allowedUsers":
5767  $this->setAllowedUsers($metadata["entry"]);
5768  $this->setLimitUsersEnabled((int) $metadata["entry"] > 0);
5769  break;
5770  case "allowedUsersTimeGap":
5771  $this->setAllowedUsersTimeGap($metadata["entry"]);
5772  break;
5773  case "pass_scoring":
5774  $this->setPassScoring($metadata["entry"]);
5775  break;
5776  case 'pass_deletion_allowed':
5777  $this->setPassDeletionAllowed((int) $metadata['entry']);
5778  break;
5779  case "show_summary":
5780  $this->setListOfQuestionsSettings($metadata["entry"]);
5781  break;
5782  case "reporting_date":
5783  $iso8601period = $metadata["entry"];
5784  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5785  $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
5786  }
5787  break;
5788  case 'enable_processing_time':
5789  $this->setEnableProcessingTime($metadata['entry']);
5790  break;
5791  case "processing_time":
5792  $this->setProcessingTime($metadata['entry']);
5793  break;
5794  case "starting_time":
5795  $iso8601period = $metadata["entry"];
5796  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5797  $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);
5798  $this->setStartingTime($date_time->get(IL_CAL_UNIX));
5799  $this->setStartingTimeEnabled(true);
5800  }
5801  break;
5802  case "ending_time":
5803  $iso8601period = $metadata["entry"];
5804  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches)) {
5805  $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);
5806  $this->setEndingTime($date_time->get(IL_CAL_UNIX));
5807  $this->setEndingTimeEnabled(true);
5808  }
5809  break;
5810  case "enable_examview":
5811  $this->setEnableExamview($metadata["entry"]);
5812  break;
5813  case 'show_examview_html':
5814  $this->setShowExamviewHtml($metadata['entry']);
5815  break;
5816  case 'show_examview_pdf':
5817  $this->setShowExamviewPdf($metadata['entry']);
5818  break;
5819  case 'redirection_mode':
5820  $this->setRedirectionMode($metadata['entry']);
5821  break;
5822  case 'redirection_url':
5823  $this->setRedirectionUrl($metadata['entry']);
5824  break;
5825  case 'examid_in_kiosk':
5826  case 'examid_in_test_pass':
5827  $this->setShowExamIdInTestPassEnabled($metadata['entry']);
5828  break;
5829  case 'show_exam_id':
5830  case 'examid_in_test_res':
5831  $this->setShowExamIdInTestResultsEnabled($metadata['entry']);
5832  break;
5833  case 'enable_archiving':
5834  $this->setEnableArchiving($metadata['entry']);
5835  break;
5836  case 'sign_submission':
5837  $this->setSignSubmission($metadata['entry']);
5838  break;
5839  case 'char_selector_availability':
5840  $this->setCharSelectorAvailability($metadata['entry']);
5841  break;
5842  case 'char_selector_definition':
5843  $this->setCharSelectorDefinition($metadata['entry']);
5844  break;
5845  case 'skill_service':
5846  $this->setSkillServiceEnabled((bool) $metadata['entry']);
5847  break;
5848  case 'result_tax_filters':
5849  $this->setResultFilterTaxIds(strlen($metadata['entry']) ? unserialize($metadata['entry']) : array());
5850  break;
5851  case 'show_grading_status':
5852  $this->setShowGradingStatusEnabled((bool) $metadata['entry']);
5853  break;
5854  case 'show_grading_mark':
5855  $this->setShowGradingMarkEnabled((bool) $metadata['entry']);
5856  break;
5857  case 'activation_limited':
5858  $this->setActivationLimited($metadata['entry']);
5859  break;
5860  case 'activation_start_time':
5861  $this->setActivationStartingTime($metadata['entry']);
5862  break;
5863  case 'activation_end_time':
5864  $this->setActivationEndingTime($metadata['entry']);
5865  break;
5866  case 'activation_visibility':
5867  $this->setActivationVisibility($metadata['entry']);
5868  break;
5869  case 'autosave':
5870  $this->setAutosave($metadata['entry']);
5871  break;
5872  case 'autosave_ival':
5873  $this->setAutosaveIval($metadata['entry']);
5874  break;
5875  case 'offer_question_hints':
5876  $this->setOfferingQuestionHintsEnabled($metadata['entry']);
5877  break;
5878  case 'instant_feedback_specific':
5879  $this->setSpecificAnswerFeedback($metadata['entry']);
5880  break;
5881  case 'obligations_enabled':
5882  $this->setObligationsEnabled($metadata['entry']);
5883  break;
5884  }
5885  if (preg_match("/mark_step_\d+/", $metadata["label"])) {
5886  $xmlmark = $metadata["entry"];
5887  preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
5888  $mark_short = $matches[1];
5889  preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
5890  $mark_official = $matches[1];
5891  preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
5892  $mark_percentage = $matches[1];
5893  preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
5894  $mark_passed = $matches[1];
5895  $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
5896  }
5897  }
5898  // handle the import of media objects in XHTML code
5899  if (is_array($_SESSION["import_mob_xhtml"])) {
5900  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
5901  include_once "./Services/RTE/classes/class.ilRTE.php";
5902  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5903  foreach ($_SESSION["import_mob_xhtml"] as $mob) {
5904  $importfile = ilObjTest::_getImportDirectory() . '/' . $_SESSION["tst_import_subdir"] . '/' . $mob["uri"];
5905  if (file_exists($importfile)) {
5906  $media_object =&ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false);
5907  ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
5908  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
5909  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
5910  } else {
5911  global $ilLog;
5912  $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
5913  }
5914  }
5915  $this->saveToDb();
5916  }
5917  }
5918 
5924  public function toXML()
5925  {
5926  include_once("./Services/Xml/classes/class.ilXmlWriter.php");
5927  $a_xml_writer = new ilXmlWriter;
5928  // set xml header
5929  $a_xml_writer->xmlHeader();
5930  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
5931  $a_xml_writer->xmlStartTag("questestinterop");
5932 
5933  $attrs = array(
5934  "ident" => "il_" . IL_INST_ID . "_tst_" . $this->getTestId(),
5935  "title" => $this->getTitle()
5936  );
5937  $a_xml_writer->xmlStartTag("assessment", $attrs);
5938  // add qti comment
5939  $a_xml_writer->xmlElement("qticomment", null, $this->getDescription());
5940 
5941  // add qti duration
5942  if ($this->enable_processing_time) {
5943  preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
5944  $a_xml_writer->xmlElement("duration", null, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
5945  }
5946 
5947  // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
5948  $a_xml_writer->xmlStartTag("qtimetadata");
5949  $a_xml_writer->xmlStartTag("qtimetadatafield");
5950  $a_xml_writer->xmlElement("fieldlabel", null, "ILIAS_VERSION");
5951  $a_xml_writer->xmlElement("fieldentry", null, $this->ilias->getSetting("ilias_version"));
5952  $a_xml_writer->xmlEndTag("qtimetadatafield");
5953 
5954  // anonymity
5955  $a_xml_writer->xmlStartTag("qtimetadatafield");
5956  $a_xml_writer->xmlElement("fieldlabel", null, "anonymity");
5957  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnonymity()));
5958  $a_xml_writer->xmlEndTag("qtimetadatafield");
5959 
5960  $a_xml_writer->xmlStartTag("qtimetadatafield");
5961  $a_xml_writer->xmlElement("fieldlabel", null, "use_pool");
5962  $a_xml_writer->xmlElement("fieldentry", null, $this->getPoolUsage() ? 1 : 0);
5963  $a_xml_writer->xmlEndTag("qtimetadatafield");
5964 
5965  // question set type (fixed, random, dynamic, ...)
5966  $a_xml_writer->xmlStartTag("qtimetadatafield");
5967  $a_xml_writer->xmlElement("fieldlabel", null, "question_set_type");
5968  $a_xml_writer->xmlElement("fieldentry", null, $this->getQuestionSetType());
5969  $a_xml_writer->xmlEndTag("qtimetadatafield");
5970 
5971  // sequence settings
5972  $a_xml_writer->xmlStartTag("qtimetadatafield");
5973  $a_xml_writer->xmlElement("fieldlabel", null, "sequence_settings");
5974  $a_xml_writer->xmlElement("fieldentry", null, $this->getSequenceSettings());
5975  $a_xml_writer->xmlEndTag("qtimetadatafield");
5976 
5977  // author
5978  $a_xml_writer->xmlStartTag("qtimetadatafield");
5979  $a_xml_writer->xmlElement("fieldlabel", null, "author");
5980  $a_xml_writer->xmlElement("fieldentry", null, $this->getAuthor());
5981  $a_xml_writer->xmlEndTag("qtimetadatafield");
5982 
5983  // reset processing time
5984  $a_xml_writer->xmlStartTag("qtimetadatafield");
5985  $a_xml_writer->xmlElement("fieldlabel", null, "reset_processing_time");
5986  $a_xml_writer->xmlElement("fieldentry", null, $this->getResetProcessingTime());
5987  $a_xml_writer->xmlEndTag("qtimetadatafield");
5988 
5989  // count system
5990  $a_xml_writer->xmlStartTag("qtimetadatafield");
5991  $a_xml_writer->xmlElement("fieldlabel", null, "count_system");
5992  $a_xml_writer->xmlElement("fieldentry", null, $this->getCountSystem());
5993  $a_xml_writer->xmlEndTag("qtimetadatafield");
5994 
5995  // multiple choice scoring
5996  $a_xml_writer->xmlStartTag("qtimetadatafield");
5997  $a_xml_writer->xmlElement("fieldlabel", null, "mc_scoring");
5998  $a_xml_writer->xmlElement("fieldentry", null, $this->getMCScoring());
5999  $a_xml_writer->xmlEndTag("qtimetadatafield");
6000 
6001  // multiple choice scoring
6002  $a_xml_writer->xmlStartTag("qtimetadatafield");
6003  $a_xml_writer->xmlElement("fieldlabel", null, "score_cutting");
6004  $a_xml_writer->xmlElement("fieldentry", null, $this->getScoreCutting());
6005  $a_xml_writer->xmlEndTag("qtimetadatafield");
6006 
6007  // multiple choice scoring
6008  $a_xml_writer->xmlStartTag("qtimetadatafield");
6009  $a_xml_writer->xmlElement("fieldlabel", null, "password");
6010  $a_xml_writer->xmlElement("fieldentry", null, $this->getPassword());
6011  $a_xml_writer->xmlEndTag("qtimetadatafield");
6012 
6013  // allowed users
6014  $a_xml_writer->xmlStartTag("qtimetadatafield");
6015  $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsers");
6016  $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsers());
6017  $a_xml_writer->xmlEndTag("qtimetadatafield");
6018 
6019  // allowed users time gap
6020  $a_xml_writer->xmlStartTag("qtimetadatafield");
6021  $a_xml_writer->xmlElement("fieldlabel", null, "allowedUsersTimeGap");
6022  $a_xml_writer->xmlElement("fieldentry", null, $this->getAllowedUsersTimeGap());
6023  $a_xml_writer->xmlEndTag("qtimetadatafield");
6024 
6025  // pass scoring
6026  $a_xml_writer->xmlStartTag("qtimetadatafield");
6027  $a_xml_writer->xmlElement("fieldlabel", null, "pass_scoring");
6028  $a_xml_writer->xmlElement("fieldentry", null, $this->getPassScoring());
6029  $a_xml_writer->xmlEndTag("qtimetadatafield");
6030 
6031  $a_xml_writer->xmlStartTag('qtimetadatafield');
6032  $a_xml_writer->xmlElement('fieldlabel', null, 'pass_deletion_allowed');
6033  $a_xml_writer->xmlElement('fieldentry', null, (int) $this->isPassDeletionAllowed());
6034  $a_xml_writer->xmlEndTag('qtimetadatafield');
6035 
6036  // score reporting date
6037  if ($this->getReportingDate()) {
6038  $a_xml_writer->xmlStartTag("qtimetadatafield");
6039  $a_xml_writer->xmlElement("fieldlabel", null, "reporting_date");
6040  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6041  $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]));
6042  $a_xml_writer->xmlEndTag("qtimetadatafield");
6043  }
6044  // number of tries
6045  $a_xml_writer->xmlStartTag("qtimetadatafield");
6046  $a_xml_writer->xmlElement("fieldlabel", null, "nr_of_tries");
6047  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getNrOfTries()));
6048  $a_xml_writer->xmlEndTag("qtimetadatafield");
6049 
6050  // pass_waiting
6051  $a_xml_writer->xmlStartTag("qtimetadatafield");
6052  $a_xml_writer->xmlElement("fieldlabel", null, "pass_waiting");
6053  $a_xml_writer->xmlElement("fieldentry", null, $this->getPassWaiting());
6054  $a_xml_writer->xmlEndTag("qtimetadatafield");
6055 
6056  // kiosk
6057  $a_xml_writer->xmlStartTag("qtimetadatafield");
6058  $a_xml_writer->xmlElement("fieldlabel", null, "kiosk");
6059  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getKiosk()));
6060  $a_xml_writer->xmlEndTag("qtimetadatafield");
6061 
6062 
6063  //redirection_mode
6064  $a_xml_writer->xmlStartTag('qtimetadatafield');
6065  $a_xml_writer->xmlElement("fieldlabel", null, "redirection_mode");
6066  $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionMode());
6067  $a_xml_writer->xmlEndTag("qtimetadatafield");
6068 
6069  //redirection_url
6070  $a_xml_writer->xmlStartTag('qtimetadatafield');
6071  $a_xml_writer->xmlElement("fieldlabel", null, "redirection_url");
6072  $a_xml_writer->xmlElement("fieldentry", null, $this->getRedirectionUrl());
6073  $a_xml_writer->xmlEndTag("qtimetadatafield");
6074 
6075  // use previous answers
6076  $a_xml_writer->xmlStartTag("qtimetadatafield");
6077  $a_xml_writer->xmlElement("fieldlabel", null, "use_previous_answers");
6078  $a_xml_writer->xmlElement("fieldentry", null, $this->getUsePreviousAnswers());
6079  $a_xml_writer->xmlEndTag("qtimetadatafield");
6080 
6081  // hide title points
6082  $a_xml_writer->xmlStartTag("qtimetadatafield");
6083  $a_xml_writer->xmlElement("fieldlabel", null, "title_output");
6084  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getTitleOutput()));
6085  $a_xml_writer->xmlEndTag("qtimetadatafield");
6086 
6087  // results presentation
6088  $a_xml_writer->xmlStartTag("qtimetadatafield");
6089  $a_xml_writer->xmlElement("fieldlabel", null, "results_presentation");
6090  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getResultsPresentation()));
6091  $a_xml_writer->xmlEndTag("qtimetadatafield");
6092 
6093  // examid in test pass
6094  $a_xml_writer->xmlStartTag("qtimetadatafield");
6095  $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_pass");
6096  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestPassEnabled()));
6097  $a_xml_writer->xmlEndTag("qtimetadatafield");
6098 
6099  // examid in kiosk
6100  $a_xml_writer->xmlStartTag("qtimetadatafield");
6101  $a_xml_writer->xmlElement("fieldlabel", null, "examid_in_test_res");
6102  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->isShowExamIdInTestResultsEnabled()));
6103  $a_xml_writer->xmlEndTag("qtimetadatafield");
6104 
6105  // solution details
6106  $a_xml_writer->xmlStartTag("qtimetadatafield");
6107  $a_xml_writer->xmlElement("fieldlabel", null, "show_summary");
6108  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getListOfQuestionsSettings()));
6109  $a_xml_writer->xmlEndTag("qtimetadatafield");
6110 
6111  // solution details
6112  $a_xml_writer->xmlStartTag("qtimetadatafield");
6113  $a_xml_writer->xmlElement("fieldlabel", null, "score_reporting");
6114  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getScoreReporting()));
6115  $a_xml_writer->xmlEndTag("qtimetadatafield");
6116 
6117  $a_xml_writer->xmlStartTag("qtimetadatafield");
6118  $a_xml_writer->xmlElement("fieldlabel", null, "solution_details");
6119  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails());
6120  $a_xml_writer->xmlEndTag("qtimetadatafield");
6121  $a_xml_writer->xmlStartTag("qtimetadatafield");
6122  $a_xml_writer->xmlElement("fieldlabel", null, "print_bs_with_res");
6123  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails() ? (int) $this->isBestSolutionPrintedWithResult() : 0);
6124  $a_xml_writer->xmlEndTag("qtimetadatafield");
6125 
6126  // solution details
6127  $a_xml_writer->xmlStartTag("qtimetadatafield");
6128  $a_xml_writer->xmlElement("fieldlabel", null, "instant_verification");
6129  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getInstantFeedbackSolution()));
6130  $a_xml_writer->xmlEndTag("qtimetadatafield");
6131 
6132  // answer specific feedback
6133  $a_xml_writer->xmlStartTag("qtimetadatafield");
6134  $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback");
6135  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedback()));
6136  $a_xml_writer->xmlEndTag("qtimetadatafield");
6137 
6138  // answer specific feedback of reached points
6139  $a_xml_writer->xmlStartTag("qtimetadatafield");
6140  $a_xml_writer->xmlElement("fieldlabel", null, "answer_feedback_points");
6141  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getAnswerFeedbackPoints()));
6142  $a_xml_writer->xmlEndTag("qtimetadatafield");
6143 
6144  // instant response answer freezing
6145  $a_xml_writer->xmlStartTag("qtimetadatafield");
6146  $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6147  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6148  $a_xml_writer->xmlEndTag("qtimetadatafield");
6149 
6150  // instant response forced
6151  $a_xml_writer->xmlStartTag("qtimetadatafield");
6152  $a_xml_writer->xmlElement("fieldlabel", null, "force_instant_feedback");
6153  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isForceInstantFeedbackEnabled());
6154  $a_xml_writer->xmlEndTag("qtimetadatafield");
6155 
6156 
6157  // highscore
6158  $highscore_metadata = array(
6159  'highscore_enabled' => array('value' => $this->getHighscoreEnabled()),
6160  'highscore_anon' => array('value' => $this->getHighscoreAnon()),
6161  'highscore_achieved_ts' => array('value' => $this->getHighscoreAchievedTS()),
6162  'highscore_score' => array('value' => $this->getHighscoreScore()),
6163  'highscore_percentage' => array('value' => $this->getHighscorePercentage()),
6164  'highscore_hints' => array('value' => $this->getHighscoreHints()),
6165  'highscore_wtime' => array('value' => $this->getHighscoreWTime()),
6166  'highscore_own_table' => array('value' => $this->getHighscoreOwnTable()),
6167  'highscore_top_table' => array('value' => $this->getHighscoreTopTable()),
6168  'highscore_top_num' => array('value' => $this->getHighscoreTopNum()),
6169  );
6170  foreach ($highscore_metadata as $label => $data) {
6171  $a_xml_writer->xmlStartTag("qtimetadatafield");
6172  $a_xml_writer->xmlElement("fieldlabel", null, $label);
6173  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $data['value']));
6174  $a_xml_writer->xmlEndTag("qtimetadatafield");
6175  }
6176 
6177  // show cancel
6178  $a_xml_writer->xmlStartTag("qtimetadatafield");
6179  $a_xml_writer->xmlElement("fieldlabel", null, "show_cancel");
6180  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowCancel()));
6181  $a_xml_writer->xmlEndTag("qtimetadatafield");
6182 
6183  // show marker
6184  $a_xml_writer->xmlStartTag("qtimetadatafield");
6185  $a_xml_writer->xmlElement("fieldlabel", null, "show_marker");
6186  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShowMarker()));
6187  $a_xml_writer->xmlEndTag("qtimetadatafield");
6188 
6189  // fixed participants
6190  $a_xml_writer->xmlStartTag("qtimetadatafield");
6191  $a_xml_writer->xmlElement("fieldlabel", null, "fixed_participants");
6192  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getFixedParticipants()));
6193  $a_xml_writer->xmlEndTag("qtimetadatafield");
6194 
6195  // show final statement
6196  $a_xml_writer->xmlStartTag("qtimetadatafield");
6197  $a_xml_writer->xmlElement("fieldlabel", null, "showfinalstatement");
6198  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6199  $a_xml_writer->xmlEndTag("qtimetadatafield");
6200 
6201  // show introduction only
6202  $a_xml_writer->xmlStartTag("qtimetadatafield");
6203  $a_xml_writer->xmlElement("fieldlabel", null, "showinfo");
6204  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6205  $a_xml_writer->xmlEndTag("qtimetadatafield");
6206 
6207  // mail notification
6208  $a_xml_writer->xmlStartTag("qtimetadatafield");
6209  $a_xml_writer->xmlElement("fieldlabel", null, "mailnotification");
6210  $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotification());
6211  $a_xml_writer->xmlEndTag("qtimetadatafield");
6212 
6213  // mail notification type
6214  $a_xml_writer->xmlStartTag("qtimetadatafield");
6215  $a_xml_writer->xmlElement("fieldlabel", null, "mailnottype");
6216  $a_xml_writer->xmlElement("fieldentry", null, $this->getMailNotificationType());
6217  $a_xml_writer->xmlEndTag("qtimetadatafield");
6218 
6219  // export settings
6220  $a_xml_writer->xmlStartTag("qtimetadatafield");
6221  $a_xml_writer->xmlElement("fieldlabel", null, "exportsettings");
6222  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getExportSettings());
6223  $a_xml_writer->xmlEndTag("qtimetadatafield");
6224 
6225  // force JavaScript
6226  $a_xml_writer->xmlStartTag("qtimetadatafield");
6227  $a_xml_writer->xmlElement("fieldlabel", null, "forcejs");
6228  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6229  $a_xml_writer->xmlEndTag("qtimetadatafield");
6230 
6231  // custom style
6232  $a_xml_writer->xmlStartTag("qtimetadatafield");
6233  $a_xml_writer->xmlElement("fieldlabel", null, "customstyle");
6234  $a_xml_writer->xmlElement("fieldentry", null, $this->getCustomStyle());
6235  $a_xml_writer->xmlEndTag("qtimetadatafield");
6236 
6237  // shuffle questions
6238  $a_xml_writer->xmlStartTag("qtimetadatafield");
6239  $a_xml_writer->xmlElement("fieldlabel", null, "shuffle_questions");
6240  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getShuffleQuestions()));
6241  $a_xml_writer->xmlEndTag("qtimetadatafield");
6242 
6243  // processing time
6244  $a_xml_writer->xmlStartTag("qtimetadatafield");
6245  $a_xml_writer->xmlElement("fieldlabel", null, "processing_time");
6246  $a_xml_writer->xmlElement("fieldentry", null, $this->getProcessingTime());
6247  $a_xml_writer->xmlEndTag("qtimetadatafield");
6248 
6249  // enable_examview
6250  $a_xml_writer->xmlStartTag("qtimetadatafield");
6251  $a_xml_writer->xmlElement("fieldlabel", null, "enable_examview");
6252  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableExamview());
6253  $a_xml_writer->xmlEndTag("qtimetadatafield");
6254 
6255  // show_examview_html
6256  $a_xml_writer->xmlStartTag("qtimetadatafield");
6257  $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_html");
6258  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewHtml());
6259  $a_xml_writer->xmlEndTag("qtimetadatafield");
6260 
6261  // show_examview_pdf
6262  $a_xml_writer->xmlStartTag("qtimetadatafield");
6263  $a_xml_writer->xmlElement("fieldlabel", null, "show_examview_pdf");
6264  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowExamviewPdf());
6265  $a_xml_writer->xmlEndTag("qtimetadatafield");
6266 
6267  // enable_archiving
6268  $a_xml_writer->xmlStartTag("qtimetadatafield");
6269  $a_xml_writer->xmlElement("fieldlabel", null, "enable_archiving");
6270  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableArchiving());
6271  $a_xml_writer->xmlEndTag("qtimetadatafield");
6272 
6273  // sign_submission
6274  $a_xml_writer->xmlStartTag("qtimetadatafield");
6275  $a_xml_writer->xmlElement("fieldlabel", null, "sign_submission");
6276  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSignSubmission());
6277  $a_xml_writer->xmlEndTag("qtimetadatafield");
6278 
6279  // char_selector_availability
6280  $a_xml_writer->xmlStartTag("qtimetadatafield");
6281  $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_availability");
6282  $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getCharSelectorAvailability()));
6283  $a_xml_writer->xmlEndTag("qtimetadatafield");
6284 
6285  // char_selector_definition
6286  $a_xml_writer->xmlStartTag("qtimetadatafield");
6287  $a_xml_writer->xmlElement("fieldlabel", null, "char_selector_definition");
6288  $a_xml_writer->xmlElement("fieldentry", null, $this->getCharSelectorDefinition());
6289  $a_xml_writer->xmlEndTag("qtimetadatafield");
6290 
6291  // skill_service
6292  $a_xml_writer->xmlStartTag("qtimetadatafield");
6293  $a_xml_writer->xmlElement("fieldlabel", null, "skill_service");
6294  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isSkillServiceEnabled());
6295  $a_xml_writer->xmlEndTag("qtimetadatafield");
6296 
6297  // result_tax_filters
6298  $a_xml_writer->xmlStartTag("qtimetadatafield");
6299  $a_xml_writer->xmlElement("fieldlabel", null, "result_tax_filters");
6300  $a_xml_writer->xmlElement("fieldentry", null, serialize((array) $this->getResultFilterTaxIds()));
6301  $a_xml_writer->xmlEndTag("qtimetadatafield");
6302 
6303  // show_grading_status
6304  $a_xml_writer->xmlStartTag("qtimetadatafield");
6305  $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_status");
6306  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingStatusEnabled());
6307  $a_xml_writer->xmlEndTag("qtimetadatafield");
6308 
6309  // show_grading_mark
6310  $a_xml_writer->xmlStartTag("qtimetadatafield");
6311  $a_xml_writer->xmlElement("fieldlabel", null, "show_grading_mark");
6312  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isShowGradingMarkEnabled());
6313  $a_xml_writer->xmlEndTag("qtimetadatafield");
6314 
6315 
6316  // starting time
6317  if ($this->getStartingTime()) {
6318  $a_xml_writer->xmlStartTag("qtimetadatafield");
6319  $a_xml_writer->xmlElement("fieldlabel", null, "starting_time");
6320  $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->starting_time);
6321  $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6322  $a_xml_writer->xmlEndTag("qtimetadatafield");
6323  }
6324  // ending time
6325  if ($this->getEndingTime()) {
6326  $a_xml_writer->xmlStartTag("qtimetadatafield");
6327  $a_xml_writer->xmlElement("fieldlabel", null, "ending_time");
6328  $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->ending_time);
6329  $a_xml_writer->xmlElement("fieldentry", null, $backward_compatibility_format);
6330  $a_xml_writer->xmlEndTag("qtimetadatafield");
6331  }
6332 
6333 
6334  //activation_limited
6335  $a_xml_writer->xmlStartTag("qtimetadatafield");
6336  $a_xml_writer->xmlElement("fieldlabel", null, "activation_limited");
6337  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isActivationLimited());
6338  $a_xml_writer->xmlEndTag("qtimetadatafield");
6339 
6340  //activation_start_time
6341  $a_xml_writer->xmlStartTag("qtimetadatafield");
6342  $a_xml_writer->xmlElement("fieldlabel", null, "activation_start_time");
6343  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationStartingTime());
6344  $a_xml_writer->xmlEndTag("qtimetadatafield");
6345 
6346  //activation_end_time
6347  $a_xml_writer->xmlStartTag("qtimetadatafield");
6348  $a_xml_writer->xmlElement("fieldlabel", null, "activation_end_time");
6349  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationEndingTime());
6350  $a_xml_writer->xmlEndTag("qtimetadatafield");
6351 
6352  //activation_visibility
6353  $a_xml_writer->xmlStartTag("qtimetadatafield");
6354  $a_xml_writer->xmlElement("fieldlabel", null, "activation_visibility");
6355  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getActivationVisibility());
6356  $a_xml_writer->xmlEndTag("qtimetadatafield");
6357 
6358  // autosave
6359  $a_xml_writer->xmlStartTag("qtimetadatafield");
6360  $a_xml_writer->xmlElement("fieldlabel", null, "autosave");
6361  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosave());
6362  $a_xml_writer->xmlEndTag("qtimetadatafield");
6363 
6364  // autosave_ival
6365  $a_xml_writer->xmlStartTag("qtimetadatafield");
6366  $a_xml_writer->xmlElement("fieldlabel", null, "autosave_ival");
6367  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getAutosaveIval());
6368  $a_xml_writer->xmlEndTag("qtimetadatafield");
6369 
6370  //offer_question_hints
6371  $a_xml_writer->xmlStartTag("qtimetadatafield");
6372  $a_xml_writer->xmlElement("fieldlabel", null, "offer_question_hints");
6373  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isOfferingQuestionHintsEnabled());
6374  $a_xml_writer->xmlEndTag("qtimetadatafield");
6375 
6376  //instant_feedback_specific
6377  $a_xml_writer->xmlStartTag("qtimetadatafield");
6378  $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_specific");
6379  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getSpecificAnswerFeedback());
6380  $a_xml_writer->xmlEndTag("qtimetadatafield");
6381 
6382  //instant_feedback_answer_fixation
6383  $a_xml_writer->xmlStartTag("qtimetadatafield");
6384  $a_xml_writer->xmlElement("fieldlabel", null, "instant_feedback_answer_fixation");
6385  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->isInstantFeedbackAnswerFixationEnabled());
6386  $a_xml_writer->xmlEndTag("qtimetadatafield");
6387 
6388  //obligations_enabled
6389  $a_xml_writer->xmlStartTag("qtimetadatafield");
6390  $a_xml_writer->xmlElement("fieldlabel", null, "obligations_enabled");
6391  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->areObligationsEnabled());
6392  $a_xml_writer->xmlEndTag("qtimetadatafield");
6393 
6394  //enable_processing_time
6395  $a_xml_writer->xmlStartTag("qtimetadatafield");
6396  $a_xml_writer->xmlElement("fieldlabel", null, "enable_processing_time");
6397  $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getEnableProcessingTime());
6398  $a_xml_writer->xmlEndTag("qtimetadatafield");
6399 
6400  foreach ($this->mark_schema->mark_steps as $index => $mark) {
6401  // mark steps
6402  $a_xml_writer->xmlStartTag("qtimetadatafield");
6403  $a_xml_writer->xmlElement("fieldlabel", null, "mark_step_$index");
6404  $a_xml_writer->xmlElement("fieldentry", null, sprintf(
6405  "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
6406  $mark->getShortName(),
6407  $mark->getOfficialName(),
6408  $mark->getMinimumLevel(),
6409  $mark->getPassed()
6410  ));
6411  $a_xml_writer->xmlEndTag("qtimetadatafield");
6412  }
6413  $a_xml_writer->xmlEndTag("qtimetadata");
6414 
6415  // add qti objectives
6416  $a_xml_writer->xmlStartTag("objectives");
6417  $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6418  $a_xml_writer->xmlEndTag("objectives");
6419 
6420  // add qti assessmentcontrol
6421  if ($this->getInstantFeedbackSolution() == 1) {
6422  $attrs = array(
6423  "solutionswitch" => "Yes"
6424  );
6425  } else {
6426  $attrs = null;
6427  }
6428  $a_xml_writer->xmlElement("assessmentcontrol", $attrs, null);
6429 
6430  if (strlen($this->getFinalStatement())) {
6431  // add qti presentation_material
6432  $a_xml_writer->xmlStartTag("presentation_material");
6433  $a_xml_writer->xmlStartTag("flow_mat");
6434  $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6435  $a_xml_writer->xmlEndTag("flow_mat");
6436  $a_xml_writer->xmlEndTag("presentation_material");
6437  }
6438 
6439  $attrs = array(
6440  "ident" => "1"
6441  );
6442  $a_xml_writer->xmlElement("section", $attrs, null);
6443  $a_xml_writer->xmlEndTag("assessment");
6444  $a_xml_writer->xmlEndTag("questestinterop");
6445 
6446  $xml = $a_xml_writer->xmlDumpMem(false);
6447  return $xml;
6448  }
6449 
6454  protected function buildIso8601PeriodFromUnixtimeForExportCompatibility($unix_timestamp)
6455  {
6456  $date_time_unix = new ilDateTime($unix_timestamp, IL_CAL_UNIX);
6457  $date_time = $date_time_unix->get(IL_CAL_DATETIME);
6458  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $date_time, $matches);
6459  $iso8601_period = sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]);
6460  return $iso8601_period;
6461  }
6462 
6469  public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6470  {
6471  global $ilBench;
6472 
6473  $this->mob_ids = array();
6474  $this->file_ids = array();
6475 
6476  // MetaData
6477  $this->exportXMLMetaData($a_xml_writer);
6478 
6479  // PageObjects
6480  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Page Objects");
6481  $ilBench->start("ContentObjectExport", "exportPageObjects");
6482  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6483  $ilBench->stop("ContentObjectExport", "exportPageObjects");
6484  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Page Objects");
6485 
6486  // MediaObjects
6487  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Media Objects");
6488  $ilBench->start("ContentObjectExport", "exportMediaObjects");
6489  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6490  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6491  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Media Objects");
6492 
6493  // FileItems
6494  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export File Items");
6495  $ilBench->start("ContentObjectExport", "exportFileItems");
6496  $this->exportFileItems($a_target_dir, $expLog);
6497  $ilBench->stop("ContentObjectExport", "exportFileItems");
6498  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export File Items");
6499  }
6500 
6507  public function exportXMLMetaData(&$a_xml_writer)
6508  {
6509  include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6510  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6511  $md2xml->setExportMode(true);
6512  $md2xml->startExport();
6513  $a_xml_writer->appendXML($md2xml->getXML());
6514  }
6515 
6521  public function modifyExportIdentifier($a_tag, $a_param, $a_value)
6522  {
6523  if ($a_tag == "Identifier" && $a_param == "Entry") {
6524  include_once "./Services/Utilities/classes/class.ilUtil.php";
6525  $a_value = ilUtil::insertInstIntoID($a_value);
6526  }
6527 
6528  return $a_value;
6529  }
6530 
6531 
6538  public function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6539  {
6540  global $ilBench;
6541 
6542  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6543 
6544  foreach ($this->questions as $question_id) {
6545  $ilBench->start("ContentObjectExport", "exportPageObject");
6546  $expLog->write(date("[y-m-d H:i:s] ") . "Page Object " . $question_id);
6547 
6548  $attrs = array();
6549  $a_xml_writer->xmlStartTag("PageObject", $attrs);
6550 
6551 
6552  // export xml to writer object
6553  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6554  include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
6555  $page_object = new ilAssQuestionPage($question_id);
6556  $page_object->buildDom();
6557  $page_object->insertInstIntoIDs($a_inst);
6558  $mob_ids = $page_object->collectMediaObjects(false);
6559  require_once 'Services/COPage/classes/class.ilPCFileList.php';
6560  $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
6561  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6562  $xml = str_replace("&", "&amp;", $xml);
6563  $a_xml_writer->appendXML($xml);
6564  $page_object->freeDom();
6565  unset($page_object);
6566 
6567  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6568 
6569  // collect media objects
6570  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6571  //$mob_ids = $page_obj->getMediaObjectIDs();
6572  foreach ($mob_ids as $mob_id) {
6573  $this->mob_ids[$mob_id] = $mob_id;
6574  }
6575  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6576 
6577  // collect all file items
6578  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6579  //$file_ids = $page_obj->getFileItemIds();
6580  foreach ($file_ids as $file_id) {
6581  $this->file_ids[$file_id] = $file_id;
6582  }
6583  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6584 
6585  $a_xml_writer->xmlEndTag("PageObject");
6586  //unset($page_obj);
6587 
6588  $ilBench->stop("ContentObjectExport", "exportPageObject");
6589  }
6590  }
6591 
6598  public function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6599  {
6600  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6601 
6602  foreach ($this->mob_ids as $mob_id) {
6603  $expLog->write(date("[y-m-d H:i:s] ") . "Media Object " . $mob_id);
6604  if (ilObjMediaObject::_exists($mob_id)) {
6605  $media_obj = new ilObjMediaObject($mob_id);
6606  $media_obj->exportXML($a_xml_writer, $a_inst);
6607  $media_obj->exportFiles($a_target_dir);
6608  unset($media_obj);
6609  }
6610  }
6611  }
6612 
6617  public function exportFileItems($a_target_dir, &$expLog)
6618  {
6619  include_once "./Modules/File/classes/class.ilObjFile.php";
6620 
6621  foreach ($this->file_ids as $file_id) {
6622  $expLog->write(date("[y-m-d H:i:s] ") . "File Item " . $file_id);
6623  $file_obj = new ilObjFile($file_id, false);
6624  $file_obj->export($a_target_dir);
6625  unset($file_obj);
6626  }
6627  }
6628 
6633  public function getImportMapping()
6634  {
6635  if (!is_array($this->import_mapping)) {
6636  return array();
6637  } else {
6638  return $this->import_mapping;
6639  }
6640  }
6641 
6645  public function canEditEctsGrades()
6646  {
6647  return $this->canShowEctsGrades() && $this->canEditMarks();
6648  }
6649 
6653  public function canShowEctsGrades()
6654  {
6655  return $this->getReportingDate();
6656  }
6657 
6661  public function getECTSGrade($passed_array, $reached_points, $max_points)
6662  {
6663  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);
6664  }
6665 
6669  public static function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6670  {
6671  include_once "./Modules/Test/classes/class.ilStatistics.php";
6672  // calculate the median
6673  $passed_statistics = new ilStatistics();
6674  $passed_statistics->setData($points_passed);
6675  $ects_percentiles = array(
6676  "A" => $passed_statistics->quantile($a),
6677  "B" => $passed_statistics->quantile($b),
6678  "C" => $passed_statistics->quantile($c),
6679  "D" => $passed_statistics->quantile($d),
6680  "E" => $passed_statistics->quantile($e)
6681  );
6682  if (count($points_passed) && ($reached_points >= $ects_percentiles["A"])) {
6683  return "A";
6684  } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["B"])) {
6685  return "B";
6686  } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["C"])) {
6687  return "C";
6688  } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["D"])) {
6689  return "D";
6690  } elseif (count($points_passed) && ($reached_points >= $ects_percentiles["E"])) {
6691  return "E";
6692  } elseif (strcmp($fx, "") != 0) {
6693  if ($max_points > 0) {
6694  $percentage = ($reached_points / $max_points) * 100.0;
6695  if ($percentage < 0) {
6696  $percentage = 0.0;
6697  }
6698  } else {
6699  $percentage = 0.0;
6700  }
6701  if ($percentage >= $fx) {
6702  return "FX";
6703  } else {
6704  return "F";
6705  }
6706  } else {
6707  return "F";
6708  }
6709  }
6710 
6714  public function checkMarks()
6715  {
6716  return $this->mark_schema->checkMarks();
6717  }
6718 
6722  public function getMarkSchema()
6723  {
6724  return $this->mark_schema;
6725  }
6726 
6730  public function getMarkSchemaForeignId()
6731  {
6732  return $this->getTestId();
6733  }
6734 
6737  public function onMarkSchemaSaved()
6738  {
6744  global $ilDB, $ilPluginAdmin, $tree;
6745 
6746  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
6747  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
6748  $this->saveCompleteStatus($testQuestionSetConfigFactory->getQuestionSetConfig());
6749 
6750  if ($this->participantDataExist()) {
6751  $this->recalculateScores(true);
6752  }
6753  }
6754 
6758  public function canEditMarks()
6759  {
6760  $total = $this->evalTotalPersons();
6761  if ($total > 0) {
6762  if ($this->getReportingDate()) {
6763  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches)) {
6764  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
6765  $now = time();
6766  if ($now < $epoch_time) {
6767  return true;
6768  }
6769  }
6770  }
6771  return false;
6772  } else {
6773  return true;
6774  }
6775  }
6776 
6784  public function setAuthor($author = "")
6785  {
6786  $this->author = $author;
6787  }
6788 
6798  public function saveAuthorToMetadata($a_author = "")
6799  {
6800  $md = new ilMD($this->getId(), 0, $this->getType());
6801  $md_life =&$md->getLifecycle();
6802  if (!$md_life) {
6803  if (strlen($a_author) == 0) {
6804  global $ilUser;
6805  $a_author = $ilUser->getFullname();
6806  }
6807 
6808  $md_life =&$md->addLifecycle();
6809  $md_life->save();
6810  $con =&$md_life->addContribute();
6811  $con->setRole("Author");
6812  $con->save();
6813  $ent =&$con->addEntity();
6814  $ent->setEntity($a_author);
6815  $ent->save();
6816  }
6817  }
6818 
6824  public function createMetaData()
6825  {
6826  parent::createMetaData();
6827  $this->saveAuthorToMetadata();
6828  }
6829 
6837  public function getAuthor()
6838  {
6839  $author = array();
6840  include_once "./Services/MetaData/classes/class.ilMD.php";
6841  $md = new ilMD($this->getId(), 0, $this->getType());
6842  $md_life =&$md->getLifecycle();
6843  if ($md_life) {
6844  $ids =&$md_life->getContributeIds();
6845  foreach ($ids as $id) {
6846  $md_cont =&$md_life->getContribute($id);
6847  if (strcmp($md_cont->getRole(), "Author") == 0) {
6848  $entids =&$md_cont->getEntityIds();
6849  foreach ($entids as $entid) {
6850  $md_ent =&$md_cont->getEntity($entid);
6851  array_push($author, $md_ent->getEntity());
6852  }
6853  }
6854  }
6855  }
6856  return join($author, ",");
6857  }
6858 
6866  public static function _lookupAuthor($obj_id)
6867  {
6868  $author = array();
6869  include_once "./Services/MetaData/classes/class.ilMD.php";
6870  $md = new ilMD($obj_id, 0, "tst");
6871  $md_life =&$md->getLifecycle();
6872  if ($md_life) {
6873  $ids =&$md_life->getContributeIds();
6874  foreach ($ids as $id) {
6875  $md_cont =&$md_life->getContribute($id);
6876  if (strcmp($md_cont->getRole(), "Author") == 0) {
6877  $entids =&$md_cont->getEntityIds();
6878  foreach ($entids as $entid) {
6879  $md_ent =&$md_cont->getEntity($entid);
6880  array_push($author, $md_ent->getEntity());
6881  }
6882  }
6883  }
6884  }
6885  return join($author, ",");
6886  }
6887 
6894  public static function _getAvailableTests($use_object_id = false)
6895  {
6896  global $ilUser;
6897  global $ilDB;
6898 
6899  $result_array = array();
6900  $tests = ilUtil::_getObjectsByOperations("tst", "write", $ilUser->getId(), -1);
6901  if (count($tests)) {
6902  $titles = ilObject::_prepareCloneSelection($tests, "tst");
6903  foreach ($tests as $ref_id) {
6904  if ($use_object_id) {
6905  $obj_id = ilObject::_lookupObjId($ref_id);
6906  $result_array[$obj_id] = $titles[$ref_id];
6907  } else {
6908  $result_array[$ref_id] = $titles[$ref_id];
6909  }
6910  }
6911  }
6912  return $result_array;
6913  }
6914 
6923  public function cloneObject($a_target_id, $a_copy_id = 0, $a_omit_tree = false)
6924  {
6925  global $ilLog, $tree, $ilDB, $ilPluginAdmin;
6926 
6927  $this->loadFromDb();
6928 
6929  // Copy settings
6931  $newObj = parent::cloneObject($a_target_id, $a_copy_id, $a_omit_tree);
6932  $newObj->setTmpCopyWizardCopyId($a_copy_id);
6933  $this->cloneMetaData($newObj);
6934 
6935  //copy online status if object is not the root copy object
6936  $cp_options = ilCopyWizardOptions::_getInstance($a_copy_id);
6937 
6938  if (!$cp_options->isRootNode($this->getRefId())) {
6939  $newObj->setOnline($this->isOnline());
6940  }
6941 
6942  $newObj->setAnonymity($this->getAnonymity());
6943  $newObj->setAnswerFeedback($this->getAnswerFeedback());
6944  $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
6945  $newObj->setAuthor($this->getAuthor());
6946  $newObj->setLimitUsersEnabled($this->isLimitUsersEnabled());
6947  $newObj->setAllowedUsers($this->getAllowedUsers());
6948  $newObj->setAllowedUsersTimeGap($this->getAllowedUsersTimeGap());
6949  $newObj->setCountSystem($this->getCountSystem());
6950  $newObj->setECTSFX($this->getECTSFX());
6951  $newObj->setECTSGrades($this->getECTSGrades());
6952  $newObj->setECTSOutput($this->getECTSOutput());
6953  $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
6954  $newObj->setEndingTimeEnabled($this->isEndingTimeEnabled());
6955  $newObj->setEndingTime($this->getEndingTime());
6956  $newObj->setFixedParticipants($this->getFixedParticipants());
6957  $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
6958  $newObj->setIntroductionEnabled($this->isIntroductionEnabled());
6959  $newObj->setIntroduction($this->getIntroduction());
6960  $newObj->setFinalStatement($this->getFinalStatement());
6961  $newObj->setShowInfo($this->getShowInfo());
6962  $newObj->setForceJS($this->getForceJS());
6963  $newObj->setCustomStyle($this->getCustomStyle());
6964  $newObj->setKiosk($this->getKiosk());
6965  $newObj->setShowFinalStatement($this->getShowFinalStatement());
6966  $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
6967  $newObj->setMCScoring($this->getMCScoring());
6968  $newObj->setMailNotification($this->getMailNotification());
6969  $newObj->setMailNotificationType($this->getMailNotificationType());
6970  $newObj->setNrOfTries($this->getNrOfTries());
6971  $newObj->setPassScoring($this->getPassScoring());
6972  $newObj->setPasswordEnabled($this->isPasswordEnabled());
6973  $newObj->setPassword($this->getPassword());
6974  $newObj->setProcessingTime($this->getProcessingTime());
6975  $newObj->setQuestionSetType($this->getQuestionSetType());
6976  $newObj->setReportingDate($this->getReportingDate());
6977  $newObj->setResetProcessingTime($this->getResetProcessingTime());
6978  $newObj->setResultsPresentation($this->getResultsPresentation());
6979  $newObj->setScoreCutting($this->getScoreCutting());
6980  $newObj->setScoreReporting($this->getScoreReporting());
6981  $newObj->setSequenceSettings($this->getSequenceSettings());
6982  $newObj->setShowCancel($this->getShowCancel());
6983  $newObj->setShowMarker($this->getShowMarker());
6984  $newObj->setShuffleQuestions($this->getShuffleQuestions());
6985  $newObj->setStartingTimeEnabled($this->isStartingTimeEnabled());
6986  $newObj->setStartingTime($this->getStartingTime());
6987  $newObj->setTitleOutput($this->getTitleOutput());
6988  $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
6989  $newObj->setRedirectionMode($this->getRedirectionMode());
6990  $newObj->setRedirectionUrl($this->getRedirectionUrl());
6991  $newObj->setCertificateVisibility($this->getCertificateVisibility());
6992  $newObj->mark_schema = clone $this->mark_schema;
6993  $newObj->setEnabledViewMode($this->getEnabledViewMode());
6994  $newObj->setTemplate($this->getTemplate());
6995  $newObj->setPoolUsage($this->getPoolUsage());
6996  $newObj->setPrintBestSolutionWithResult($this->isBestSolutionPrintedWithResult());
6997  $newObj->setShowExamIdInTestPassEnabled($this->isShowExamIdInTestPassEnabled());
6998  $newObj->setShowExamIdInTestResultsEnabled($this->isShowExamIdInTestResultsEnabled());
6999  $newObj->setEnableExamView($this->getEnableExamview());
7000  $newObj->setShowExamViewHtml($this->getShowExamviewHtml());
7001  $newObj->setShowExamViewPdf($this->getShowExamviewPdf());
7002  $newObj->setEnableArchiving($this->getEnableArchiving());
7003  $newObj->setSignSubmission($this->getSignSubmission());
7004  $newObj->setCharSelectorAvailability((int) $this->getCharSelectorAvailability());
7005  $newObj->setCharSelectorDefinition($this->getCharSelectorDefinition());
7006  $newObj->setSkillServiceEnabled($this->isSkillServiceEnabled());
7007  $newObj->setResultFilterTaxIds($this->getResultFilterTaxIds());
7008  $newObj->setInstantFeedbackAnswerFixationEnabled($this->isInstantFeedbackAnswerFixationEnabled());
7009  $newObj->setForceInstantFeedbackEnabled($this->isForceInstantFeedbackEnabled());
7010  $newObj->setAutosave($this->getAutosave());
7011  $newObj->setAutosaveIval($this->getAutosaveIval());
7012  $newObj->setOfferingQuestionHintsEnabled($this->isOfferingQuestionHintsEnabled());
7013  $newObj->setSpecificAnswerFeedback($this->getSpecificAnswerFeedback());
7014  if ($this->isPassWaitingEnabled()) {
7015  $newObj->setPassWaiting($this->getPassWaiting());
7016  }
7017  $newObj->setObligationsEnabled($this->areObligationsEnabled());
7018  $newObj->saveToDb();
7019 
7020  // clone certificate
7021  include_once "./Services/Certificate/classes/class.ilCertificate.php";
7022  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
7023  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
7024  $newcert = new ilCertificate(new ilTestCertificateAdapter($newObj));
7025  $cert->cloneCertificate($newcert);
7026 
7027  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
7028  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7029  $testQuestionSetConfigFactory->getQuestionSetConfig()->cloneQuestionSetRelatedData($newObj);
7030 
7031  require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdList.php';
7032  $skillLevelThresholdList = new ilTestSkillLevelThresholdList($ilDB);
7033  $skillLevelThresholdList->setTestId($this->getTestId());
7034  $skillLevelThresholdList->loadFromDb();
7035  $skillLevelThresholdList->cloneListForTest($newObj->getTestId());
7036 
7037  $newObj->saveToDb();
7038  $newObj->updateMetaData();// #14467
7039 
7040  include_once('./Services/Tracking/classes/class.ilLPObjSettings.php');
7041  $obj_settings = new ilLPObjSettings($this->getId());
7042  $obj_settings->cloneSettings($newObj->getId());
7043 
7044  return $newObj;
7045  }
7046 
7053  public function getQuestionCount()
7054  {
7055  $num = 0;
7056 
7057  if ($this->isRandomTest()) {
7058  global $tree, $ilDB, $ilPluginAdmin;
7059 
7060  $questionSetConfig = new ilTestRandomQuestionSetConfig(
7061  $tree,
7062  $ilDB,
7063  $ilPluginAdmin,
7064  $this
7065  );
7066 
7067  $questionSetConfig->loadFromDb();
7068 
7069  if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
7070  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php';
7071  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetBuilderWithAmountPerPool.php';
7072  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php';
7073 
7074  $sourcePoolDefinitionList = new ilTestRandomQuestionSetSourcePoolDefinitionList(
7075  $ilDB,
7076  $this,
7078  );
7079 
7080  $sourcePoolDefinitionList->loadDefinitions();
7081 
7082  $num = $sourcePoolDefinitionList->getQuestionAmount();
7083  } else {
7084  $num = $questionSetConfig->getQuestionAmountPerTest();
7085  }
7086  } else {
7087  $num = count($this->questions);
7088  }
7089 
7090  return $num;
7091  }
7092 
7100  public function logAction($logtext = "", $question_id = "")
7101  {
7102  global $ilUser;
7103 
7104  $original_id = "";
7105  if (strcmp($question_id, "") != 0) {
7106  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7107  $original_id = assQuestion::_getOriginalId($question_id);
7108  }
7109  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7110  ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, true, $this->getRefId());
7111  }
7112 
7120  public static function _getObjectIDFromTestID($test_id)
7121  {
7122  global $ilDB;
7123  $object_id = false;
7124  $result = $ilDB->queryF(
7125  "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7126  array('integer'),
7127  array($test_id)
7128  );
7129  if ($result->numRows()) {
7130  $row = $ilDB->fetchAssoc($result);
7131  $object_id = $row["obj_fi"];
7132  }
7133  return $object_id;
7134  }
7135 
7143  public static function _getObjectIDFromActiveID($active_id)
7144  {
7145  global $ilDB;
7146  $object_id = false;
7147  $result = $ilDB->queryF(
7148  "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",
7149  array('integer'),
7150  array($active_id)
7151  );
7152  if ($result->numRows()) {
7153  $row = $ilDB->fetchAssoc($result);
7154  $object_id = $row["obj_fi"];
7155  }
7156  return $object_id;
7157  }
7158 
7166  public static function _getTestIDFromObjectID($object_id)
7167  {
7168  global $ilDB;
7169  $test_id = false;
7170  $result = $ilDB->queryF(
7171  "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7172  array('integer'),
7173  array($object_id)
7174  );
7175  if ($result->numRows()) {
7176  $row = $ilDB->fetchAssoc($result);
7177  $test_id = $row["test_id"];
7178  }
7179  return $test_id;
7180  }
7181 
7190  public function getTextAnswer($active_id, $question_id, $pass = null)
7191  {
7192  global $ilDB;
7193 
7194  $res = "";
7195  if (($active_id) && ($question_id)) {
7196  if (is_null($pass)) {
7197  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7198  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7199  }
7200  $result = $ilDB->queryF(
7201  "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7202  array('integer', 'integer', 'integer'),
7203  array($active_id, $question_id, $pass)
7204  );
7205  if ($result->numRows() == 1) {
7206  $row = $ilDB->fetchAssoc($result);
7207  $res = $row["value1"];
7208  }
7209  }
7210  return $res;
7211  }
7212 
7220  public function getQuestiontext($question_id)
7221  {
7222  global $ilDB;
7223 
7224  $res = "";
7225  if ($question_id) {
7226  $result = $ilDB->queryF(
7227  "SELECT question_text FROM qpl_questions WHERE question_id = %s",
7228  array('integer'),
7229  array($question_id)
7230  );
7231  if ($result->numRows() == 1) {
7232  $row = $ilDB->fetchAssoc($result);
7233  $res = $row["question_text"];
7234  }
7235  }
7236  return $res;
7237  }
7238 
7245  public function &getInvitedUsers($user_id="", $order="login, lastname, firstname")
7246  {
7247  global $ilDB;
7248 
7249  $result_array = array();
7250 
7251  if ($this->getAnonymity()) {
7252  if (is_numeric($user_id)) {
7253  $result = $ilDB->queryF(
7254  "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7255  "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 " .
7256  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7257  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7258  "ORDER BY $order",
7259  array('text', 'text', 'text', 'integer', 'integer'),
7260  array("", $this->lng->txt("anonymous"), "", $this->getTestId(), $user_id)
7261  );
7262  } else {
7263  $result = $ilDB->queryF(
7264  "SELECT tst_active.active_id, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7265  "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 " .
7266  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7267  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7268  "ORDER BY $order",
7269  array('text', 'text', 'text', 'integer'),
7270  array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7271  );
7272  }
7273  } else {
7274  if (is_numeric($user_id)) {
7275  $result = $ilDB->queryF(
7276  "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7277  "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 " .
7278  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7279  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7280  "ORDER BY $order",
7281  array('integer', 'integer'),
7282  array($this->getTestId(), $user_id)
7283  );
7284  } else {
7285  $result = $ilDB->queryF(
7286  "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7287  "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 " .
7288  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7289  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7290  "ORDER BY $order",
7291  array('integer'),
7292  array($this->getTestId())
7293  );
7294  }
7295  }
7296  $result_array = array();
7297  while ($row = $ilDB->fetchAssoc($result)) {
7298  $result_array[$row['usr_id']]= $row;
7299  }
7300  return $result_array;
7301  }
7302 
7309  public function &getTestParticipants()
7310  {
7311  global $ilDB;
7312 
7313  if ($this->getAnonymity()) {
7314  $query = "
7315  SELECT tst_active.active_id,
7316  tst_active.tries,
7317  tst_active.user_fi usr_id,
7318  %s login,
7319  %s lastname,
7320  %s firstname,
7321  tst_active.submitted test_finished,
7322  usr_data.matriculation,
7323  usr_data.active,
7324  tst_active.lastindex,
7325  COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7326  FROM tst_active
7327  LEFT JOIN usr_data
7328  ON tst_active.user_fi = usr_data.usr_id
7329  WHERE tst_active.test_fi = %s
7330  ORDER BY usr_data.lastname
7331  ";
7332  $result = $ilDB->queryF(
7333  $query,
7334  array('text', 'text', 'text', 'integer'),
7335  array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7336  );
7337  } else {
7338  $query = "
7339  SELECT tst_active.active_id,
7340  tst_active.tries,
7341  tst_active.user_fi usr_id,
7342  usr_data.login,
7343  usr_data.lastname,
7344  usr_data.firstname,
7345  tst_active.submitted test_finished,
7346  usr_data.matriculation,
7347  usr_data.active,
7348  tst_active.lastindex,
7349  COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7350  FROM tst_active
7351  LEFT JOIN usr_data
7352  ON tst_active.user_fi = usr_data.usr_id
7353  WHERE tst_active.test_fi = %s
7354  ORDER BY usr_data.lastname
7355  ";
7356  $result = $ilDB->queryF(
7357  $query,
7358  array('integer'),
7359  array($this->getTestId())
7360  );
7361  }
7362  $data = array();
7363  while ($row = $ilDB->fetchAssoc($result)) {
7364  $data[$row['active_id']] = $row;
7365  }
7366  foreach ($data as $index => $participant) {
7367  if (strlen(trim($participant["firstname"] . $participant["lastname"])) == 0) {
7368  $data[$index]["lastname"] = $this->lng->txt("deleted_user");
7369  }
7370  }
7371  return $data;
7372  }
7373 
7374  public function getTestParticipantsForManualScoring($filter = null)
7375  {
7376  global $ilDB;
7377 
7378  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7380  if (count($scoring) == 0) {
7381  return array();
7382  }
7383 
7384  $participants =&$this->getTestParticipants();
7385  $filtered_participants = array();
7386  foreach ($participants as $active_id => $participant) {
7387  $qstType_IN_manScoreableQstTypes = $ilDB->in('qpl_questions.question_type_fi', $scoring, false, 'integer');
7388 
7389  $queryString = "
7390  SELECT tst_test_result.manual
7391 
7392  FROM tst_test_result
7393 
7394  INNER JOIN qpl_questions
7395  ON tst_test_result.question_fi = qpl_questions.question_id
7396 
7397  WHERE tst_test_result.active_fi = %s
7398  AND $qstType_IN_manScoreableQstTypes
7399  ";
7400 
7401  $result = $ilDB->queryF(
7402  $queryString,
7403  array("integer"),
7404  array($active_id)
7405  );
7406 
7407  $count = $result->numRows();
7408 
7409  if ($count > 0) {
7410  switch ($filter) {
7411  case 1: // only active users
7412  if ($participant->active) {
7413  $filtered_participants[$active_id] = $participant;
7414  }
7415  break;
7416  case 2: // only inactive users
7417  if (!$participant->active) {
7418  $filtered_participants[$active_id] = $participant;
7419  }
7420  break;
7421  case 3: // all users
7422  $filtered_participants[$active_id] = $participant;
7423  break;
7424  case 4:
7425  // already scored participants
7426  //$found = 0;
7427  //while ($row = $ilDB->fetchAssoc($result))
7428  //{
7429  // if ($row["manual"]) $found++;
7430  //}
7431  //if ($found == $count)
7432  //{
7433  //$filtered_participants[$active_id] = $participant;
7434  //}
7435  //else
7436  //{
7437  $assessmentSetting = new ilSetting("assessment");
7438  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7439  if ($manscoring_done) {
7440  $filtered_participants[$active_id] = $participant;
7441  }
7442  //}
7443  break;
7444  case 5:
7445  // unscored participants
7446  //$found = 0;
7447  //while ($row = $ilDB->fetchAssoc($result))
7448  //{
7449  // if ($row["manual"]) $found++;
7450  //}
7451  //if ($found == 0)
7452  //{
7453  $assessmentSetting = new ilSetting("assessment");
7454  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7455  if (!$manscoring_done) {
7456  $filtered_participants[$active_id] = $participant;
7457  }
7458  //}
7459  break;
7460  case 6:
7461  // partially scored participants
7462  $found = 0;
7463  while ($row = $ilDB->fetchAssoc($result)) {
7464  if ($row["manual"]) {
7465  $found++;
7466  }
7467  }
7468  if (($found > 0) && ($found < $count)) {
7469  $filtered_participants[$active_id] = $participant;
7470  }
7471  break;
7472  default:
7473  $filtered_participants[$active_id] = $participant;
7474  break;
7475  }
7476  }
7477  }
7478  return $filtered_participants;
7479  }
7480 
7488  public function &getUserData($ids)
7489  {
7490  global $ilDB;
7491 
7492  if (!is_array($ids) || count($ids) ==0) {
7493  return array();
7494  }
7495 
7496  if ($this->getAnonymity()) {
7497  $result = $ilDB->queryF(
7498  "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",
7499  array('text', 'text', 'text'),
7500  array("", $this->lng->txt("anonymous"), "")
7501  );
7502  } else {
7503  $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");
7504  }
7505 
7506  $result_array = array();
7507  while ($row = $ilDB->fetchAssoc($result)) {
7508  $result_array[$row["usr_id"]]= $row;
7509  }
7510  return $result_array;
7511  }
7512 
7513  public function &getGroupData($ids)
7514  {
7515  if (!is_array($ids) || count($ids) ==0) {
7516  return array();
7517  }
7518  $result = array();
7519  foreach ($ids as $ref_id) {
7520  $obj_id = ilObject::_lookupObjId($ref_id);
7521  $result[$ref_id] = array("ref_id" => $ref_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7522  }
7523  return $result;
7524  }
7525 
7526  public function &getRoleData($ids)
7527  {
7528  if (!is_array($ids) || count($ids) ==0) {
7529  return array();
7530  }
7531  $result = array();
7532  foreach ($ids as $obj_id) {
7533  $result[$obj_id] = array("obj_id" => $obj_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7534  }
7535  return $result;
7536  }
7537 
7538 
7545  public function inviteGroup($group_id)
7546  {
7547  include_once "./Modules/Group/classes/class.ilObjGroup.php";
7548  $group = new ilObjGroup($group_id);
7549  $members = $group->getGroupMemberIds();
7550  include_once './Services/User/classes/class.ilObjUser.php';
7551  foreach ($members as $user_id) {
7552  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7553  }
7554  }
7555 
7562  public function inviteRole($role_id)
7563  {
7564  global $rbacreview;
7565  $members = $rbacreview->assignedUsers($role_id);
7566  include_once './Services/User/classes/class.ilObjUser.php';
7567  foreach ($members as $user_id) {
7568  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7569  }
7570  }
7571 
7572 
7573 
7580  public function disinviteUser($user_id)
7581  {
7582  global $ilDB;
7583 
7584  $affectedRows = $ilDB->manipulateF(
7585  "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7586  array('integer', 'integer'),
7587  array($this->getTestId(), $user_id)
7588  );
7589  }
7590 
7597  public function inviteUser($user_id, $client_ip="")
7598  {
7599  global $ilDB;
7600 
7601  $affectedRows = $ilDB->manipulateF(
7602  "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7603  array('integer', 'integer'),
7604  array($this->getTestId(), $user_id)
7605  );
7606  $affectedRows = $ilDB->manipulateF(
7607  "INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
7608  array('integer', 'integer', 'text', 'integer'),
7609  array($this->getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : null, time())
7610  );
7611  }
7612 
7613 
7614  public function setClientIP($user_id, $client_ip)
7615  {
7616  global $ilDB;
7617 
7618  $affectedRows = $ilDB->manipulateF(
7619  "UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
7620  array('text', 'integer', 'integer', 'integer'),
7621  array((strlen($client_ip)) ? $client_ip : null, time(), $this->getTestId(), $user_id)
7622  );
7623  }
7624 
7630  public static function _getSolvedQuestions($active_id, $question_fi = null)
7631  {
7632  global $ilDB;
7633  if (is_numeric($question_fi)) {
7634  $result = $ilDB->queryF(
7635  "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
7636  array('integer', 'integer'),
7637  array($active_id, $question_fi)
7638  );
7639  } else {
7640  $result = $ilDB->queryF(
7641  "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
7642  array('integer'),
7643  array($active_id)
7644  );
7645  }
7646  $result_array = array();
7647  while ($row = $ilDB->fetchAssoc($result)) {
7648  $result_array[$row["question_fi"]]= $row;
7649  }
7650  return $result_array;
7651  }
7652 
7653 
7657  public function setQuestionSetSolved($value, $question_id, $user_id)
7658  {
7659  global $ilDB;
7660 
7661  $active_id = $this->getActiveIdOfUser($user_id);
7662  $affectedRows = $ilDB->manipulateF(
7663  "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
7664  array('integer', 'integer'),
7665  array($active_id, $question_id)
7666  );
7667  $affectedRows = $ilDB->manipulateF(
7668  "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
7669  array('integer', 'integer', 'integer'),
7670  array($value, $question_id, $active_id)
7671  );
7672  }
7673 
7677  public function isTestFinished($active_id)
7678  {
7679  global $ilDB;
7680 
7681  $result = $ilDB->queryF(
7682  "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
7683  array('integer', 'integer'),
7684  array($active_id, 1)
7685  );
7686  return $result->numRows() == 1;
7687  }
7688 
7692  public function isActiveTestSubmitted($user_id = null)
7693  {
7694  global $ilUser;
7695  global $ilDB;
7696 
7697  if (!is_numeric($user_id)) {
7698  $user_id = $ilUser->getId();
7699  }
7700 
7701  $result = $ilDB->queryF(
7702  "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
7703  array('integer', 'integer', 'integer'),
7704  array($this->getTestId(), $user_id, 1)
7705  );
7706  return $result->numRows() == 1;
7707  }
7708 
7712  public function hasNrOfTriesRestriction()
7713  {
7714  return $this->getNrOfTries() != 0;
7715  }
7716 
7717 
7723  public function isNrOfTriesReached($tries)
7724  {
7725  return $tries >= (int) $this->getNrOfTries();
7726  }
7727 
7728 
7737  public function getAllTestResults($participants, $prepareForCSV = true)
7738  {
7739  $results = array();
7740  $row = array(
7741  "user_id" => $this->lng->txt("user_id"),
7742  "matriculation" => $this->lng->txt("matriculation"),
7743  "lastname" => $this->lng->txt("lastname"),
7744  "firstname" => $this->lng->txt("firstname"),
7745  "login" =>$this->lng->txt("login"),
7746  "reached_points" => $this->lng->txt("tst_reached_points"),
7747  "max_points" => $this->lng->txt("tst_maximum_points"),
7748  "percent_value" => $this->lng->txt("tst_percent_solved"),
7749  "mark" => $this->lng->txt("tst_mark"),
7750  "ects" => $this->lng->txt("ects_grade")
7751  );
7752  $results[] = $row;
7753  if (count($participants)) {
7754  if ($this->getECTSOutput()) {
7755  $passed_array =&$this->getTotalPointsPassedArray();
7756  }
7757  foreach ($participants as $active_id => $user_rec) {
7758  $mark = $ects_mark = '';
7759  $row = array();
7760  $reached_points = 0;
7761  $max_points = 0;
7762  foreach ($this->questions as $value) {
7763  $question =&ilObjTest::_instanciateQuestion($value);
7764  if (is_object($question)) {
7765  $max_points += $question->getMaximumPoints();
7766  $reached_points += $question->getReachedPoints($active_id);
7767  }
7768  }
7769  if ($max_points > 0) {
7770  $percentvalue = $reached_points / $max_points;
7771  if ($percentvalue < 0) {
7772  $percentvalue = 0.0;
7773  }
7774  } else {
7775  $percentvalue = 0;
7776  }
7777  $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
7778  $passed = "";
7779  if ($mark_obj) {
7780  $mark = $mark_obj->getOfficialName();
7781  if ($this->getECTSOutput()) {
7782  $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
7783  }
7784  }
7785  if ($this->getAnonymity()) {
7786  $user_rec['firstname'] = "";
7787  $user_rec['lastname'] = $this->lng->txt("anonymous");
7788  }
7789  $row = array(
7790  "user_id"=>$user_rec['usr_id'],
7791  "matriculation" => $user_rec['matriculation'],
7792  "lastname" => $user_rec['lastname'],
7793  "firstname" => $user_rec['firstname'],
7794  "login"=>$user_rec['login'],
7795  "reached_points" => $reached_points,
7796  "max_points" => $max_points,
7797  "percent_value" => $percentvalue,
7798  "mark" => $mark,
7799  "ects" => $ects_mark
7800  );
7801  $results[] = $prepareForCSV ? $this->processCSVRow($row, true) : $row;
7802  }
7803  }
7804  return $results;
7805  }
7806 
7817  public function &processCSVRow($row, $quoteAll = false, $separator = ";")
7818  {
7819  $resultarray = array();
7820  foreach ($row as $rowindex => $entry) {
7821  $surround = false;
7822  if ($quoteAll) {
7823  $surround = true;
7824  }
7825  if (strpos($entry, "\"") !== false) {
7826  $entry = str_replace("\"", "\"\"", $entry);
7827  $surround = true;
7828  }
7829  if (strpos($entry, $separator) !== false) {
7830  $surround = true;
7831  }
7832  // replace all CR LF with LF (for Excel for Windows compatibility
7833  $entry = str_replace(chr(13) . chr(10), chr(10), $entry);
7834 
7835  if ($surround) {
7836  $entry = "\"" . $entry . "\"";
7837  }
7838 
7839  $resultarray[$rowindex] = $entry;
7840  }
7841  return $resultarray;
7842  }
7843 
7852  public static function _getPass($active_id)
7853  {
7854  global $ilDB;
7855  $result = $ilDB->queryF(
7856  "SELECT tries FROM tst_active WHERE active_id = %s",
7857  array('integer'),
7858  array($active_id)
7859  );
7860  if ($result->numRows()) {
7861  $row = $ilDB->fetchAssoc($result);
7862  return $row["tries"];
7863  } else {
7864  return 0;
7865  }
7866  }
7867 
7877  public static function _getMaxPass($active_id)
7878  {
7879  global $ilDB;
7880  $result = $ilDB->queryF(
7881  "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
7882  array('integer'),
7883  array($active_id)
7884  );
7885  if ($result->numRows()) {
7886  $row = $ilDB->fetchAssoc($result);
7887  $max = $row["maxpass"];
7888  } else {
7889  $max = null;
7890  }
7891  return $max;
7892  }
7893 
7899  public static function _getBestPass($active_id)
7900  {
7901  global $ilDB;
7902 
7903  $result = $ilDB->queryF(
7904  "SELECT * FROM tst_pass_result WHERE active_fi = %s",
7905  array('integer'),
7906  array($active_id)
7907  );
7908  if ($result->numRows()) {
7909  $bestrow = null;
7910  $bestfactor = 0;
7911  while ($row = $ilDB->fetchAssoc($result)) {
7912  if ($row["maxpoints"] > 0) {
7913  $factor = $row["points"] / $row["maxpoints"];
7914  } else {
7915  $factor = 0;
7916  }
7917 
7918  if ($factor > $bestfactor) {
7919  $bestrow = $row;
7920  $bestfactor = $factor;
7921  }
7922  }
7923  if (is_array($bestrow)) {
7924  return $bestrow["pass"];
7925  } else {
7926  return 0;
7927  }
7928  } else {
7929  return 0;
7930  }
7931  }
7932 
7941  public static function _getResultPass($active_id)
7942  {
7943  $counted_pass = null;
7944  if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS) {
7945  $counted_pass = ilObjTest::_getBestPass($active_id);
7946  } else {
7947  $counted_pass = ilObjTest::_getMaxPass($active_id);
7948  }
7949  return $counted_pass;
7950  }
7951 
7961  public function getAnsweredQuestionCount($active_id, $pass = null)
7962  {
7963  if ($this->isDynamicTest()) {
7964  global $tree, $ilDB, $lng, $ilPluginAdmin;
7965 
7966  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
7967  $testSessionFactory = new ilTestSessionFactory($this);
7968  $testSession = $testSessionFactory->getSession($active_id);
7969 
7970  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
7971  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
7972  $testSequence = $testSequenceFactory->getSequenceByTestSession($testSession);
7973 
7974  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
7975  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
7976  $dynamicQuestionSetConfig->loadFromDb();
7977 
7978  $testSequence->loadFromDb($dynamicQuestionSetConfig);
7979  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
7980 
7981  return $testSequence->getTrackedQuestionCount();
7982  }
7983 
7984  if ($this->isRandomTest()) {
7985  $this->loadQuestions($active_id, $pass);
7986  }
7987  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7988  $workedthrough = 0;
7989  foreach ($this->questions as $value) {
7990  if (assQuestion::_isWorkedThrough($active_id, $value, $pass)) {
7991  $workedthrough += 1;
7992  }
7993  }
7994  return $workedthrough;
7995  }
7996 
8003  public static function lookupPassResultsUpdateTimestamp($active_id, $pass)
8004  {
8005  global $ilDB;
8006 
8007  if (is_null($pass)) {
8008  $pass = 0;
8009  }
8010 
8011  $query = "
8012  SELECT tst_pass_result.tstamp pass_res_tstamp,
8013  tst_test_result.tstamp quest_res_tstamp
8014 
8015  FROM tst_pass_result
8016 
8017  LEFT JOIN tst_test_result
8018  ON tst_test_result.active_fi = tst_pass_result.active_fi
8019  AND tst_test_result.pass = tst_pass_result.pass
8020 
8021  WHERE tst_pass_result.active_fi = %s
8022  AND tst_pass_result.pass = %s
8023 
8024  ORDER BY tst_test_result.tstamp DESC
8025  ";
8026 
8027  $result = $ilDB->queryF(
8028  $query,
8029  array('integer', 'integer'),
8030  array($active_id, $pass)
8031  );
8032 
8033  while ($row = $ilDB->fetchAssoc($result)) {
8034  if ($row['qres_tstamp']) {
8035  return $row['quest_res_tstamp'];
8036  }
8037 
8038  return $row['pass_res_tstamp'];
8039  }
8040 
8041  return 0;
8042  }
8043 
8052  public function isExecutable($testSession, $user_id, $allowPassIncrease = false)
8053  {
8054  $result = array(
8055  "executable" => true,
8056  "errormessage" => ""
8057  );
8058  if (!$this->startingTimeReached()) {
8059  $result["executable"] = false;
8060  $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getStartingTime(), IL_CAL_UNIX)));
8061  return $result;
8062  }
8063  if ($this->endingTimeReached()) {
8064  $result["executable"] = false;
8065  $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getEndingTime(), IL_CAL_UNIX)));
8066  return $result;
8067  }
8068 
8069  $active_id = $this->getActiveIdOfUser($user_id);
8070 
8071  if ($this->getEnableProcessingTime()) {
8072  if ($active_id > 0) {
8073  $starting_time = $this->getStartingTimeOfUser($active_id);
8074  if ($starting_time !== false) {
8075  if ($this->isMaxProcessingTimeReached($starting_time, $active_id)) {
8076  if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > (self::_getPass($active_id)+1)))) {
8077  // a test pass was quitted because the maximum processing time was reached, but the time
8078  // will be resetted for future passes, so if there are more passes allowed, the participant may
8079  // start the test again.
8080  // This code block is only called when $allowPassIncrease is TRUE which only happens when
8081  // the test info page is opened. Otherwise this will lead to unexpected results!
8082  $testSession->increasePass();
8083  $testSession->setLastSequence(0);
8084  $testSession->saveToDb();
8085  } else {
8086  $result["executable"] = false;
8087  $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8088  }
8089  return $result;
8090  }
8091  }
8092  }
8093  }
8094  require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8095  $testPassesSelector = new ilTestPassesSelector($GLOBALS['ilDB'], $this);
8096  $testPassesSelector->setActiveId($active_id);
8097  $testPassesSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8098 
8099  if ($this->hasNrOfTriesRestriction() && ($active_id > 0)) {
8100  $closedPasses = $testPassesSelector->getClosedPasses();
8101 
8102  if (count($closedPasses) >= $this->getNrOfTries()) {
8103  $result["executable"] = false;
8104  $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8105  return $result;
8106  }
8107  }
8108  if ($this->isPassWaitingEnabled() && $testPassesSelector->getLastFinishedPass() !== null) {
8109  $lastPass = $testPassesSelector->getLastFinishedPassTimestamp();
8110  if ($lastPass && strlen($this->getPassWaiting())) {
8111  $pass_waiting_string = $this->getPassWaiting();
8112  $time_values = explode(":", $pass_waiting_string);
8113  $next_pass_allowed = strtotime('+ ' . $time_values[0] . ' Months + ' . $time_values[1] . ' Days + ' . $time_values[2] . ' Hours' . $time_values[3] . ' Minutes', $lastPass);
8114 
8115  if (time() < $next_pass_allowed) {
8116  $date = ilDatePresentation::formatDate(new ilDateTime($next_pass_allowed, IL_CAL_UNIX));
8117 
8118  $result["executable"] = false;
8119  $result["errormessage"] = sprintf($this->lng->txt('wait_for_next_pass_hint_msg'), $date);
8120  return $result;
8121  }
8122  }
8123  }
8124  return $result;
8125  }
8126 
8134  public function canViewResults()
8135  {
8136  // this logic was implemented before, it got stabled only for now
8137  // this method is not as exact as it's required, it's to be replaced in the long time
8138 
8139  switch ($this->getScoreReporting()) {
8140  case self::SCORE_REPORTING_IMMIDIATLY:
8141  case self::SCORE_REPORTING_FINISHED: // this isn't excact enough
8142 
8143  return true;
8144 
8145  case self::SCORE_REPORTING_DATE:
8146 
8147  if (!$this->getReportingDate()) {
8148  return false;
8149  }
8150 
8151  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches)) {
8152  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8153  $now = time();
8154  if ($now < $epoch_time) {
8155  return false;
8156  }
8157  }
8158 
8159  return true;
8160  }
8161 
8162  return false;
8163  }
8164 
8166  {
8167  $active_id = $testSession->getActiveId();
8168  if ($active_id > 0) {
8169  $starting_time = $this->getStartingTimeOfUser($active_id);
8170  }
8171  $notimeleft = false;
8172  if ($starting_time !== false) {
8173  if ($this->isMaxProcessingTimeReached($starting_time, $active_id)) {
8174  $notimeleft = true;
8175  }
8176  }
8177  $result = true;
8178  if (!$this->isTestFinishedToViewResults($active_id, $testSession->getPass()) && ($this->getScoreReporting() == REPORT_AFTER_TEST)) {
8179  $result = false;
8180  }
8181  if (($this->endingTimeReached()) || $notimeleft) {
8182  $result = true;
8183  }
8184  $result = $result & $this->canViewResults();
8185  return $result;
8186  }
8187 
8195  public function getStartingTimeOfUser($active_id, $pass = null)
8196  {
8197  global $ilDB;
8198 
8199  if ($active_id < 1) {
8200  return false;
8201  }
8202  if ($pass === null) {
8203  $pass = ($this->getResetProcessingTime()) ? self::_getPass($active_id) : 0;
8204  }
8205  $result = $ilDB->queryF(
8206  "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
8207  array('integer', 'integer'),
8208  array($active_id, $pass)
8209  );
8210  if ($result->numRows()) {
8211  $row = $ilDB->fetchAssoc($result);
8212  if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches)) {
8213  return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8214  } else {
8215  return time();
8216  }
8217  } else {
8218  return time();
8219  }
8220  }
8221 
8230  public function isMaxProcessingTimeReached($starting_time, $active_id)
8231  {
8232  if ($this->getEnableProcessingTime()) {
8233  $processing_time = $this->getProcessingTimeInSeconds($active_id);
8234  $now = time();
8235  if ($now > ($starting_time + $processing_time)) {
8236  return true;
8237  } else {
8238  return false;
8239  }
8240  } else {
8241  return false;
8242  }
8243  }
8244 
8245  public function &getTestQuestions()
8246  {
8247  global $ilDB;
8248 
8249  $query = "
8250  SELECT questions.*,
8251  questtypes.type_tag,
8252  tstquest.sequence,
8253  tstquest.obligatory,
8254  origquest.obj_fi orig_obj_fi
8255 
8256  FROM qpl_questions questions
8257 
8258  INNER JOIN qpl_qst_type questtypes
8259  ON questtypes.question_type_id = questions.question_type_fi
8260 
8261  INNER JOIN tst_test_question tstquest
8262  ON tstquest.question_fi = questions.question_id
8263 
8264  LEFT JOIN qpl_questions origquest
8265  ON origquest.question_id = questions.original_id
8266 
8267  WHERE tstquest.test_fi = %s
8268 
8269  ORDER BY tstquest.sequence
8270  ";
8271 
8272  $query_result = $ilDB->queryF(
8273  $query,
8274  array('integer'),
8275  array($this->getTestId())
8276  );
8277 
8278  $questions = array();
8279 
8280  while ($row = $ilDB->fetchAssoc($query_result)) {
8281  $question = $row;
8282 
8283  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8284 
8285  $questions[] = $question;
8286  }
8287 
8288  return $questions;
8289  }
8290 
8291  public function checkQuestionParent($questionId)
8292  {
8293  global $DIC; /* @var ILIAS\DI\Container $DIC */
8294 
8295  $row = $DIC->database()->fetchAssoc($DIC->database()->queryF(
8296  "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
8297  array('integer', 'integer'),
8298  array($questionId, $this->getId())
8299  ));
8300 
8301  return (bool) $row['cnt'];
8302  }
8303 
8307  public function getPotentialRandomTestQuestions()
8308  {
8312  global $ilDB;
8313 
8314  $query = "
8315  SELECT questions.*,
8316  questtypes.type_tag,
8317  origquest.obj_fi orig_obj_fi
8318 
8319  FROM qpl_questions questions
8320 
8321  INNER JOIN qpl_qst_type questtypes
8322  ON questtypes.question_type_id = questions.question_type_fi
8323 
8324  INNER JOIN tst_rnd_cpy tstquest
8325  ON tstquest.qst_fi = questions.question_id
8326 
8327  LEFT JOIN qpl_questions origquest
8328  ON origquest.question_id = questions.original_id
8329 
8330  WHERE tstquest.tst_fi = %s
8331  ";
8332 
8333  $query_result = $ilDB->queryF(
8334  $query,
8335  array('integer'),
8336  array($this->getTestId())
8337  );
8338 
8339  $questions = array();
8340 
8341  while ($row = $ilDB->fetchAssoc($query_result)) {
8342  $question = $row;
8343 
8344  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8345 
8346  $questions[] = $question;
8347  }
8348 
8349  return $questions;
8350  }
8351 
8358  public function getShuffleQuestions()
8359  {
8360  return ($this->shuffle_questions) ? 1 : 0;
8361  }
8362 
8369  public function setShuffleQuestions($a_shuffle)
8370  {
8371  $this->shuffle_questions = ($a_shuffle) ? 1 : 0;
8372  }
8373 
8386  public function getListOfQuestionsSettings()
8387  {
8388  return ($this->show_summary) ? $this->show_summary : 0;
8389  }
8390 
8403  public function setListOfQuestionsSettings($a_value = 0)
8404  {
8405  $this->show_summary = $a_value;
8406  }
8407 
8414  public function getListOfQuestions()
8415  {
8416  if (($this->show_summary & 1) > 0) {
8417  return true;
8418  } else {
8419  return false;
8420  }
8421  }
8422 
8429  public function setListOfQuestions($a_value = true)
8430  {
8431  if ($a_value) {
8432  $this->show_summary = 1;
8433  } else {
8434  $this->show_summary = 0;
8435  }
8436  }
8437 
8444  public function getListOfQuestionsStart()
8445  {
8446  if (($this->show_summary & 2) > 0) {
8447  return true;
8448  } else {
8449  return false;
8450  }
8451  }
8452 
8459  public function setListOfQuestionsStart($a_value = true)
8460  {
8461  if ($a_value && $this->getListOfQuestions()) {
8462  $this->show_summary = $this->show_summary | 2;
8463  }
8464  if (!$a_value && $this->getListOfQuestions()) {
8465  if ($this->getListOfQuestionsStart()) {
8466  $this->show_summary = $this->show_summary ^ 2;
8467  }
8468  }
8469  }
8470 
8477  public function getListOfQuestionsEnd()
8478  {
8479  if (($this->show_summary & 4) > 0) {
8480  return true;
8481  } else {
8482  return false;
8483  }
8484  }
8485 
8492  public function setListOfQuestionsEnd($a_value = true)
8493  {
8494  if ($a_value && $this->getListOfQuestions()) {
8495  $this->show_summary = $this->show_summary | 4;
8496  }
8497  if (!$a_value && $this->getListOfQuestions()) {
8498  if ($this->getListOfQuestionsEnd()) {
8499  $this->show_summary = $this->show_summary ^ 4;
8500  }
8501  }
8502  }
8503 
8511  {
8512  if (($this->show_summary & 8) > 0) {
8513  return true;
8514  } else {
8515  return false;
8516  }
8517  }
8518 
8525  public function setListOfQuestionsDescription($a_value = true)
8526  {
8527  if ($a_value && $this->getListOfQuestions()) {
8528  $this->show_summary = $this->show_summary | 8;
8529  }
8530  if (!$a_value && $this->getListOfQuestions()) {
8531  if ($this->getListOfQuestionsDescription()) {
8532  $this->show_summary = $this->show_summary ^ 8;
8533  }
8534  }
8535  }
8536 
8543  public function getResultsPresentation()
8544  {
8545  return ($this->results_presentation) ? $this->results_presentation : 0;
8546  }
8547 
8554  public function getShowPassDetails()
8555  {
8556  if (($this->results_presentation & 1) > 0) {
8557  return true;
8558  } else {
8559  return false;
8560  }
8561  }
8562 
8569  public function getShowSolutionDetails()
8570  {
8571  if (($this->results_presentation & 2) > 0) {
8572  return true;
8573  } else {
8574  return false;
8575  }
8576  }
8577 
8584  public function getShowSolutionPrintview()
8585  {
8586  if (($this->results_presentation & 4) > 0) {
8587  return true;
8588  } else {
8589  return false;
8590  }
8591  }
8592 
8599  public function getShowSolutionFeedback()
8600  {
8601  if (($this->results_presentation & 8) > 0) {
8602  return true;
8603  } else {
8604  return false;
8605  }
8606  }
8607 
8614  public function getShowSolutionAnswersOnly()
8615  {
8616  if (($this->results_presentation & 16) > 0) {
8617  return true;
8618  } else {
8619  return false;
8620  }
8621  }
8622 
8629  public function getShowSolutionSignature()
8630  {
8631  if (($this->results_presentation & 32) > 0) {
8632  return true;
8633  } else {
8634  return false;
8635  }
8636  }
8637 
8642  public function getShowSolutionSuggested()
8643  {
8644  if (($this->results_presentation & 64) > 0) {
8645  return true;
8646  } else {
8647  return false;
8648  }
8649  }
8650 
8656  {
8657  if (($this->results_presentation & 128) > 0) {
8658  return true;
8659  } else {
8660  return false;
8661  }
8662  }
8663 
8670  public function setResultsPresentation($a_results_presentation = 3)
8671  {
8672  $this->results_presentation = $a_results_presentation;
8673  }
8674 
8683  public function setShowPassDetails($a_details = 1)
8684  {
8685  if ($a_details) {
8686  $this->results_presentation = $this->results_presentation | 1;
8687  } else {
8688  if ($this->getShowPassDetails()) {
8689  $this->results_presentation = $this->results_presentation ^ 1;
8690  }
8691  }
8692  }
8693 
8700  public function setShowSolutionDetails($a_details = 1)
8701  {
8702  if ($a_details) {
8703  $this->results_presentation = $this->results_presentation | 2;
8704  } else {
8705  if ($this->getShowSolutionDetails()) {
8706  $this->results_presentation = $this->results_presentation ^ 2;
8707  }
8708  }
8709  }
8710 
8717  public function canShowSolutionPrintview($user_id = null)
8718  {
8719  return $this->getShowSolutionPrintview();
8720  }
8721 
8728  public function setShowSolutionPrintview($a_printview = 1)
8729  {
8730  if ($a_printview) {
8731  $this->results_presentation = $this->results_presentation | 4;
8732  } else {
8733  if ($this->getShowSolutionPrintview()) {
8734  $this->results_presentation = $this->results_presentation ^ 4;
8735  }
8736  }
8737  }
8738 
8745  public function setShowSolutionFeedback($a_feedback = true)
8746  {
8747  if ($a_feedback) {
8748  $this->results_presentation = $this->results_presentation | 8;
8749  } else {
8750  if ($this->getShowSolutionFeedback()) {
8751  $this->results_presentation = $this->results_presentation ^ 8;
8752  }
8753  }
8754  }
8755 
8762  public function setShowSolutionAnswersOnly($a_full = true)
8763  {
8764  if ($a_full) {
8765  $this->results_presentation = $this->results_presentation | 16;
8766  } else {
8767  if ($this->getShowSolutionAnswersOnly()) {
8768  $this->results_presentation = $this->results_presentation ^ 16;
8769  }
8770  }
8771  }
8772 
8779  public function setShowSolutionSignature($a_signature = false)
8780  {
8781  if ($a_signature) {
8782  $this->results_presentation = $this->results_presentation | 32;
8783  } else {
8784  if ($this->getShowSolutionSignature()) {
8785  $this->results_presentation = $this->results_presentation ^ 32;
8786  }
8787  }
8788  }
8789 
8796  public function setShowSolutionSuggested($a_solution = false)
8797  {
8798  if ($a_solution) {
8799  $this->results_presentation = $this->results_presentation | 64;
8800  } else {
8801  if ($this->getShowSolutionSuggested()) {
8802  $this->results_presentation = $this->results_presentation ^ 64;
8803  }
8804  }
8805  }
8806 
8812  public function setShowSolutionListComparison($a_comparison = false)
8813  {
8814  if ($a_comparison) {
8815  $this->results_presentation = $this->results_presentation | 128;
8816  } else {
8817  if ($this->getShowSolutionListComparison()) {
8818  $this->results_presentation = $this->results_presentation ^ 128;
8819  }
8820  }
8821  }
8822 
8826  public static function _getUserIdFromActiveId($active_id)
8827  {
8828  global $ilDB;
8829  $result = $ilDB->queryF(
8830  "SELECT user_fi FROM tst_active WHERE active_id = %s",
8831  array('integer'),
8832  array($active_id)
8833  );
8834  if ($result->numRows()) {
8835  $row = $ilDB->fetchAssoc($result);
8836  return $row["user_fi"];
8837  } else {
8838  return -1;
8839  }
8840  }
8841 
8845  public function isLimitUsersEnabled()
8846  {
8847  return $this->limitUsersEnabled;
8848  }
8849 
8854  {
8855  $this->limitUsersEnabled = $limitUsersEnabled;
8856  }
8857 
8858  public function getAllowedUsers()
8859  {
8860  return ($this->allowedUsers) ? $this->allowedUsers : 0;
8861  }
8862 
8863  public function setAllowedUsers($a_allowed_users)
8864  {
8865  $this->allowedUsers = $a_allowed_users;
8866  }
8867 
8868  public function getAllowedUsersTimeGap()
8869  {
8870  return ($this->allowedUsersTimeGap) ? $this->allowedUsersTimeGap : 0;
8871  }
8872 
8873  public function setAllowedUsersTimeGap($a_allowed_users_time_gap)
8874  {
8875  $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
8876  }
8877 
8878  public function checkMaximumAllowedUsers()
8879  {
8880  global $ilDB;
8881 
8882  $nr_of_users = $this->getAllowedUsers();
8883  $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
8884  if (($nr_of_users > 0) && ($time_gap > 0)) {
8885  $now = time();
8886  $time_border = $now - $time_gap;
8887  $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
8888  $query = "
8889  SELECT DISTINCT tst_times.active_fi
8890  FROM tst_times
8891  INNER JOIN tst_active
8892  ON tst_times.active_fi = tst_active.active_id
8893  AND (
8894  tst_times.pass > tst_active.last_finished_pass OR tst_active.last_finished_pass IS NULL
8895  )
8896  WHERE tst_times.tstamp > %s
8897  AND tst_active.test_fi = %s
8898  ";
8899  $result = $ilDB->queryF($query, array('integer', 'integer'), array($time_border, $this->getTestId()));
8900  if ($result->numRows() >= $nr_of_users) {
8901  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
8903  $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
8904  }
8905  return false;
8906  } else {
8907  return true;
8908  }
8909  }
8910  return true;
8911  }
8912 
8913  public function _getLastAccess($active_id)
8914  {
8915  global $ilDB;
8916 
8917  $result = $ilDB->queryF(
8918  "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
8919  array('integer'),
8920  array($active_id)
8921  );
8922  if ($result->numRows()) {
8923  $row = $ilDB->fetchAssoc($result);
8924  return $row["finished"];
8925  }
8926  return "";
8927  }
8928 
8929  public static function lookupLastTestPassAccess($activeId, $passIndex)
8930  {
8931  global $DIC; /* @var \ILIAS\DI\Container $DIC */
8932 
8933  $query = "
8934  SELECT MAX(tst_times.tstamp) as last_pass_access
8935  FROM tst_times
8936  WHERE active_fi = %s
8937  AND pass = %s
8938  ";
8939 
8940  $res = $DIC->database()->queryF(
8941  $query,
8942  array('integer', 'integer'),
8943  array($activeId, $passIndex)
8944  );
8945 
8946  while ($row = $DIC->database()->fetchAssoc($res)) {
8947  return $row['last_pass_access'];
8948  }
8949 
8950  return null;
8951  }
8952 
8960  public function isHTML($a_text)
8961  {
8962  if (preg_match("/<[^>]*?>/", $a_text)) {
8963  return true;
8964  } else {
8965  return false;
8966  }
8967  }
8968 
8976  public function QTIMaterialToString($a_material)
8977  {
8978  $result = "";
8979  for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
8980  $material = $a_material->getMaterial($i);
8981  if (strcmp($material["type"], "mattext") == 0) {
8982  $result .= $material["material"]->getContent();
8983  }
8984  if (strcmp($material["type"], "matimage") == 0) {
8985  $matimage = $material["material"];
8986  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) {
8987  // import an mediaobject which was inserted using tiny mce
8988  if (!is_array($_SESSION["import_mob_xhtml"])) {
8989  $_SESSION["import_mob_xhtml"] = array();
8990  }
8991  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
8992  }
8993  }
8994  }
8995  global $ilLog;
8996  $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
8997  return $result;
8998  }
8999 
9008  public function addQTIMaterial(&$a_xml_writer, $a_material)
9009  {
9010  include_once "./Services/RTE/classes/class.ilRTE.php";
9011  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9012 
9013  $a_xml_writer->xmlStartTag("material");
9014  $attrs = array(
9015  "texttype" => "text/plain"
9016  );
9017  if ($this->isHTML($a_material)) {
9018  $attrs["texttype"] = "text/xhtml";
9019  }
9020  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
9021 
9022  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9023  foreach ($mobs as $mob) {
9024  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9025  if (strpos($a_material, "mm_$mob") !== false) {
9026  if (ilObjMediaObject::_exists($mob)) {
9027  $mob_obj = new ilObjMediaObject($mob);
9028  $imgattrs = array(
9029  "label" => $moblabel,
9030  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9031  );
9032  }
9033  $a_xml_writer->xmlElement("matimage", $imgattrs, null);
9034  }
9035  }
9036  $a_xml_writer->xmlEndTag("material");
9037  }
9038 
9045  public function prepareTextareaOutput($txt_output, $prepare_for_latex_output = false, $omitNl2BrWhenTextArea = false)
9046  {
9047  include_once "./Services/Utilities/classes/class.ilUtil.php";
9048  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output, $omitNl2BrWhenTextArea);
9049  }
9050 
9057  public function saveCertificateVisibility($a_value)
9058  {
9059  global $ilDB;
9060 
9061  $affectedRows = $ilDB->manipulateF(
9062  "UPDATE tst_tests SET certificate_visibility = %s, tstamp = %s WHERE test_id = %s",
9063  array('text', 'integer', 'integer'),
9064  array($a_value, time(), $this->getTestId())
9065  );
9066  }
9067 
9074  public function getCertificateVisibility()
9075  {
9076  return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0;
9077  }
9078 
9085  public function setCertificateVisibility($a_value)
9086  {
9087  $this->certificate_visibility = $a_value;
9088  }
9089 
9096  public function getAnonymity()
9097  {
9098  return ($this->anonymity) ? 1 : 0;
9099  }
9100 
9107  public function setAnonymity($a_value = 0)
9108  {
9109  switch ($a_value) {
9110  case 1:
9111  $this->anonymity = 1;
9112  break;
9113  default:
9114  $this->anonymity = 0;
9115  break;
9116  }
9117  }
9118 
9125  public function getShowCancel()
9126  {
9127  return ($this->show_cancel) ? 1 : 0;
9128  }
9129 
9136  public function setShowCancel($a_value = 1)
9137  {
9138  switch ($a_value) {
9139  case 1:
9140  $this->show_cancel = 1;
9141  break;
9142  default:
9143  $this->show_cancel = 0;
9144  break;
9145  }
9146  }
9147 
9154  public function getShowMarker()
9155  {
9156  return ($this->show_marker) ? 1 : 0;
9157  }
9158 
9165  public function setShowMarker($a_value = 1)
9166  {
9167  switch ($a_value) {
9168  case 1:
9169  $this->show_marker = 1;
9170  break;
9171  default:
9172  $this->show_marker = 0;
9173  break;
9174  }
9175  }
9176 
9183  public function getFixedParticipants()
9184  {
9185  return ($this->fixed_participants) ? 1 : 0;
9186  }
9187 
9194  public function setFixedParticipants($a_value = 1)
9195  {
9196  switch ($a_value) {
9197  case 1:
9198  $this->fixed_participants = 1;
9199  break;
9200  default:
9201  $this->fixed_participants = 0;
9202  break;
9203  }
9204  }
9205 
9213  public static function _lookupAnonymity($a_obj_id)
9214  {
9215  global $ilDB;
9216 
9217  $result = $ilDB->queryF(
9218  "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
9219  array('integer'),
9220  array($a_obj_id)
9221  );
9222  while ($row = $ilDB->fetchAssoc($result)) {
9223  return $row['anonymity'];
9224  }
9225  return 0;
9226  }
9227 
9234  public static function lookupQuestionSetTypeByActiveId($active_id)
9235  {
9236  global $ilDB;
9237 
9238  $query = "
9239  SELECT tst_tests.question_set_type
9240  FROM tst_active
9241  INNER JOIN tst_tests
9242  ON tst_active.test_fi = tst_tests.test_id
9243  WHERE tst_active.active_id = %s
9244  ";
9245 
9246  $res = $ilDB->queryF($query, array('integer'), array($active_id));
9247 
9248  while ($row = $ilDB->fetchAssoc($res)) {
9249  return $row['question_set_type'];
9250  }
9251 
9252  return null;
9253  }
9254 
9263  public function _lookupRandomTestFromActiveId($active_id)
9264  {
9265  throw new Exception(__METHOD__ . ' is deprecated ... use ilObjTest::lookupQuestionSetTypeByActiveId() instead!');
9266 
9267  global $ilDB;
9268 
9269  $result = $ilDB->queryF(
9270  "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",
9271  array('integer'),
9272  array($active_id)
9273  );
9274  while ($row = $ilDB->fetchAssoc($result)) {
9275  return $row['random_test'];
9276  }
9277  return 0;
9278  }
9279 
9290  public function userLookupFullName($user_id, $overwrite_anonymity = false, $sorted_order = false, $suffix = "")
9291  {
9292  if ($this->getAnonymity() && !$overwrite_anonymity) {
9293  return $this->lng->txt("anonymous") . $suffix;
9294  } else {
9295  include_once './Services/User/classes/class.ilObjUser.php';
9296  $uname = ilObjUser::_lookupName($user_id);
9297  if (strlen($uname["firstname"] . $uname["lastname"]) == 0) {
9298  $uname["firstname"] = $this->lng->txt("deleted_user");
9299  }
9300  if ($sorted_order) {
9301  return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9302  } else {
9303  return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9304  }
9305  }
9306  }
9307 
9315  public function getStartTestLabel($active_id)
9316  {
9317  if ($this->getNrOfTries() == 1) {
9318  return $this->lng->txt("tst_start_test");
9319  }
9320  $active_pass = self::_getPass($active_id);
9321  $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9322  if ($res == 0) {
9323  if ($active_pass == 0) {
9324  return $this->lng->txt("tst_start_test");
9325  } else {
9326  return $this->lng->txt("tst_start_new_test_pass");
9327  }
9328  } else {
9329  return $this->lng->txt("tst_resume_test");
9330  }
9331  }
9332 
9338  public function getAvailableDefaults()
9339  {
9344  global $ilDB, $ilUser;
9345 
9346  $result = $ilDB->queryF(
9347  "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
9348  array('integer'),
9349  array($ilUser->getId())
9350  );
9351  $defaults = array();
9352  while ($row = $ilDB->fetchAssoc($result)) {
9353  $defaults[$row["test_defaults_id"]] = $row;
9354  }
9355  return $defaults;
9356  }
9357 
9365  public function &getTestDefaults($test_defaults_id)
9366  {
9367  return self::_getTestDefaults($test_defaults_id);
9368  }
9369 
9370  public static function _getTestDefaults($test_defaults_id)
9371  {
9372  global $ilDB;
9373 
9374  $result = $ilDB->queryF(
9375  "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9376  array('integer'),
9377  array($test_defaults_id)
9378  );
9379  if ($result->numRows() == 1) {
9380  $row = $ilDB->fetchAssoc($result);
9381  return $row;
9382  } else {
9383  return null;
9384  }
9385  }
9386 
9393  public function deleteDefaults($test_default_id)
9394  {
9395  global $ilDB;
9396  $affectedRows = $ilDB->manipulateF(
9397  "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9398  array('integer'),
9399  array($test_default_id)
9400  );
9401  }
9402 
9409  public function addDefaults($a_name)
9410  {
9411  global $ilDB;
9412  global $ilUser;
9413  $testsettings = array(
9414  "TitleOutput" => $this->getTitleOutput(),
9415  "PassScoring" => $this->getPassScoring(),
9416  "IntroEnabled" => $this->isIntroductionEnabled(),
9417  "Introduction" => $this->getIntroduction(),
9418  "FinalStatement" => $this->getFinalStatement(),
9419  "ShowInfo" => $this->getShowInfo(),
9420  "ForceJS" => $this->getForceJS(),
9421  "CustomStyle" => $this->getCustomStyle(),
9422  "ShowFinalStatement" => $this->getShowFinalStatement(),
9423  "SequenceSettings" => $this->getSequenceSettings(),
9424  "ScoreReporting" => $this->getScoreReporting(),
9425  "ScoreCutting" => $this->getScoreCutting(),
9426  'SpecificAnswerFeedback' => $this->getSpecificAnswerFeedback(),
9427  'PrintBsWithRes' => (int) $this->isBestSolutionPrintedWithResult(),
9428  "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9429  "AnswerFeedback" => $this->getAnswerFeedback(),
9430  "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9431  "ResultsPresentation" => $this->getResultsPresentation(),
9432  "Anonymity" => $this->getAnonymity(),
9433  "ShowCancel" => $this->getShowCancel(),
9434  "ShowMarker" => $this->getShowMarker(),
9435  "ReportingDate" => $this->getReportingDate(),
9436  "NrOfTries" => $this->getNrOfTries(),
9437  "Shuffle" => $this->getShuffleQuestions(),
9438  "Kiosk" => $this->getKiosk(),
9439  "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9440  "ProcessingTime" => $this->getProcessingTime(),
9441  "EnableProcessingTime" => $this->getEnableProcessingTime(),
9442  "ResetProcessingTime" => $this->getResetProcessingTime(),
9443  "StartingTimeEnabled" => $this->isStartingTimeEnabled(),
9444  "StartingTime" => $this->getStartingTime(),
9445  "EndingTimeEnabled" => $this->isEndingTimeEnabled(),
9446  "EndingTime" => $this->getEndingTime(),
9447  "ECTSOutput" => $this->getECTSOutput(),
9448  "ECTSFX" => $this->getECTSFX(),
9449  "ECTSGrades" => $this->getECTSGrades(),
9450  "questionSetType" => $this->getQuestionSetType(),
9451  "CountSystem" => $this->getCountSystem(),
9452  "MCScoring" => $this->getMCScoring(),
9453  "mailnotification" => $this->getMailNotification(),
9454  "mailnottype" => $this->getMailNotificationType(),
9455  "exportsettings" => $this->getExportSettings(),
9456  "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings(),
9457  'obligations_enabled' => (int) $this->areObligationsEnabled(),
9458  'offer_question_hints' => (int) $this->isOfferingQuestionHintsEnabled(),
9459  'pass_deletion_allowed' => (int) $this->isPassDeletionAllowed(),
9460  'enable_examview' => $this->getEnableExamview(),
9461  'show_examview_html' => $this->getShowExamviewHtml(),
9462  'show_examview_pdf' => $this->getShowExamviewPdf(),
9463  'char_selector_availability' => $this->getCharSelectorAvailability(),
9464  'char_selector_definition' => $this->getCharSelectorDefinition(),
9465  'skill_service' => (int) $this->isSkillServiceEnabled(),
9466  'result_tax_filters' => (array) $this->getResultFilterTaxIds(),
9467  'show_grading_status' => (int) $this->isShowGradingStatusEnabled(),
9468  'show_grading_mark' => (int) $this->isShowGradingMarkEnabled(),
9469 
9470  'inst_fb_answer_fixation' => $this->isInstantFeedbackAnswerFixationEnabled(),
9471  'force_inst_fb' => $this->isForceInstantFeedbackEnabled(),
9472  'redirection_mode' => $this->getRedirectionMode(),
9473  'redirection_url' => $this->getRedirectionUrl(),
9474  'sign_submission' => $this->getSignSubmission(),
9475  'autosave' => (int) $this->getAutosave(),
9476  'autosave_ival' => (int) $this->getAutosaveIval(),
9477  'examid_in_test_pass' => (int) $this->isShowExamIdInTestPassEnabled(),
9478  'examid_in_test_res' => (int) $this->isShowExamIdInTestResultsEnabled(),
9479 
9480  'enable_archiving' => (int) $this->getEnableArchiving(),
9481  'password_enabled' => (int) $this->isPasswordEnabled(),
9482  'password' => (string) $this->getPassword(),
9483  'fixed_participants' => $this->getFixedParticipants(),
9484  'limit_users_enabled' => $this->isLimitUsersEnabled(),
9485  'allowedusers' => $this->getAllowedUsers(),
9486  'alloweduserstimegap' => $this->getAllowedUsersTimeGap(),
9487  'pool_usage' => $this->getPoolUsage(),
9488  'activation_limited' => $this->isActivationLimited(),
9489  'activation_start_time' => $this->getActivationStartingTime(),
9490  'activation_end_time' => $this->getActivationEndingTime(),
9491  'activation_visibility' => $this->getActivationVisibility(),
9492  'highscore_enabled' => $this->getHighscoreEnabled(),
9493  'highscore_anon' => $this->getHighscoreAnon(),
9494  'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
9495  'highscore_score' => $this->getHighscoreScore(),
9496  'highscore_percentage' => $this->getHighscorePercentage(),
9497  'highscore_hints' => $this->getHighscoreHints(),
9498  'highscore_wtime' => $this->getHighscoreWTime(),
9499  'highscore_own_table' => $this->getHighscoreOwnTable(),
9500  'highscore_top_table' => $this->getHighscoreTopTable(),
9501  'highscore_top_num' => $this->getHighscoreTopNum(),
9502  'use_previous_answers' => (string) $this->getUsePreviousAnswers(),
9503  'pass_waiting' => $this->getPassWaiting()
9504  );
9505 
9506  $next_id = $ilDB->nextId('tst_test_defaults');
9507  $ilDB->insert(
9508  'tst_test_defaults',
9509  array(
9510  'test_defaults_id' => array('integer', $next_id),
9511  'name' => array('text', $a_name),
9512  'user_fi' => array('integer', $ilUser->getId()),
9513  'defaults' => array('clob', serialize($testsettings)),
9514  'marks' => array('clob', serialize($this->mark_schema)),
9515  'tstamp' => array('integer', time())
9516  )
9517  );
9518  }
9519 
9527  public function applyDefaults($test_defaults)
9528  {
9529  $testsettings = unserialize($test_defaults["defaults"]);
9530  include_once "./Modules/Test/classes/class.assMarkSchema.php";
9531  $this->mark_schema = unserialize($test_defaults["marks"]);
9532 
9533  $this->setTitleOutput($testsettings["TitleOutput"]);
9534  $this->setPassScoring($testsettings["PassScoring"]);
9535  $this->setIntroductionEnabled($testsettings["IntroEnabled"]);
9536  $this->setIntroduction($testsettings["Introduction"]);
9537  $this->setFinalStatement($testsettings["FinalStatement"]);
9538  $this->setShowInfo($testsettings["ShowInfo"]);
9539  $this->setForceJS($testsettings["ForceJS"]);
9540  $this->setCustomStyle($testsettings["CustomStyle"]);
9541  $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
9542  $this->setSequenceSettings($testsettings["SequenceSettings"]);
9543  $this->setScoreReporting($testsettings["ScoreReporting"]);
9544  $this->setScoreCutting($testsettings['ScoreCutting']);
9545  $this->setSpecificAnswerFeedback($testsettings['SpecificAnswerFeedback']);
9546  $this->setPrintBestSolutionWithResult((bool) $testsettings['PrintBsWithRes']);
9547  $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
9548  $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
9549  $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
9550  $this->setResultsPresentation($testsettings["ResultsPresentation"]);
9551  $this->setAnonymity($testsettings["Anonymity"]);
9552  $this->setShowCancel($testsettings["ShowCancel"]);
9553  $this->setShuffleQuestions($testsettings["Shuffle"]);
9554  $this->setShowMarker($testsettings["ShowMarker"]);
9555  $this->setReportingDate($testsettings["ReportingDate"]);
9556  $this->setNrOfTries($testsettings["NrOfTries"]);
9557  $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
9558  $this->setRedirectionMode($testsettings['redirection_mode']);
9559  $this->setRedirectionUrl($testsettings['redirection_url']);
9560  $this->setProcessingTime($testsettings["ProcessingTime"]);
9561  $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
9562  $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
9563  $this->setStartingTimeEnabled($testsettings["StartingTimeEnabled"]);
9564  $this->setStartingTime($testsettings["StartingTime"]);
9565  $this->setKiosk($testsettings["Kiosk"]);
9566  $this->setEndingTimeEnabled($testsettings["EndingTimeEnabled"]);
9567  $this->setEndingTime($testsettings["EndingTime"]);
9568  $this->setECTSOutput($testsettings["ECTSOutput"]);
9569  $this->setECTSFX($testsettings["ECTSFX"]);
9570  $this->setECTSGrades($testsettings["ECTSGrades"]);
9571  if (isset($testsettings["isRandomTest"])) {
9572  if ($testsettings["isRandomTest"]) {
9573  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
9574  } else {
9575  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
9576  }
9577  } elseif (isset($testsettings["questionSetType"])) {
9578  $this->setQuestionSetType($testsettings["questionSetType"]);
9579  }
9580  $this->setCountSystem($testsettings["CountSystem"]);
9581  $this->setMCScoring($testsettings["MCScoring"]);
9582  $this->setMailNotification($testsettings["mailnotification"]);
9583  $this->setMailNotificationType($testsettings["mailnottype"]);
9584  $this->setExportSettings($testsettings['exportsettings']);
9585  $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
9586  $this->setObligationsEnabled($testsettings["obligations_enabled"]);
9587  $this->setOfferingQuestionHintsEnabled($testsettings["offer_question_hints"]);
9588  $this->setHighscoreEnabled($testsettings['highscore_enabled']);
9589  $this->setHighscoreAnon($testsettings['highscore_anon']);
9590  $this->setHighscoreAchievedTS($testsettings['highscore_achieved_ts']);
9591  $this->setHighscoreScore($testsettings['highscore_score']);
9592  $this->setHighscorePercentage($testsettings['highscore_percentage']);
9593  $this->setHighscoreHints($testsettings['highscore_hints']);
9594  $this->setHighscoreWTime($testsettings['highscore_wtime']);
9595  $this->setHighscoreOwnTable($testsettings['highscore_own_table']);
9596  $this->setHighscoreTopTable($testsettings['highscore_top_table']);
9597  $this->setHighscoreTopNum($testsettings['highscore_top_num']);
9598  $this->setPassDeletionAllowed($testsettings['pass_deletion_allowed']);
9599  if (isset($testsettings['examid_in_kiosk'])) {
9600  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_kiosk']);
9601  } else {
9602  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_test_pass']);
9603  }
9604  if (isset($testsettings['show_exam_id'])) {
9605  $this->setShowExamIdInTestResultsEnabled($testsettings['show_exam_id']);
9606  } else {
9607  $this->setShowExamIdInTestResultsEnabled($testsettings['examid_in_test_res']);
9608  }
9609  $this->setEnableExamview($testsettings['enable_examview']);
9610  $this->setShowExamviewHtml($testsettings['show_examview_html']);
9611  $this->setShowExamviewPdf($testsettings['show_examview_pdf']);
9612  $this->setEnableArchiving($testsettings['enable_archiving']);
9613  $this->setSignSubmission($testsettings['sign_submission']);
9614  $this->setCharSelectorAvailability($testsettings['char_selector_availability']);
9615  $this->setCharSelectorDefinition($testsettings['char_selector_definition']);
9616  $this->setSkillServiceEnabled((bool) $testsettings['skill_service']);
9617  $this->setResultFilterTaxIds((array) $testsettings['result_tax_filters']);
9618  $this->setShowGradingStatusEnabled((bool) $testsettings['show_grading_status']);
9619  $this->setShowGradingMarkEnabled((bool) $testsettings['show_grading_mark']);
9620 
9621  $this->setInstantFeedbackAnswerFixationEnabled($testsettings['inst_fb_answer_fixation']);
9622  $this->setForceInstantFeedbackEnabled($testsettings['force_inst_fb']);
9623  $this->setRedirectionMode($testsettings['redirection_mode']);
9624  $this->setRedirectionUrl($testsettings['redirection_url']);
9625 
9626  $this->setAutosave($testsettings['autosave']);
9627  $this->setAutosaveIval($testsettings['autosave_ival']);
9628  $this->setShowExamIdInTestResultsEnabled((int) $testsettings['examid_in_test_res']);
9629  $this->setPasswordEnabled($testsettings['password_enabled']);
9630  $this->setPassword($testsettings['password']);
9631  $this->setFixedParticipants($testsettings['fixed_participants']);
9632  $this->setLimitUsersEnabled($testsettings['limit_users_enabled']);
9633  $this->setAllowedUsers($testsettings['allowedusers']);
9634  $this->setAllowedUsersTimeGap($testsettings['alloweduserstimegap']);
9635  $this->setUsePreviousAnswers($testsettings['use_previous_answers']);
9636  $this->setPoolUsage($testsettings['pool_usage']);
9637  $this->setActivationLimited($testsettings['activation_limited']);
9638  $this->setActivationStartingTime($testsettings['activation_start_time']);
9639  $this->setActivationEndingTime($testsettings['activation_end_time']);
9640  $this->setActivationVisibility($testsettings['activation_visibility']);
9641  $this->setPassWaiting($testsettings['pass_waiting']);
9642 
9643  $this->saveToDb();
9644 
9645  return true;
9646  }
9647 
9655  public function processPrintoutput2FO($print_output)
9656  {
9657  if (extension_loaded("tidy")) {
9658  $config = array(
9659  "indent" => false,
9660  "output-xml" => true,
9661  "numeric-entities" => true
9662  );
9663  $tidy = new tidy();
9664  $tidy->parseString($print_output, $config, 'utf8');
9665  $tidy->cleanRepair();
9666  $print_output = tidy_get_output($tidy);
9667  $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
9668  } else {
9669  $print_output = str_replace("&nbsp;", "&#160;", $print_output);
9670  $print_output = str_replace("&otimes;", "X", $print_output);
9671  }
9672  $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
9673 
9674  // additional font support
9675  $xsl = str_replace(
9676  'font-family="Helvetica, unifont"',
9677  'font-family="' . $GLOBALS['ilSetting']->get('rpc_pdf_font', 'Helvetica, unifont') . '"',
9678  $xsl
9679  );
9680 
9681  $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
9682  $xh = xslt_create();
9683  $params = array();
9684  $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", null, $args, $params);
9685  xslt_error($xh);
9686  xslt_free($xh);
9687  return $output;
9688  }
9689 
9696  public function deliverPDFfromHTML($content, $title = null)
9697  {
9698  $content = preg_replace("/href=\".*?\"/", "", $content);
9699  $printbody = new ilTemplate("tpl.il_as_tst_print_body.html", true, true, "Modules/Test");
9700  $printbody->setVariable("TITLE", ilUtil::prepareFormOutput($this->getTitle()));
9701  $printbody->setVariable("ADM_CONTENT", $content);
9702  $printbody->setCurrentBlock("css_file");
9703  $printbody->setVariable("CSS_FILE", $this->getTestStyleLocation("filesystem"));
9704  $printbody->parseCurrentBlock();
9705  $printbody->setCurrentBlock("css_file");
9706  $printbody->setVariable("CSS_FILE", ilUtil::getStyleSheetLocation("filesystem", "delos.css"));
9707  $printbody->parseCurrentBlock();
9708  $printoutput = $printbody->get();
9709  $html = str_replace("href=\"./", "href=\"" . ILIAS_HTTP_PATH . "/", $printoutput);
9710  $html = preg_replace("/<div id=\"dontprint\">.*?<\\/div>/ims", "", $html);
9711  if (extension_loaded("tidy")) {
9712  $config = array(
9713  "indent" => false,
9714  "output-xml" => true,
9715  "numeric-entities" => true
9716  );
9717  $tidy = new tidy();
9718  $tidy->parseString($html, $config, 'utf8');
9719  $tidy->cleanRepair();
9720  $html = tidy_get_output($tidy);
9721  $html = preg_replace("/^.*?(<html)/", "\\1", $html);
9722  } else {
9723  $html = str_replace("&nbsp;", "&#160;", $html);
9724  $html = str_replace("&otimes;", "X", $html);
9725  }
9726  $html = preg_replace("/src=\".\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
9728  }
9729 
9736  public function deliverPDFfromFO($fo, $title = null)
9737  {
9738  global $ilLog;
9739 
9740  include_once "./Services/Utilities/classes/class.ilUtil.php";
9741  $fo_file = ilUtil::ilTempnam() . ".fo";
9742  $fp = fopen($fo_file, "w");
9743  fwrite($fp, $fo);
9744  fclose($fp);
9745 
9746  include_once './Services/WebServices/RPC/classes/class.ilRpcClientFactory.php';
9747  try {
9748  $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo);
9749  $filename = (strlen($title)) ? $title : $this->getTitle();
9750  ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
9751  return true;
9752  } catch (Exception $e) {
9753  $ilLog->write(__METHOD__ . ': ' . $e->getMessage());
9754  return false;
9755  }
9756  }
9757 
9767  public static function getManualFeedback($active_id, $question_id, $pass)
9768  {
9769  global $ilDB;
9770  $feedback = "";
9771  $result = $ilDB->queryF(
9772  "SELECT feedback FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
9773  array('integer', 'integer', 'integer'),
9774  array($active_id, $question_id, $pass)
9775  );
9776  if ($result->numRows()) {
9777  $row = $ilDB->fetchAssoc($result);
9778  include_once("./Services/RTE/classes/class.ilRTE.php");
9779  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
9780  }
9781  return $feedback;
9782  }
9783 
9794  public function saveManualFeedback($active_id, $question_id, $pass, $feedback)
9795  {
9796  global $ilDB;
9797 
9798  $affectedRows = $ilDB->manipulateF(
9799  "DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
9800  array('integer', 'integer', 'integer'),
9801  array($active_id, $question_id, $pass)
9802  );
9803 
9804  if (strlen($feedback)) {
9805  $next_id = $ilDB->nextId('tst_manual_fb');
9807  $result = $ilDB->insert(
9808  'tst_manual_fb',
9809  array(
9810  'manual_feedback_id' => array( 'integer', $next_id ),
9811  'active_fi' => array( 'integer', $active_id ),
9812  'question_fi' => array( 'integer', $question_id ),
9813  'pass' => array( 'integer', $pass),
9814  'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc($feedback, 0) ),
9815  'tstamp' => array( 'integer', time() ),
9816  )
9817  );
9818  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
9820  global $lng, $ilUser;
9821  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
9822  $username = ilObjTestAccess::_getParticipantData($active_id);
9823  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
9824  $this->logAction(sprintf($lng->txtlng("assessment", "log_manual_feedback", ilObjAssessmentFolder::_getLogLanguage()), $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")", $username, assQuestion::_getQuestionTitle($question_id), $feedback));
9825  }
9826  }
9827  return true;
9828  }
9829 
9837  public function getJavaScriptOutput()
9838  {
9839  return true;
9840 
9841  // global $ilUser;
9842 // if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
9843 // if ($this->getForceJS()) return TRUE;
9844 // $assessmentSetting = new ilSetting("assessment");
9845 // return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
9846  }
9847 
9848  public function &createTestSequence($active_id, $pass, $shuffle)
9849  {
9850  include_once "./Modules/Test/classes/class.ilTestSequence.php";
9851  $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
9852  }
9853 
9859  public function setTestId($a_id)
9860  {
9861  $this->test_id = $a_id;
9862  }
9863 
9872  public function getDetailedTestResults($participants)
9873  {
9874  $results = array();
9875  if (count($participants)) {
9876  foreach ($participants as $active_id => $user_rec) {
9877  $row = array();
9878  $reached_points = 0;
9879  $max_points = 0;
9880  foreach ($this->questions as $value) {
9881  $question =&ilObjTest::_instanciateQuestion($value);
9882  if (is_object($question)) {
9883  $max_points += $question->getMaximumPoints();
9884  $reached_points += $question->getReachedPoints($active_id);
9885  if ($max_points > 0) {
9886  $percentvalue = $reached_points / $max_points;
9887  if ($percentvalue < 0) {
9888  $percentvalue = 0.0;
9889  }
9890  } else {
9891  $percentvalue = 0;
9892  }
9893  if ($this->getAnonymity()) {
9894  $user_rec['firstname'] = "";
9895  $user_rec['lastname'] = $this->lng->txt("anonymous");
9896  }
9897  $row = array(
9898  "user_id"=>$user_rec['usr_id'],
9899  "matriculation" => $user_rec['matriculation'],
9900  "lastname" => $user_rec['lastname'],
9901  "firstname" => $user_rec['firstname'],
9902  "login"=>$user_rec['login'],
9903  "question_id" => $question->getId(),
9904  "question_title" => $question->getTitle(),
9905  "reached_points" => $reached_points,
9906  "max_points" => $max_points
9907  );
9908  $results[] = $row;
9909  }
9910  }
9911  }
9912  }
9913  return $results;
9914  }
9915 
9919  public static function _lookupTestObjIdForQuestionId($a_q_id)
9920  {
9921  global $ilDB;
9922 
9923  $result = $ilDB->queryF(
9924  "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",
9925  array('integer'),
9926  array($a_q_id)
9927  );
9928  $rec = $ilDB->fetchAssoc($result);
9929  return $rec["obj_id"];
9930  }
9931 
9938  public function isPluginActive($a_pname)
9939  {
9940  global $ilPluginAdmin;
9941  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname)) {
9942  return true;
9943  } else {
9944  return false;
9945  }
9946  }
9947 
9948  public function getPassed($active_id)
9949  {
9950  global $ilDB;
9951 
9952  $result = $ilDB->queryF(
9953  "SELECT passed FROM tst_result_cache WHERE active_fi = %s",
9954  array('integer'),
9955  array($active_id)
9956  );
9957  if ($result->numRows()) {
9958  $row = $ilDB->fetchAssoc($result);
9959  return $row['passed'];
9960  } else {
9961  $counted_pass = ilObjTest::_getResultPass($active_id);
9962  $result_array =&$this->getTestResult($active_id, $counted_pass);
9963  return $result_array["test"]["passed"];
9964  }
9965  }
9966 
9972  public function canShowCertificate($testSession, $user_id, $active_id)
9973  {
9974  if ($this->canShowTestResults($testSession)) {
9975  include_once "./Services/Certificate/classes/class.ilCertificate.php";
9976  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
9977  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
9978  if ($cert->isComplete()) {
9979  $vis = $this->getCertificateVisibility();
9980  $showcert = false;
9981  switch ($vis) {
9982  case 0:
9983  $showcert = true;
9984  break;
9985  case 1:
9986  if ($this->getPassed($active_id)) {
9987  $showcert = true;
9988  }
9989  break;
9990  case 2:
9991  $showcert = false;
9992  break;
9993  }
9994  if ($showcert) {
9995  return true;
9996  } else {
9997  return false;
9998  }
9999  } else {
10000  return false;
10001  }
10002  } else {
10003  return false;
10004  }
10005  }
10006 
10010  public function getParticipantsForTestAndQuestion($test_id, $question_id)
10011  {
10013  global $ilDB;
10014 
10015  $query = "
10016  SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
10017  FROM tst_test_result
10018  INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s
10019  INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi
10020  LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi
10021  WHERE tst_test_result.question_fi = %s
10022  ORDER BY usr_data.lastname ASC, usr_data.firstname ASC
10023  ";
10024 
10025  $result = $ilDB->queryF(
10026  $query,
10027  array('integer', 'integer'),
10028  array($test_id, $question_id)
10029  );
10030  $foundusers = array();
10032  while ($row = $ilDB->fetchAssoc($result)) {
10033  if (!array_key_exists($row["active_fi"], $foundusers)) {
10034  $foundusers[$row["active_fi"]] = array();
10035  }
10036  array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10037  }
10038  return $foundusers;
10039  }
10040 
10046  public function getAggregatedResultsData()
10047  {
10048  $data =&$this->getCompleteEvaluationData();
10049  $foundParticipants =&$data->getParticipants();
10050  $results = array("overview" => array(), "questions" => array());
10051  if (count($foundParticipants)) {
10052  $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10053  $total_finished = $this->evalTotalFinished();
10054  $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10055  $average_time = $this->evalTotalStartedAverageTime();
10056  $diff_seconds = $average_time;
10057  $diff_hours = floor($diff_seconds/3600);
10058  $diff_seconds -= $diff_hours * 3600;
10059  $diff_minutes = floor($diff_seconds/60);
10060  $diff_seconds -= $diff_minutes * 60;
10061  $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10062  $total_passed = 0;
10063  $total_passed_reached = 0;
10064  $total_passed_max = 0;
10065  $total_passed_time = 0;
10066  foreach ($foundParticipants as $userdata) {
10067  if ($userdata->getPassed()) {
10068  $total_passed++;
10069  $total_passed_reached += $userdata->getReached();
10070  $total_passed_max += $userdata->getMaxpoints();
10071  $total_passed_time += $userdata->getTimeOfWork();
10072  }
10073  }
10074  $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10075  $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10076  $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10077  $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10078  $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);
10079  $average_time = $average_passed_time;
10080  $diff_seconds = $average_time;
10081  $diff_hours = floor($diff_seconds/3600);
10082  $diff_seconds -= $diff_hours * 3600;
10083  $diff_minutes = floor($diff_seconds/60);
10084  $diff_seconds -= $diff_minutes * 60;
10085  $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10086  }
10087 
10088  foreach ($data->getQuestionTitles() as $question_id => $question_title) {
10089  $answered = 0;
10090  $reached = 0;
10091  $max = 0;
10092  foreach ($foundParticipants as $userdata) {
10093  for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
10094  if (is_object($userdata->getPass($i))) {
10095  $question =&$userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10096  if (is_array($question)) {
10097  $answered++;
10098  $reached += $question["reached"];
10099  $max += $question["points"];
10100  }
10101  }
10102  }
10103  }
10104  $percent = $max ? $reached/$max * 100.0 : 0;
10105  $counter++;
10106  $results["questions"][$question_id] = array(
10107  $question_title,
10108  sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10109  sprintf("%.2f", $percent) . "%",
10110  $answered,
10111  sprintf("%.2f", $answered ? $reached / $answered : 0),
10112  sprintf("%.2f", $answered ? $max / $answered : 0),
10113  $percent / 100.0
10114  );
10115  }
10116  return $results;
10117  }
10118 
10122  public function getXMLZip()
10123  {
10124  require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10125  $expFactory = new ilTestExportFactory($this);
10126  $test_exp = $expFactory->getExporter('xml');
10127  return $test_exp->buildExportFile();
10128  }
10129 
10133  public function getMailNotification()
10134  {
10135  return $this->mailnotification;
10136  }
10137 
10143  public function setMailNotification($a_notification)
10144  {
10145  $this->mailnotification = $a_notification;
10146  }
10147 
10148  public function sendSimpleNotification($active_id)
10149  {
10150  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10151 
10152  $mail = new ilTestMailNotification();
10153  $owner_id = $this->getOwner();
10154  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10155  $mail->sendSimpleNotification($owner_id, $this->getTitle(), $usr_data);
10156  }
10157 
10164  {
10165  include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
10166  include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
10167  $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI(''), 'outEvaluation', $this->getAnonymity());
10168  return $table_gui->getSelectedColumns();
10169  }
10170 
10171  public function sendAdvancedNotification($active_id)
10172  {
10173  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10174 
10175  $mail = new ilTestMailNotification();
10176  $owner_id = $this->getOwner();
10177  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10178 
10179  require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10180  $expFactory = new ilTestExportFactory($this);
10181  $exportObj = $expFactory->getExporter('results');
10182  $file = $exportObj->exportToExcel($deliver = false, 'active_id', $active_id, $passedonly = false);
10183  include_once "./Services/Mail/classes/class.ilFileDataMail.php";
10184  $fd = new ilFileDataMail(ANONYMOUS_USER_ID);
10185  $fd->copyAttachmentFile($file, "result_" . $active_id . ".xls");
10186  $file_names[] = "result_" . $active_id . ".xls";
10187 
10188  $mail->sendAdvancedNotification($owner_id, $this->getTitle(), $usr_data, $file_names);
10189 
10190  if (count($file_names)) {
10191  $fd->unlinkFiles($file_names);
10192  unset($fd);
10193  @unlink($file);
10194  }
10195  }
10196 
10197  public function createRandomSolutions($number)
10198  {
10199  global $ilDB;
10200 
10201  // 1. get a user
10202  $query = "SELECT usr_id FROM usr_data";
10203  $result = $ilDB->query($query);
10204  while ($data = $ilDB->fetchAssoc($result)) {
10205  $activequery = sprintf(
10206  "SELECT user_fi FROM tst_active WHERE test_fi = %s AND user_fi = %s",
10207  $ilDB->quote($this->getTestId()),
10208  $ilDB->quote($data['usr_id'])
10209  );
10210  $activeresult = $ilDB->query($activequery);
10211  if ($activeresult->numRows() == 0) {
10212  $user_id = $data['usr_id'];
10213  if ($user_id != 13) {
10214  include_once "./Modules/Test/classes/class.ilTestSession.php";
10215  $testSession = new ilTestSession();
10216  $testSession->setRefId($this->getRefId());
10217  $testSession->setTestId($this->getTestId());
10218  $testSession->setUserId($user_id);
10219  $testSession->saveToDb();
10220  $passes = ($this->getNrOfTries()) ? $this->getNrOfTries() : 10;
10221  $random = new \ilRandom();
10222  $nr_of_passes = $random->int(1, $passes);
10223  $active_id = $testSession->getActiveId();
10224  for ($pass = 0; $pass < $nr_of_passes; $pass++) {
10225  include_once "./Modules/Test/classes/class.ilTestSequence.php";
10226  $testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10227  $testSequence->loadFromDb();
10228  $testSequence->loadQuestions();
10229  if (!$testSequence->hasSequence()) {
10230  $testSequence->createNewSequence($this->getQuestionCount(), $shuffle);
10231  $testSequence->saveToDb();
10232  }
10233  for ($seq = 1; $seq <= count($this->questions); $seq++) {
10234  $question_id = $testSequence->getQuestionForSequence($seq);
10235  $objQuestion = ilObjTest::_instanciateQuestion($question_id);
10236  $assSettings = new ilSetting('assessment');
10237  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
10238  $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
10239  $processLockerFactory->setQuestionId($objQuestion->getId());
10240  $processLockerFactory->setUserId($testSession->getUserId());
10241  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
10242  $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
10243  $objQuestion->setProcessLocker($processLockerFactory->getLocker());
10244  $objQuestion->createRandomSolution($testSession->getActiveId(), $pass);
10245  }
10246  $testSession->increasePass();
10247  $testSession->setLastSequence(0);
10248  $testSession->setLastFinishedPass($pass);
10249  $testSession->setSubmitted(1);
10250  $testSession->setSubmittedTimestamp(date('Y-m-d H:i:s'));
10251  $testSession->saveToDb();
10252  }
10253  $number--;
10254  if ($number == 0) {
10255  return;
10256  }
10257  }
10258  }
10259  }
10260  }
10261 
10262  public function getResultsForActiveId($active_id)
10263  {
10264  global $ilDB;
10265 
10266  $query = "
10267  SELECT *
10268  FROM tst_result_cache
10269  WHERE active_fi = %s
10270  ";
10271 
10272  $result = $ilDB->queryF(
10273  $query,
10274  array('integer'),
10275  array($active_id)
10276  );
10277 
10278  if (!$result->numRows()) {
10279  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10280 
10282 
10283  $query = "
10284  SELECT *
10285  FROM tst_result_cache
10286  WHERE active_fi = %s
10287  ";
10288 
10289  $result = $ilDB->queryF(
10290  $query,
10291  array('integer'),
10292  array($active_id)
10293  );
10294  }
10295 
10296  $row = $ilDB->fetchAssoc($result);
10297 
10298  return $row;
10299  }
10300 
10301  public function getMailNotificationType()
10302  {
10303  if ($this->mailnottype == 1) {
10304  return $this->mailnottype;
10305  } else {
10306  return 0;
10307  }
10308  }
10309 
10311  {
10312  if ($a_type == 1) {
10313  $this->mailnottype = 1;
10314  } else {
10315  $this->mailnottype = 0;
10316  }
10317  }
10318 
10319  public function getExportSettings()
10320  {
10321  if ($this->exportsettings) {
10322  return $this->exportsettings;
10323  } else {
10324  return 0;
10325  }
10326  }
10327 
10328  public function setExportSettings($a_settings)
10329  {
10330  if ($a_settings) {
10331  $this->exportsettings = $a_settings;
10332  } else {
10333  $this->exportsettings = 0;
10334  }
10335  }
10336 
10338  {
10339  if (($this->exportsettings & 1) > 0) {
10340  return true;
10341  } else {
10342  return false;
10343  }
10344  }
10345 
10346  public function setExportSettingsSingleChoiceShort($a_settings)
10347  {
10348  if ($a_settings) {
10349  $this->exportsettings = $this->exportsettings | 1;
10350  } else {
10351  if ($this->getExportSettingsSingleChoiceShort()) {
10352  $this->exportsettings = $this->exportsettings ^ 1;
10353  }
10354  }
10355  }
10356 
10357  public function getEnabledViewMode()
10358  {
10359  return $this->enabled_view_mode;
10360  }
10361 
10362  public function setEnabledViewMode($mode)
10363  {
10364  $this->enabled_view_mode = $mode;
10365  }
10366 
10367  public function setTemplate($template_id)
10368  {
10369  $this->template_id = (int) $template_id;
10370  }
10371 
10372  public function getTemplate()
10373  {
10374  return $this->template_id;
10375  }
10376 
10377  public function moveQuestionAfterOLD($previous_question_id, $new_question_id)
10378  {
10379  $new_array = array();
10380  $position = 1;
10381 
10382  $query = 'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
10383  $types = array('integer');
10384  $values = array($this->getTestId());
10385 
10386  $new_question_id += 1;
10387 
10388  global $ilDB;
10389  $inserted = false;
10390  $res = $ilDB->queryF($query, $types, $values);
10391  while ($row = $ilDB->fetchAssoc($res)) {
10392  $qid = $row['question_fi'];
10393 
10394  if ($qid == $new_question_id) {
10395  continue;
10396  } elseif ($qid == $previous_question_id) {
10397  $new_array[$position++] = $qid;
10398  $new_array[$position++] = $new_question_id;
10399  $inserted = true;
10400  } else {
10401  $new_array[$position++] = $qid;
10402  }
10403  }
10404 
10405  $update_query = 'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
10406  $update_types = array('integer', 'integer', 'integer');
10407 
10408  foreach ($new_array as $position => $qid) {
10409  $ilDB->manipulateF(
10410  $update_query,
10411  $update_types,
10412  $vals = array(
10413  $position,
10414  $this->getTestId(),
10415  $qid
10416  )
10417  );
10418  }
10419  }
10420 
10422  {
10423  if (is_array($options)) {
10424  $this->setGenericAnswerFeedback(in_array('instant_feedback_generic', $options) ? 1 : 0);
10425  $this->setSpecificAnswerFeedback(in_array('instant_feedback_specific', $options) ? 1 : 0);
10426  $this->setAnswerFeedbackPoints(in_array('instant_feedback_points', $options) ? 1 : 0);
10427  $this->setInstantFeedbackSolution(in_array('instant_feedback_solution', $options) ? 1 : 0);
10428  } else {
10429  $this->setGenericAnswerFeedback(0);
10430  $this->setSpecificAnswerFeedback(0);
10431  $this->setAnswerFeedbackPoints(0);
10432  $this->setInstantFeedbackSolution(0);
10433  }
10434  }
10435 
10437  {
10438  $setter = array(
10439  'pass_details' => 'setShowPassDetails',
10440  'solution_details' => 'setShowSolutionDetails',
10441  'solution_printview' => 'setShowSolutionPrintview',
10442  'solution_feedback' => 'setShowSolutionFeedback',
10443  'solution_answers_only' => 'setShowSolutionAnswersOnly',
10444  'solution_signature' => 'setShowSolutionSignature',
10445  'solution_suggested' => 'setShowSolutionSuggested',
10446  );
10447  foreach ($setter as $key => $setter) {
10448  if (in_array($key, $options)) {
10449  $this->$setter(1);
10450  } else {
10451  $this->$setter(0);
10452  }
10453  }
10454  }
10455 
10456  public function getPoolUsage()
10457  {
10458  return (boolean) $this->poolUsage;
10459  }
10460 
10461  public function setPoolUsage($usage)
10462  {
10463  $this->poolUsage = (boolean) $usage;
10464  }
10465 
10467  {
10468  $tree = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['tree'] : $GLOBALS['tree'];
10469  $db = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['ilDB'];
10470  $pluginAdmin = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilPluginAdmin'] : $GLOBALS['ilPluginAdmin'];
10471 
10472  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
10473  $qscFactory = new ilTestQuestionSetConfigFactory($tree, $db, $pluginAdmin, $this);
10474  $questionSetConfig = $qscFactory->getQuestionSetConfig();
10475 
10476  /* @var ilTestFixedQuestionSetConfig $questionSetConfig */
10477  $questionSetConfig->reindexQuestionOrdering();
10478 
10479  $this->loadQuestions();
10480  }
10481 
10482  public function setQuestionOrderAndObligations($orders, $obligations)
10483  {
10484  global $ilDB;
10485 
10486  asort($orders);
10487 
10488  $i = 0;
10489 
10490  foreach ($orders as $id => $position) {
10491  $i++;
10492 
10493  $obligatory = (
10494  isset($obligations[$id]) && $obligations[$id] ? 1 : 0
10495  );
10496 
10497  $query = "
10498  UPDATE tst_test_question
10499  SET sequence = %s,
10500  obligatory = %s
10501  WHERE question_fi = %s
10502  ";
10503 
10504  $ilDB->manipulateF(
10505  $query,
10506  array('integer', 'integer', 'integer'),
10507  array($i, $obligatory, $id)
10508  );
10509  }
10510 
10511  $this->loadQuestions();
10512  }
10513 
10514  public function moveQuestionAfter($question_to_move, $question_before)
10515  {
10516  global $ilDB;
10517  //var_dump(func_get_args());
10518  if ($question_before) {
10519  $query = 'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
10520  $types = array('integer');
10521  $values = array($question_before);
10522  $rset = $ilDB->queryF($query, $types, $values);
10523  }
10524 
10525  if (!$question_before || ($rset && !($row = $ilDB->fetchAssoc($rset)))) {
10526  $row = array(
10527  'sequence' => 0,
10528  'test_fi' => $this->getTestId(),
10529  );
10530  }
10531 
10532  $update = 'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
10533  $types = array('integer', 'integer');
10534  $values = array($row['sequence'], $row['test_fi']);
10535  $ilDB->manipulateF($update, $types, $values);
10536 
10537  $update = 'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
10538  $types = array('integer', 'integer');
10539  $values = array($row['sequence'] + 1, $question_to_move);
10540  $ilDB->manipulateF($update, $types, $values);
10541 
10543  }
10544 
10546  {
10547  global $ilDB;
10548 
10550 
10551  $IN_questions = $ilDB->in('q1.question_id', array_keys($questions), false, 'integer');
10552 
10553  $query = "
10554  SELECT count(q1.question_id) cnt
10555 
10556  FROM qpl_questions q1
10557 
10558  INNER JOIN qpl_questions q2
10559  ON q2.question_id = q1.original_id
10560 
10561  WHERE $IN_questions
10562  AND q1.obj_fi = q2.obj_fi
10563  ";
10564 
10565  $rset = $ilDB->query($query);
10566 
10567  $row = $ilDB->fetchAssoc($rset);
10568 
10569  return $row['cnt'] > 0;
10570  }
10571 
10578  public static function _lookupFinishedUserTests($a_user_id)
10579  {
10580  global $ilDB;
10581 
10582  $result = $ilDB->queryF(
10583  "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
10584  " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
10585  " WHERE user_fi=%s" .
10586  " GROUP BY test_fi",
10587  array('integer', 'integer'),
10588  array($a_user_id, 1)
10589  );
10590  $all = array();
10591  while ($row = $ilDB->fetchAssoc($result)) {
10592  $obj_id = self::_getObjectIDFromTestID($row["test_fi"]);
10593  $all[$obj_id] = (bool) $row["pass"];
10594  }
10595  return $all;
10596  }
10597  public function getQuestions()
10598  {
10599  return $this->questions;
10600  }
10601 
10602  public function isOnline()
10603  {
10604  return $this->online;
10605  }
10606 
10607  public function setOnline($a_online = true)
10608  {
10609  $this->online = (bool) $a_online;
10610  }
10611 
10615  public function getOldOnlineStatus()
10616  {
10617  return $this->oldOnlineStatus;
10618  }
10619 
10624  {
10625  $this->oldOnlineStatus = $oldOnlineStatus;
10626  }
10627 
10628  public function setPrintBestSolutionWithResult($status)
10629  {
10630  $this->print_best_solution_with_result = (bool) $status;
10631  }
10632 
10634  {
10636  }
10637 
10644  {
10646  }
10647 
10654  {
10655  $this->offeringQuestionHintsEnabled = (bool) $offeringQuestionHintsEnabled;
10656  }
10657 
10658  public function setActivationVisibility($a_value)
10659  {
10660  $this->activation_visibility = (bool) $a_value;
10661  }
10662 
10663  public function getActivationVisibility()
10664  {
10666  }
10667 
10668  public function isActivationLimited()
10669  {
10670  return (bool) $this->activation_limited;
10671  }
10672 
10673  public function setActivationLimited($a_value)
10674  {
10675  $this->activation_limited = (bool) $a_value;
10676  }
10677 
10678  /* GET/SET for highscore feature */
10679 
10685  public function setHighscoreEnabled($a_enabled)
10686  {
10687  $this->_highscore_enabled = (bool) $a_enabled;
10688  }
10689 
10695  public function getHighscoreEnabled()
10696  {
10697  return (bool) $this->_highscore_enabled;
10698  }
10699 
10707  public function setHighscoreAnon($a_anon)
10708  {
10709  $this->_highscore_anon = (bool) $a_anon;
10710  }
10711 
10721  public function getHighscoreAnon()
10722  {
10723  return (bool) $this->_highscore_anon;
10724  }
10725 
10734  public function isHighscoreAnon()
10735  {
10736  if ($this->getAnonymity() == 1) {
10737  return true;
10738  } else {
10739  return (bool) $this->getHighscoreAnon();
10740  }
10741  }
10742 
10748  public function setHighscoreAchievedTS($a_achieved_ts)
10749  {
10750  $this->_highscore_achieved_ts = (bool) $a_achieved_ts;
10751  }
10752 
10758  public function getHighscoreAchievedTS()
10759  {
10760  return (bool) $this->_highscore_achieved_ts;
10761  }
10762 
10768  public function setHighscoreScore($a_score)
10769  {
10770  $this->_highscore_score = (bool) $a_score;
10771  }
10772 
10778  public function getHighscoreScore()
10779  {
10780  return (bool) $this->_highscore_score;
10781  }
10782 
10788  public function setHighscorePercentage($a_percentage)
10789  {
10790  $this->_highscore_percentage = (bool) $a_percentage;
10791  }
10792 
10798  public function getHighscorePercentage()
10799  {
10800  return (bool) $this->_highscore_percentage;
10801  }
10802 
10808  public function setHighscoreHints($a_hints)
10809  {
10810  $this->_highscore_hints = (bool) $a_hints;
10811  }
10812 
10818  public function getHighscoreHints()
10819  {
10820  return (bool) $this->_highscore_hints;
10821  }
10822 
10828  public function setHighscoreWTime($a_wtime)
10829  {
10830  $this->_highscore_wtime = (bool) $a_wtime;
10831  }
10832 
10838  public function getHighscoreWTime()
10839  {
10840  return (bool) $this->_highscore_wtime;
10841  }
10842 
10848  public function setHighscoreOwnTable($a_own_table)
10849  {
10850  $this->_highscore_own_table = (bool) $a_own_table;
10851  }
10852 
10858  public function getHighscoreOwnTable()
10859  {
10860  return (bool) $this->_highscore_own_table;
10861  }
10862 
10868  public function setHighscoreTopTable($a_top_table)
10869  {
10870  $this->_highscore_top_table = (bool) $a_top_table;
10871  }
10872 
10878  public function getHighscoreTopTable()
10879  {
10880  return (bool) $this->_highscore_top_table;
10881  }
10882 
10889  public function setHighscoreTopNum($a_top_num)
10890  {
10891  $this->_highscore_top_num = (int) $a_top_num;
10892  }
10893 
10902  public function getHighscoreTopNum($a_retval = 10)
10903  {
10904  $retval = $a_retval;
10905  if ((int) $this->_highscore_top_num != 0) {
10906  $retval = $this->_highscore_top_num;
10907  }
10908 
10909  return $retval;
10910  }
10911 
10915  public function getHighscoreMode()
10916  {
10917  switch (true) {
10918  case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
10919  return self::HIGHSCORE_SHOW_ALL_TABLES;
10920  break;
10921 
10922  case $this->getHighscoreTopTable():
10923  return self::HIGHSCORE_SHOW_TOP_TABLE;
10924  break;
10925 
10926  case $this->getHighscoreOwnTable():
10927  default:
10928  return self::HIGHSCORE_SHOW_OWN_TABLE;
10929  break;
10930  }
10931  }
10932 
10936  public function setHighscoreMode($mode)
10937  {
10938  switch ($mode) {
10939  case self::HIGHSCORE_SHOW_ALL_TABLES:
10940  $this->setHighscoreTopTable(1);
10941  $this->setHighscoreOwnTable(1);
10942  break;
10943 
10944  case self::HIGHSCORE_SHOW_TOP_TABLE:
10945  $this->setHighscoreTopTable(1);
10946  $this->setHighscoreOwnTable(0);
10947  break;
10948 
10949  case self::HIGHSCORE_SHOW_OWN_TABLE:
10950  default:
10951  $this->setHighscoreTopTable(0);
10952  $this->setHighscoreOwnTable(1);
10953  break;
10954  }
10955  }
10956  /* End GET/SET for highscore feature*/
10957 
10958  public function setSpecificAnswerFeedback($specific_answer_feedback)
10959  {
10960  switch ($specific_answer_feedback) {
10961  case 1:
10962  $this->specific_answer_feedback = 1;
10963  break;
10964  default:
10965  $this->specific_answer_feedback = 0;
10966  break;
10967  }
10968  }
10969 
10970  public function getSpecificAnswerFeedback()
10971  {
10972  switch ($this->specific_answer_feedback) {
10973  case 1:
10974  return 1;
10975  default:
10976  return 0;
10977  }
10978  }
10979 
10986  {
10987  $this->obligationsEnabled = (bool) $obligationsEnabled;
10988  }
10989 
10995  public function areObligationsEnabled()
10996  {
10997  return (bool) $this->obligationsEnabled;
10998  }
10999 
11006  public static function isQuestionObligationPossible($questionId)
11007  {
11008  require_once('Modules/TestQuestionPool/classes/class.assQuestion.php');
11009 
11010  $classConcreteQuestion = assQuestion::_getQuestionType($questionId);
11011 
11012  assQuestion::_includeClass($classConcreteQuestion, 0);
11013 
11014  // static binder is not at work yet (in PHP < 5.3)
11015  //$obligationPossible = $classConcreteQuestion::isObligationPossible();
11016  $obligationPossible = call_user_func(array($classConcreteQuestion, 'isObligationPossible'), $questionId);
11017 
11018  return $obligationPossible;
11019  }
11020 
11027  public static function isQuestionObligatory($question_id)
11028  {
11029  global $ilDB;
11030 
11031  $rset = $ilDB->queryF('SELECT obligatory FROM tst_test_question WHERE question_fi = %s', array('integer'), array($question_id));
11032 
11033  if ($row = $ilDB->fetchAssoc($rset)) {
11034  return (bool) $row['obligatory'];
11035  }
11036 
11037  return false;
11038  }
11039 
11052  public static function allObligationsAnswered($test_id, $active_id, $pass)
11053  {
11054  global $ilDB;
11055 
11056  $rset = $ilDB->queryF(
11057  'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
11058  array('integer', 'integer'),
11059  array($active_id, $pass)
11060  );
11061 
11062  if ($row = $ilDB->fetchAssoc($rset)) {
11063  return (bool) $row['obligations_answered'];
11064  }
11065 
11066  return !self::hasObligations($test_id);
11067  }
11068 
11077  public static function hasObligations($test_id)
11078  {
11079  global $ilDB;
11080 
11081  $rset = $ilDB->queryF(
11082  'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
11083  array('integer'),
11084  array($test_id)
11085  );
11086 
11087  $row = $ilDB->fetchAssoc($rset);
11088 
11089  return (bool) $row['cnt'] > 0;
11090  }
11091 
11092  public function setAutosave($autosave)
11093  {
11094  $this->autosave = $autosave;
11095  }
11096 
11097  public function getAutosave()
11098  {
11099  return $this->autosave;
11100  }
11101 
11103  {
11104  $this->autosave_ival = $autosave_ival;
11105  }
11106 
11107  public function getAutosaveIval()
11108  {
11109  return $this->autosave_ival;
11110  }
11111 
11117  public function isPassDeletionAllowed()
11118  {
11120  }
11121 
11128  {
11129  $this->passDeletionAllowed = (bool) $passDeletionAllowed;
11130  }
11131 
11132  #region Examview / PDF Examview
11133 
11137  {
11138  $this->show_examview_html = $show_examview_html;
11139  }
11140 
11144  public function getShowExamviewHtml()
11145  {
11147  }
11148 
11153  {
11154  $this->show_examview_pdf = $show_examview_pdf;
11155  }
11156 
11160  public function getShowExamviewPdf()
11161  {
11162  return $this->show_examview_pdf;
11163  }
11164 
11169  {
11170  $this->enable_examview = $enable_examview;
11171  }
11172 
11176  public function getEnableExamview()
11177  {
11178  return $this->enable_examview;
11179  }
11180 
11181  #endregion
11182 
11184  {
11185  $this->activation_starting_time = $starting_time;
11186  }
11187 
11188  public function setActivationEndingTime($ending_time = null)
11189  {
11190  $this->activation_ending_time = $ending_time;
11191  }
11192 
11193  public function getActivationStartingTime()
11194  {
11195  return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : null;
11196  }
11197 
11198  public function getActivationEndingTime()
11199  {
11200  return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : null;
11201  }
11202 
11204  {
11205  global $ilDB;
11206 
11207  $times = array();
11208  $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",
11209  array('integer'),
11210  array($this->getTestId())
11211  );
11212  while ($row = $ilDB->fetchAssoc($result)) {
11213  $times[$row['active_fi']] = $row['started'];
11214  }
11215  return $times;
11216  }
11217 
11219  {
11220  global $ilDB;
11221 
11222  $times = array();
11223  $result = $ilDB->queryF(
11224  "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",
11225  array('integer'),
11226  array($this->getTestId())
11227  );
11228  while ($row = $ilDB->fetchAssoc($result)) {
11229  $times[$row['active_fi']] = $row['additionaltime'];
11230  }
11231  return $times;
11232  }
11233 
11234  public function getExtraTime($active_id)
11235  {
11236  global $ilDB;
11237 
11238  $result = $ilDB->queryF(
11239  "SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
11240  array('integer'),
11241  array($active_id)
11242  );
11243  if ($result->numRows() > 0) {
11244  $row = $ilDB->fetchAssoc($result);
11245  return $row['additionaltime'];
11246  }
11247  return 0;
11248  }
11249 
11250  public function addExtraTime($active_id, $minutes)
11251  {
11252  global $ilDB;
11253 
11254  $participants = array();
11255  if ($active_id == 0) {
11256  $result = $ilDB->queryF(
11257  "SELECT active_id FROM tst_active WHERE test_fi = %s",
11258  array('integer'),
11259  array($this->getTestId())
11260  );
11261  while ($row = $ilDB->fetchAssoc($result)) {
11262  array_push($participants, $row['active_id']);
11263  }
11264  } else {
11265  array_push($participants, $active_id);
11266  }
11267  foreach ($participants as $active_id) {
11268  $result = $ilDB->queryF(
11269  "SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
11270  array('integer'),
11271  array($active_id)
11272  );
11273  if ($result->numRows() > 0) {
11274  $ilDB->manipulateF(
11275  "DELETE FROM tst_addtime WHERE active_fi = %s",
11276  array('integer'),
11277  array($active_id)
11278  );
11279  }
11280 
11281  $ilDB->manipulateF(
11282  "UPDATE tst_active SET tries = %s, submitted = %s, submittimestamp = %s WHERE active_id = %s",
11283  array('integer','integer','timestamp','integer'),
11284  array(0, 0, null, $active_id)
11285  );
11286 
11287  $ilDB->manipulateF(
11288  "INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
11289  array('integer','integer','integer'),
11290  array($active_id, $minutes, time())
11291  );
11292 
11293  require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
11295  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_added_extratime", ilObjAssessmentFolder::_getLogLanguage()), $minutes, $active_id));
11296  }
11297  }
11298  }
11299 
11306  {
11307  $this->enable_archiving = $enable_archiving;
11308  return $this;
11309  }
11310 
11314  public function getEnableArchiving()
11315  {
11316  return $this->enable_archiving;
11317  }
11318 
11319  public function getMaxPassOfTest()
11320  {
11324  global $ilDB;
11325 
11326  $query = '
11327  SELECT MAX(tst_pass_result.pass) + 1 max_res
11328  FROM tst_pass_result
11329  INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
11330  WHERE test_fi = ' . $ilDB->quote($this->getTestId(), 'integer') . '
11331  ';
11332  $res = $ilDB->query($query);
11333  $data = $ilDB->fetchAssoc($res);
11334  return (int) $data['max_res'];
11335  }
11336 
11342  public static function lookupExamId($active_id, $pass)
11343  {
11344  global $ilDB;
11345 
11346  $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
11347  $exam_id_result = $ilDB->queryF($exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ));
11348  if ($ilDB->numRows($exam_id_result) == 1) {
11349  $exam_id_row = $ilDB->fetchAssoc($exam_id_result);
11350 
11351  if ($exam_id_row['exam_id'] != null) {
11352  return $exam_id_row['exam_id'];
11353  }
11354  }
11355 
11356  return null;
11357  }
11358 
11365  public static function buildExamId($active_id, $pass, $test_obj_id = null)
11366  {
11367  global $ilSetting;
11368 
11369  $inst_id = $ilSetting->get('inst_id', null);
11370 
11371  if ($test_obj_id === null) {
11372  $obj_id = self::_getObjectIDFromActiveID($active_id);
11373  } else {
11374  $obj_id = $test_obj_id;
11375  }
11376 
11377  $examId = 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
11378 
11379  return $examId;
11380  }
11381 
11383  {
11384  $this->show_exam_id_in_test_pass_enabled = $show_exam_id_in_test_pass_enabled;
11385  }
11386 
11388  {
11390  }
11391 
11396  {
11397  $this->show_exam_id_in_test_results_enabled = $show_exam_id_in_test_results_enabled;
11398  }
11399 
11404  {
11406  }
11407 
11412  {
11413  $this->sign_submission = $sign_submission;
11414  }
11415 
11419  public function getSignSubmission()
11420  {
11421  return $this->sign_submission;
11422  }
11423 
11427  public function setCharSelectorAvailability($availability)
11428  {
11429  $this->char_selector_availability = (int) $availability;
11430  }
11431 
11436  {
11437  return (int) $this->char_selector_availability;
11438  }
11439 
11443  public function setCharSelectorDefinition($definition = '')
11444  {
11445  $this->char_selector_definition = $definition;
11446  }
11447 
11451  public function getCharSelectorDefinition()
11452  {
11454  }
11455 
11456 
11463  {
11464  $this->questionSetType = $questionSetType;
11465  }
11466 
11472  public function getQuestionSetType()
11473  {
11474  return $this->questionSetType;
11475  }
11476 
11484  public static function lookupQuestionSetType($objId)
11485  {
11486  global $ilDB;
11487 
11488  $query = "SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
11489 
11490  $res = $ilDB->queryF($query, array('integer'), array($objId));
11491 
11492  $questionSetType = null;
11493 
11494  while ($row = $ilDB->fetchAssoc($res)) {
11495  $questionSetType = $row['question_set_type'];
11496  }
11497 
11498  return $questionSetType;
11499  }
11500 
11506  public function isFixedTest()
11507  {
11508  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED;
11509  }
11510 
11516  public function isRandomTest()
11517  {
11518  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_RANDOM;
11519  }
11520 
11526  public function isDynamicTest()
11527  {
11528  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC;
11529  }
11530 
11538  public static function _lookupRandomTest($a_obj_id)
11539  {
11540  return self::lookupQuestionSetType($a_obj_id) == self::QUESTION_SET_TYPE_RANDOM;
11541  }
11542 
11544  {
11545  switch ($questionSetType) {
11547  return $lng->txt('tst_question_set_type_fixed');
11548 
11550  return $lng->txt('tst_question_set_type_random');
11551 
11553  return $lng->txt('tst_question_set_type_dynamic');
11554  }
11555 
11556  throw new ilTestException('invalid question set type value given: ' . $questionSetType);
11557  }
11558 
11559  public function participantDataExist()
11560  {
11561  if ($this->participantDataExist === null) {
11562  $this->participantDataExist = (bool) $this->evalTotalPersons();
11563  }
11564 
11566  }
11567 
11568  public function isScoreReportingAvailable()
11569  {
11570  if ($this->getScoreReporting() == 4) {
11571  return false;
11572  }
11573 
11574  if ($this->getScoreReporting() == 3 && $this->getReportingDate() > time()) {
11575  return false;
11576  }
11577 
11578  return true;
11579  }
11580 
11581  public function recalculateScores($preserve_manscoring = false)
11582  {
11583  require_once 'class.ilTestScoring.php';
11584  $scoring = new ilTestScoring($this);
11585  $scoring->setPreserveManualScores($preserve_manscoring);
11586  $scoring->recalculateSolutions();
11587  }
11588 
11589  public static function getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
11590  {
11591  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
11592 
11593  $questionChangeListeners = array(
11595  );
11596 
11597  return $questionChangeListeners;
11598  }
11599 
11600  public static function getTestObjIdsWithActiveForUserId($userId)
11601  {
11602  global $ilDB;
11603 
11604  $query = "
11605  SELECT obj_fi
11606  FROM tst_active
11607  INNER JOIN tst_tests
11608  ON test_id = test_fi
11609  WHERE user_fi = %s
11610  ";
11611 
11612  $res = $ilDB->queryF($query, array('integer'), array($userId));
11613 
11614  $objIds = array();
11615 
11616  while ($row = $ilDB->fetchAssoc($res)) {
11617  $objIds[] = (int) $row['obj_fi'];
11618  }
11619 
11620  return $objIds;
11621  }
11622 
11624  {
11625  $this->skillServiceEnabled = $skillServiceEnabled;
11626  }
11627 
11628  public function isSkillServiceEnabled()
11629  {
11631  }
11632 
11634  {
11635  $this->resultFilterTaxIds = $resultFilterTaxIds;
11636  }
11637 
11638  public function getResultFilterTaxIds()
11639  {
11641  }
11642 
11644  {
11645  if (!$this->isSkillServiceEnabled()) {
11646  return false;
11647  }
11648 
11649  if (!self::isSkillManagementGloballyActivated()) {
11650  return false;
11651  }
11652 
11653  return true;
11654  }
11655 
11657 
11658  public static function isSkillManagementGloballyActivated()
11659  {
11660  if (self::$isSkillManagementGloballyActivated === null) {
11661  include_once 'Services/Skill/classes/class.ilSkillManagementSettings.php';
11662  $skmgSet = new ilSkillManagementSettings();
11663 
11664  self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
11665  }
11666 
11667  return self::$isSkillManagementGloballyActivated;
11668  }
11669 
11671  {
11672  $this->showGradingStatusEnabled = $showGradingStatusEnabled;
11673  }
11674 
11675  public function isShowGradingStatusEnabled()
11676  {
11678  }
11679 
11681  {
11682  $this->showGradingMarkEnabled = $showGradingMarkEnabled;
11683  }
11684 
11685 
11686  public function isShowGradingMarkEnabled()
11687  {
11689  }
11690 
11692  {
11693  $this->instantFeedbackAnswerFixationEnabled = $instantFeedbackAnswerFixationEnabled;
11694  }
11695 
11697  {
11699  }
11700 
11705  {
11707  }
11708 
11713  {
11714  $this->forceInstantFeedbackEnabled = $forceInstantFeedbackEnabled;
11715  }
11716 
11717  public static function ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run = false)
11718  {
11719  global $ilDB, $lng, $ilPluginAdmin;
11720 
11721  /* @var ilObjTest $testOBJ */
11722 
11723  $testOBJ = ilObjectFactory::getInstanceByRefId($testObjId, false);
11724 
11725  $activeId = $testOBJ->getActiveIdOfUser($userId);
11726 
11727  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
11728  $testSessionFactory = new ilTestSessionFactory($testOBJ);
11729 
11730  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
11731  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
11732 
11733  $testSession = $testSessionFactory->getSession($activeId);
11734  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
11735  $testSequence->loadFromDb();
11736 
11737  // begin-patch lok changed smeyer
11738  if ($a_force_new_run) {
11739  if ($testSequence->hasSequence()) {
11740  $testSession->increasePass();
11741  }
11742  $testSession->setLastSequence(0);
11743  $testSession->saveToDb();
11744  }
11745  // end-patch lok
11746  }
11747 
11748  public static function isParticipantsLastPassActive($testRefId, $userId)
11749  {
11750  global $ilDB, $lng, $ilPluginAdmin;
11751 
11752  /* @var ilObjTest $testOBJ */
11753 
11754  $testOBJ = ilObjectFactory::getInstanceByRefId($testRefId, false);
11755 
11756 
11757  $activeId = $testOBJ->getActiveIdOfUser($userId);
11758 
11759  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
11760  $testSessionFactory = new ilTestSessionFactory($testOBJ);
11761  // Added temporarily bugfix smeyer
11762  $testSessionFactory->reset();
11763 
11764  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
11765  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
11766 
11767  $testSession = $testSessionFactory->getSession($activeId);
11768  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
11769  $testSequence->loadFromDb();
11770 
11771  return $testSequence->hasSequence();
11772  }
11773 
11777  public function isTestFinalBroken()
11778  {
11779  return $this->testFinalBroken;
11780  }
11781 
11786  {
11787  $this->testFinalBroken = $testFinalBroken;
11788  }
11789 
11790  public function adjustTestSequence()
11791  {
11795  global $ilDB;
11796 
11797  $query = "
11798  SELECT COUNT(test_question_id) cnt
11799  FROM tst_test_question
11800  WHERE test_fi = %s
11801  ORDER BY sequence
11802  ";
11803 
11804  $questRes = $ilDB->queryF($query, array('integer'), array($this->getTestId()));
11805 
11806  $row = $ilDB->fetchAssoc($questRes);
11807  $questCount = $row['cnt'];
11808 
11809  if ($this->getShuffleQuestions()) {
11810  $query = "
11811  SELECT tseq.*
11812  FROM tst_active tac
11813  INNER JOIN tst_sequence tseq
11814  ON tseq.active_fi = tac.active_id
11815  WHERE tac.test_fi = %s
11816  ";
11817 
11818  $partRes = $ilDB->queryF(
11819  $query,
11820  array('integer'),
11821  array($this->getTestId())
11822  );
11823 
11824  while ($row = $ilDB->fetchAssoc($partRes)) {
11825  $sequence = @unserialize($row['sequence']);
11826 
11827  if (!$sequence) {
11828  $sequence = array();
11829  }
11830 
11831  $sequence = array_filter($sequence, function ($value) use ($questCount) {
11832  return $value <= $questCount;
11833  });
11834 
11835  $num_seq = count($sequence);
11836  if ($questCount > $num_seq) {
11837  $diff = $questCount - $num_seq;
11838  for ($i = 1; $i <= $diff; $i++) {
11839  $sequence[$num_seq + $i - 1] = $num_seq + $i;
11840  }
11841  }
11842 
11843  $new_sequence = serialize($sequence);
11844 
11845  $ilDB->update('tst_sequence', array(
11846  'sequence' => array('clob', $new_sequence)
11847  ), array(
11848  'active_fi' => array('integer', $row['active_fi']),
11849  'pass' => array('integer', $row['pass'])
11850  ));
11851  }
11852  } else {
11853  $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : array());
11854 
11855  $query = "
11856  SELECT tseq.*
11857  FROM tst_active tac
11858  INNER JOIN tst_sequence tseq
11859  ON tseq.active_fi = tac.active_id
11860  WHERE tac.test_fi = %s
11861  ";
11862 
11863  $part_rest = $ilDB->queryF(
11864  $query,
11865  array('integer'),
11866  array($this->getTestId())
11867  );
11868 
11869  while ($row = $ilDB->fetchAssoc($part_rest)) {
11870  $ilDB->update('tst_sequence', array(
11871  'sequence' => array('clob', $new_sequence)
11872  ), array(
11873  'active_fi' => array('integer', $row['active_fi']),
11874  'pass' => array('integer', $row['pass'])
11875  ));
11876  }
11877  }
11878  }
11879 }
$files
Definition: add-vimline.php:18
setAllowedUsers($a_allowed_users)
static _getUserIdFromActiveId($active_id)
$params
Definition: disable.php:11
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.
static getPluginObject($a_ctype, $a_cname, $a_slot_id, $a_pname)
Get plugin object.
setSkillServiceEnabled($skillServiceEnabled)
getListOfQuestionsDescription()
Returns TRUE if the list of questions should be presented with the question descriptions.
setOldOnlineStatus($oldOnlineStatus)
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.
const REPORT_AFTER_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.
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
setPassDeletionAllowed($passDeletionAllowed)
setter for the test setting passDeletionAllowed
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
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.
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)
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.
$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.
$online
the object&#39;s online status
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
This class handles all operations on files (attachments) in directory ilias_data/mail.
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.
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.
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.
static formatDate(ilDateTime $date, $a_skip_day=false, $a_include_wd=false)
Format a date public.
& 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 ...
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
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.
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.
$userdata
Definition: demo.php:48
& 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.
static _lookupTitle($a_id)
lookup object title
getAnonymity()
Returns the anonymity status of the test.
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.
Resolve range
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)
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.
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.
canShowTestResults($testSession)
isRandomTest()
Returns the fact wether this test is a random questions test or not.
canViewResults()
Returns true, if the test results can be viewed.
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
$counter
$time
Definition: cron.php:21
updateWorkingTime($times_id)
Update the working time of a test when a question is answered.
Interface ilDBInterface.
$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)
$xml
Definition: metadata.php:240
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...
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\+" &#(? foreach( $entity_files as $file) $output
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.
getMarkSchemaForeignId()
{int}
setNrOfTries($nr_of_tries=0)
Sets the nr of tries for the test.
if($format !==null) $name
Definition: metadata.php:146
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
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.
setScoringFeedbackOptionsByArray($options)
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:61
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 ...
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.
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.
evalTotalFinished()
Returns the number of total finished tests.
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
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
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.
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()
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.
Create styles array
The data for the language used.
getFinalStatement()
Gets the final statement.
setKiosk($kiosk=0)
Sets the kiosk mode for the test.
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.
setTimingType($a_type)
Set timing type.
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
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)
Create a temporary file in an ILIAS writable 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)
evalTotalStartedAverageTime()
Returns the average processing time for all started tests.
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)
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.
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}
Create PDF certificates.
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.
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
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
A class defining mark schemas for assessment test objects.
if(!file_exists("$old.txt")) if($old===$new) if(file_exists("$new.txt")) $file
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.
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
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.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
$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.
$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)
getPassScoring()
Gets the pass scoring type.