ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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  var $test_id;
88 
95 
102  var $author;
103 
110 
117 
122 
129  protected $introduction;
130 
137 
146 
157 
166 
173 
183 
190 
198 
206 
216 
223 
230 
237 
242 
248  protected $starting_time;
249 
254 
260  protected $ending_time;
261 
266  protected $ects_output = FALSE;
267 
272  protected $ects_fx = NULL;
273 
278  protected $ects_grades = array();
279 
280 
288 
295 
302 
310 
317 
324 
331 
335  protected $passwordEnabled;
336 
342  protected $password;
343 
348 
354  protected $allowedUsers;
355 
362 
369 
376 
383 
390 
397 
404 
411 
418 
425 
432 
438  private $_showinfo;
439 
445  private $_forcejs = TRUE;
446 
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  function create()
739  {
740  parent::create();
741 
742  // meta data will be created by
743  // import parser
744  if (!$a_upload)
745  {
746  $this->createMetaData();
747  }
748  }
749 
756  function update()
757  {
758  if (!parent::update())
759  {
760  return false;
761  }
762 
763  // put here object specific stuff
764  $this->updateMetaData();
765  return true;
766  }
767 
773  public function read()
774  {
775  parent::read();
776  $this->loadFromDb();
777  }
778 
779 
786  function delete()
787  {
788  // always call parent delete function first!!
789  if (!parent::delete())
790  {
791  return false;
792  }
793 
794  // delet meta data
795  $this->deleteMetaData();
796 
797  //put here your module specific stuff
798  $this->deleteTest();
799 
800  require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentImportFails.php';
801  $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($this->getId());
802  $qsaImportFails->deleteRegisteredImportFails();
803  require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdImportFails.php';
804  $sltImportFails = new ilTestSkillLevelThresholdImportFails($this->getId());
805  $sltImportFails->deleteRegisteredImportFails();
806 
807  return true;
808  }
809 
815  function deleteTest()
816  {
817  global $tree, $ilDB, $ilPluginAdmin, $lng;
818 
819  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
820  $participantData = new ilTestParticipantData($ilDB, $lng);
821  $participantData->load($this->getTestId());
822  $this->removeTestResults($participantData);
823 
824  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_mark WHERE test_fi = %s",
825  array('integer'),
826  array($this->getTestId())
827  );
828 
829  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_tests WHERE test_id = %s",
830  array('integer'),
831  array($this->getTestId())
832  );
833 
834  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
835  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
836  $testQuestionSetConfigFactory->getQuestionSetConfig()->removeQuestionSetRelatedData();
837 
838  // delete export files
839  include_once "./Services/Utilities/classes/class.ilUtil.php";
840  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
841  $directory = $tst_data_dir."/tst_".$this->getId();
842  if (is_dir($directory))
843  {
844  include_once "./Services/Utilities/classes/class.ilUtil.php";
845  ilUtil::delDir($directory);
846  }
847  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
848  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
849  // remaining usages are not in text anymore -> delete them
850  // and media objects (note: delete method of ilObjMediaObject
851  // checks whether object is used in another context; if yes,
852  // the object is not deleted!)
853  foreach($mobs as $mob)
854  {
855  ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
856  if (ilObjMediaObject::_exists($mob))
857  {
858  $mob_obj = new ilObjMediaObject($mob);
859  $mob_obj->delete();
860  }
861  }
862  }
863 
870  {
871  include_once "./Services/Utilities/classes/class.ilUtil.php";
872  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
873  ilUtil::makeDir($tst_data_dir);
874  if (!is_writable($tst_data_dir))
875  {
876  $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
877  .") not writeable.",$this->ilias->error_obj->MESSAGE);
878  }
879 
880  // create learning module directory (data_dir/lm_data/lm_<id>)
881  $tst_dir = $tst_data_dir."/tst_".$this->getId();
882  ilUtil::makeDir($tst_dir);
883  if (!@is_dir($tst_dir))
884  {
885  $this->ilias->raiseError("Creation of Test Directory failed.",$this->ilias->error_obj->MESSAGE);
886  }
887  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
888  $export_dir = $tst_dir."/export";
889  ilUtil::makeDir($export_dir);
890  if (!@is_dir($export_dir))
891  {
892  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->MESSAGE);
893  }
894  }
895 
902  {
903  include_once "./Services/Utilities/classes/class.ilUtil.php";
904  $export_dir = ilUtil::getDataDir()."/tst_data"."/tst_".$this->getId()."/export";
905  return $export_dir;
906  }
907 
914  function getExportFiles($dir)
915  {
916  // quit if import dir not available
917  if(!@is_dir($dir) || !is_writeable($dir))
918  {
919  return array();
920  }
921 
922  $files = array();
923  foreach(new DirectoryIterator($dir) as $file)
924  {
928  if($file->isDir())
929  {
930  continue;
931  }
932 
933  $files[] = $file->getBasename();
934  }
935 
936  sort($files);
937 
938  return $files;
939  }
940 
944  public static function _setImportDirectory($a_import_dir = null)
945  {
946  if (strlen($a_import_dir))
947  {
948  $_SESSION["tst_import_dir"] = $a_import_dir;
949  }
950  else
951  {
952  unset($_SESSION["tst_import_dir"]);
953  }
954  }
955 
962  public static function _getImportDirectory()
963  {
964  if (strlen($_SESSION["tst_import_dir"]))
965  {
966  return $_SESSION["tst_import_dir"];
967  }
968  return null;
969  }
970 
972  {
974  }
975 
981  public static function _createImportDirectory()
982  {
983  global $ilias;
984  include_once "./Services/Utilities/classes/class.ilUtil.php";
985  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
986  ilUtil::makeDir($tst_data_dir);
987 
988  if (!is_writable($tst_data_dir))
989  {
990  $ilias->raiseError("Test Data Directory (".$tst_data_dir
991  .") not writeable.", $ilias->error_obj->FATAL);
992  }
993 
994  // create test directory (data_dir/tst_data/tst_import)
995  $tst_dir = $tst_data_dir."/tst_import";
996  ilUtil::makeDir($tst_dir);
997  if (!@is_dir($tst_dir))
998  {
999  $ilias->raiseError("Creation of test import directory failed.",$ilias->error_obj->FATAL);
1000  }
1001 
1002  // assert that this is empty and does not contain old data
1003  ilUtil::delDir($tst_dir, true);
1004 
1005  return $tst_dir;
1006  }
1007 
1015  {
1016  global $ilDB;
1017 
1018  $result = $ilDB->queryF("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",
1019  array('integer'),
1020  array($this->getTestId())
1021  );
1022  $hasSC = false;
1023  while ($row = $ilDB->fetchAssoc($result))
1024  {
1025  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0)
1026  {
1027  $hasSC = true;
1028  }
1029  }
1030  return $hasSC;
1031  }
1032 
1040  {
1041  global $ilDB;
1042 
1043  $result = $ilDB->queryF("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",
1044  array('integer'),
1045  array($this->getTestId())
1046  );
1047  if ($result->numRows() == 1)
1048  {
1049  $row = $ilDB->fetchAssoc($result);
1050  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0)
1051  {
1052  return TRUE;
1053  }
1054  else
1055  {
1056  return false;
1057  }
1058  }
1059  return FALSE;
1060  }
1061 
1069  {
1070  global $ilDB;
1071 
1072  if (!$this->hasSingleChoiceQuestions()) return false;
1073 
1074  $result = $ilDB->queryF("
1075  SELECT DISTINCT(qpl_qst_sc.shuffle) foundshuffles
1076  FROM qpl_questions,
1077  qpl_qst_sc,
1078  tst_test_result,
1079  qpl_qst_type,
1080  tst_active
1081  WHERE tst_test_result.question_fi = qpl_questions.question_id
1082  AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
1083  AND tst_test_result.active_fi = tst_active.active_id
1084  AND qpl_questions.question_id = qpl_qst_sc.question_fi
1085  AND tst_active.test_fi = %s
1086  AND qpl_qst_type.type_tag = %s
1087  ",
1088  array('integer', 'text'),
1089  array($this->getTestId(), 'assSingleChoice')
1090  );
1091  if ($result->numRows() == 1)
1092  {
1093  $row = $ilDB->fetchAssoc($result);
1094  return ($row['foundshuffles'] == 0);
1095  }
1096  return FALSE;
1097  }
1098 
1105  final public function isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
1106  {
1107  if( !count($this->mark_schema->mark_steps) )
1108  {
1109  return false;
1110  }
1111 
1112  if( !$testQuestionSetConfig->isQuestionSetConfigured() )
1113  {
1114  return false;
1115  }
1116 
1117  return true;
1118  }
1119 
1126  function _isComplete($obj_id)
1127  {
1128  global $tree, $ilDB, $ilPluginAdmin;
1129 
1130  $test = new ilObjTest($obj_id, false);
1131  $test->loadFromDb();
1132 
1133  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1134  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
1135 
1136  return $test->isComplete( $testQuestionSetConfigFactory->getQuestionSetConfig() );
1137  }
1138 
1142  public function saveECTSStatus()
1143  {
1147  global $ilDB;
1148 
1149  if($this->getTestId() > 0)
1150  {
1151  $this->setECTSFX(preg_replace('/,/', '.', $this->getECTSFX()));
1152  if(!preg_match('/\d+/', $this->getECTSFX()))
1153  {
1154  $this->setECTSFX(NULL);
1155  }
1156 
1157  $grades = $this->getECTSGrades();
1158  $ilDB->manipulateF(
1159  "UPDATE tst_tests
1160  SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s
1161  WHERE test_id = %s",
1162  array('text', 'float', 'float', 'float', 'float', 'float', 'float', 'integer'),
1163  array(
1164  (int)$this->getECTSOutput(),
1165  $grades['A'], $grades['B'], $grades['C'], $grades['D'], $grades['E'],
1166  $this->getECTSFX(),
1167  $this->getTestId()
1168  )
1169  );
1170  }
1171  }
1172 
1177  public function saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
1178  {
1179  global $ilDB;
1180 
1181  $complete = 0;
1182  if($this->isComplete($testQuestionSetConfig))
1183  {
1184  $complete = 1;
1185  }
1186  if($this->getTestId() > 0)
1187  {
1188  $ilDB->manipulateF(
1189  "UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1190  array('text', 'integer'),
1191  array($complete, $this->test_id)
1192  );
1193  }
1194  }
1195 
1201  function getAllRTEContent()
1202  {
1203  $result = array();
1204  array_push($result, $this->getIntroduction());
1205  array_push($result, $this->getFinalStatement());
1206  return $result;
1207  }
1208 
1215  {
1216  include_once("./Services/RTE/classes/class.ilRTE.php");
1217  $completecontent = "";
1218  foreach ($this->getAllRTEContent() as $content)
1219  {
1220  $completecontent .= $content;
1221  }
1222  ilRTE::_cleanupMediaObjectUsage($completecontent, $this->getType() . ":html",
1223  $this->getId());
1224  }
1225 
1231  public function saveToDb($properties_only = FALSE)
1232  {
1233  global $tree, $ilDB, $ilPluginAdmin;
1234 
1235  // moved online_status to ilObjectActivation (see below)
1236 
1237  // cleanup RTE images
1238  $this->cleanupMediaobjectUsage();
1239 
1240  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1241  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
1242  $testQuestionSetConfig = $testQuestionSetConfigFactory->getQuestionSetConfig();
1243 
1244  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1245  if ($this->test_id == -1)
1246  {
1247  // Create new dataset
1248  $next_id = $ilDB->nextId('tst_tests');
1249 
1250  $ilDB->insert('tst_tests', array(
1251  'test_id' => array('integer', $next_id),
1252  'obj_fi' => array('integer', $this->getId()),
1253  'author' => array('text', $this->getAuthor()),
1254  'intro_enabled' => array('integer', (int)$this->isIntroductionEnabled()),
1255  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1256  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1257  'showinfo' => array('integer', $this->getShowInfo()),
1258  'forcejs' => array('integer', $this->getForceJS()),
1259  'customstyle' => array('text', $this->getCustomStyle()),
1260  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1261  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1262  'score_reporting' => array('integer', $this->getScoreReporting()),
1263  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1264  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1265  'answer_feedback' => array('text', $this->getAnswerFeedback()),
1266  'anonymity' => array('text', $this->getAnonymity()),
1267  'show_cancel' => array('text', $this->getShowCancel()),
1268  'show_marker' => array('integer', $this->getShowMarker()),
1269  'fixed_participants' => array('text', $this->getFixedParticipants()),
1270  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1271  'kiosk' => array('integer', $this->getKiosk()),
1272  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1273  'title_output' => array('text', $this->getTitleOutput()),
1274  'processing_time' => array('text', $this->getProcessingTime()),
1275  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1276  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1277  'reporting_date' => array('text', $this->getReportingDate()),
1278  'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1279  'starting_time' => array('integer', $this->getStartingTime()),
1280  'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1281  'ending_time' => array('integer', $this->getEndingTime()),
1282  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1283  'ects_output' => array('text', $this->getECTSOutput()),
1284  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : NULL),
1285  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : NULL),
1286  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : NULL),
1287  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : NULL),
1288  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : NULL),
1289  'ects_fx' => array('float', $this->getECTSFX()),
1290  'count_system' => array('text', $this->getCountSystem()),
1291  'mc_scoring' => array('text', $this->getMCScoring()),
1292  'score_cutting' => array('text', $this->getScoreCutting()),
1293  'pass_scoring' => array('text', $this->getPassScoring()),
1294  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1295  'results_presentation' => array('integer', $this->getResultsPresentation()),
1296  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1297  'password_enabled' => array('integer', (int)$this->isPasswordEnabled()),
1298  'password' => array('text', $this->getPassword()),
1299  'limit_users_enabled' => array('integer', (int)$this->isLimitUsersEnabled()),
1300  'allowedusers' => array('integer', $this->getAllowedUsers()),
1301  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1302  'mailnottype' => array('integer', $this->getMailNotificationType()),
1303  'exportsettings' => array('integer', $this->getExportSettings()),
1304  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1305  'mailnotification' => array('integer', $this->getMailNotification()),
1306  'created' => array('integer', time()),
1307  'tstamp' => array('integer', time()),
1308  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1309  'template_id' => array('integer', $this->getTemplate()),
1310  'pool_usage' => array('integer', $this->getPoolUsage()),
1311  'print_bs_with_res' => array('integer', (int)$this->isBestSolutionPrintedWithResult()),
1312  'obligations_enabled' => array('integer', (int)$this->areObligationsEnabled()),
1313  'offer_question_hints' => array('integer', (int)$this->isOfferingQuestionHintsEnabled()),
1314  'highscore_enabled' => array('integer', (int)$this->getHighscoreEnabled()),
1315  'highscore_anon' => array('integer', (int)$this->getHighscoreAnon()),
1316  'highscore_achieved_ts' => array('integer', (int)$this->getHighscoreAchievedTS()),
1317  'highscore_score' => array('integer', (int)$this->getHighscoreScore()),
1318  'highscore_percentage' => array('integer', (int)$this->getHighscorePercentage()),
1319  'highscore_hints' => array('integer', (int)$this->getHighscoreHints()),
1320  'highscore_wtime' => array('integer', (int)$this->getHighscoreWTime()),
1321  'highscore_own_table' => array('integer', (int)$this->getHighscoreOwnTable()),
1322  'highscore_top_table' => array('integer', (int)$this->getHighscoreTopTable()),
1323  'highscore_top_num' => array('integer', (int)$this->getHighscoreTopNum()),
1324  'online_status' => array('integer', (int)$this->isOnline()),
1325  'specific_feedback' => array('integer', (int)$this->getSpecificAnswerFeedback()),
1326  'autosave' => array('integer', (int)$this->getAutosave()),
1327  'autosave_ival' => array('integer', (int)$this->getAutosaveIval()),
1328  'pass_deletion_allowed' => array('integer', (int)$this->isPassDeletionAllowed()),
1329  'enable_examview' => array('integer', (int)$this->getEnableExamview()),
1330  'show_examview_html' => array('integer', (int)$this->getShowExamviewHtml()),
1331  'show_examview_pdf' => array('integer', (int)$this->getShowExamviewPdf()),
1332  'redirection_mode' => array('integer', (int)$this->getRedirectionMode()),
1333  'redirection_url' => array('text', (string)$this->getRedirectionUrl()),
1334  'enable_archiving' => array('integer', (int)$this->getEnableArchiving()),
1335  'examid_in_test_pass' => array('integer', (int)$this->isShowExamIdInTestPassEnabled()),
1336  'examid_in_test_res' => array('integer', (int)$this->isShowExamIdInTestResultsEnabled()),
1337  'sign_submission' => array('integer', (int)$this->getSignSubmission()),
1338  'question_set_type' => array('text', $this->getQuestionSetType()),
1339  'char_selector_availability' => array('integer', (int)$this->getCharSelectorAvailability()),
1340  'char_selector_definition' => array('text', (string)$this->getCharSelectorDefinition()),
1341  'skill_service' => array('integer', (int)$this->isSkillServiceEnabled()),
1342  'result_tax_filters' => array('text', serialize((array)$this->getResultFilterTaxIds())),
1343  'show_grading_status' => array('integer', (int)$this->isShowGradingStatusEnabled()),
1344  'show_grading_mark' => array('integer', (int)$this->isShowGradingMarkEnabled()),
1345  'inst_fb_answer_fixation' => array('integer', (int)$this->isInstantFeedbackAnswerFixationEnabled()),
1346  'force_inst_fb' => array('integer', (int)$this->isForceInstantFeedbackEnabled()),
1347  'broken' => array('integer', (int)$this->isTestFinalBroken()),
1348  'pass_waiting' => array('text', (string)$this->getPassWaiting())
1349  ));
1350 
1351  $this->test_id = $next_id;
1352 
1354  {
1355  $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1356  }
1357  }
1358  else
1359  {
1360  // Modify existing dataset
1361  $oldrow = array();
1363  {
1364  $result = $ilDB->queryF("SELECT * FROM tst_tests WHERE test_id = %s",
1365  array('integer'),
1366  array($this->test_id)
1367  );
1368  if ($result->numRows() == 1)
1369  {
1370  $oldrow = $ilDB->fetchAssoc($result);
1371  }
1372  }
1373 
1374  $ilDB->update('tst_tests',
1375  array(
1376  'author' => array('text', $this->getAuthor()),
1377  'intro_enabled' => array('integer', (int)$this->isIntroductionEnabled()),
1378  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1379  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1380  'showinfo' => array('integer', $this->getShowInfo()),
1381  'forcejs' => array('integer', $this->getForceJS()),
1382  'customstyle' => array('text', $this->getCustomStyle()),
1383  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1384  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1385  'score_reporting' => array('integer', $this->getScoreReporting()),
1386  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1387  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1388  'answer_feedback' => array('text', $this->getGenericAnswerFeedback()),
1389  'anonymity' => array('text', $this->getAnonymity()),
1390  'show_cancel' => array('text', $this->getShowCancel()),
1391  'show_marker' => array('integer', $this->getShowMarker()),
1392  'fixed_participants' => array('text', $this->getFixedParticipants()),
1393  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1394  'kiosk' => array('integer', $this->getKiosk()),
1395  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1396  'title_output' => array('text', $this->getTitleOutput()),
1397  'processing_time' => array('text', $this->getProcessingTime()),
1398  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1399  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1400  'reporting_date' => array('text', $this->getReportingDate()),
1401  'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1402  'starting_time' => array('integer', $this->getStartingTime()),
1403  'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1404  'ending_time' => array('integer', $this->getEndingTime()),
1405  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1406  'ects_output' => array('text', $this->getECTSOutput()),
1407  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : NULL),
1408  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : NULL),
1409  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : NULL),
1410  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : NULL),
1411  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : NULL),
1412  'ects_fx' => array('float', $this->getECTSFX()),
1413  'count_system' => array('text', $this->getCountSystem()),
1414  'mc_scoring' => array('text', $this->getMCScoring()),
1415  'score_cutting' => array('text', $this->getScoreCutting()),
1416  'pass_scoring' => array('text', $this->getPassScoring()),
1417  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1418  'results_presentation' => array('integer', $this->getResultsPresentation()),
1419  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1420  'password_enabled' => array('integer', (int)$this->isPasswordEnabled()),
1421  'password' => array('text', $this->getPassword()),
1422  'limit_users_enabled' => array('integer', (int)$this->isLimitUsersEnabled()),
1423  'allowedusers' => array('integer', $this->getAllowedUsers()),
1424  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1425  'mailnottype' => array('integer', $this->getMailNotificationType()),
1426  'exportsettings' => array('integer', $this->getExportSettings()),
1427  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1428  'mailnotification' => array('integer', $this->getMailNotification()),
1429  'tstamp' => array('integer', time()),
1430  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1431  'template_id' => array('integer', $this->getTemplate()),
1432  'pool_usage' => array('integer', $this->getPoolUsage()),
1433  'print_bs_with_res' => array('integer', (int)$this->isBestSolutionPrintedWithResult()),
1434  'obligations_enabled' => array('integer', (int)$this->areObligationsEnabled()),
1435  'offer_question_hints' => array('integer', (int)$this->isOfferingQuestionHintsEnabled()),
1436  'highscore_enabled' => array('integer', (int)$this->getHighscoreEnabled()),
1437  'highscore_anon' => array('integer', (int)$this->getHighscoreAnon()),
1438  'highscore_achieved_ts' => array('integer', (int)$this->getHighscoreAchievedTS()),
1439  'highscore_score' => array('integer', (int)$this->getHighscoreScore()),
1440  'highscore_percentage' => array('integer', (int)$this->getHighscorePercentage()),
1441  'highscore_hints' => array('integer', (int)$this->getHighscoreHints()),
1442  'highscore_wtime' => array('integer', (int)$this->getHighscoreWTime()),
1443  'highscore_own_table' => array('integer', (int)$this->getHighscoreOwnTable()),
1444  'highscore_top_table' => array('integer', (int)$this->getHighscoreTopTable()),
1445  'highscore_top_num' => array('integer', (int)$this->getHighscoreTopNum()),
1446  'online_status' => array('integer', (int)$this->isOnline()),
1447  'specific_feedback' => array('integer', (int)$this->getSpecificAnswerFeedback()),
1448  'autosave' => array('integer', (int)$this->getAutosave()),
1449  'autosave_ival' => array('integer', (int)$this->getAutosaveIval()),
1450  'pass_deletion_allowed' => array('integer', (int)$this->isPassDeletionAllowed()),
1451  'enable_examview' => array('integer', (int)$this->getEnableExamview()),
1452  'show_examview_html' => array('integer', (int)$this->getShowExamviewHtml()),
1453  'show_examview_pdf' => array('integer', (int)$this->getShowExamviewPdf()),
1454  'redirection_mode' => array('integer', (int)$this->getRedirectionMode()),
1455  'redirection_url' => array('text', (string)$this->getRedirectionUrl()),
1456  'enable_archiving' => array('integer', (int)$this->getEnableArchiving()),
1457  'examid_in_test_pass' => array('integer', (int)$this->isShowExamIdInTestPassEnabled()),
1458  'examid_in_test_res' => array('integer', (int)$this->isShowExamIdInTestResultsEnabled()),
1459  'sign_submission' => array('integer', (int)$this->getSignSubmission()),
1460  'question_set_type' => array('text', $this->getQuestionSetType()),
1461  'char_selector_availability' => array('integer', (int)$this->getCharSelectorAvailability()),
1462  'char_selector_definition' => array('text', (string)$this->getCharSelectorDefinition()),
1463  'skill_service' => array('integer', (int)$this->isSkillServiceEnabled()),
1464  'result_tax_filters' => array('text', serialize((array)$this->getResultFilterTaxIds())),
1465  'show_grading_status' => array('integer', (int)$this->isShowGradingStatusEnabled()),
1466  'show_grading_mark' => array('integer', (int)$this->isShowGradingMarkEnabled()),
1467  'inst_fb_answer_fixation' => array('integer', (int)$this->isInstantFeedbackAnswerFixationEnabled()),
1468  'force_inst_fb' => array('integer', (int)$this->isForceInstantFeedbackEnabled()),
1469  'broken' => array('integer', (int)$this->isTestFinalBroken()),
1470  'pass_waiting' => array('text', (string)$this->getPassWaiting())
1471  ),
1472  array(
1473  'test_id' => array('integer', (int)$this->getTestId())
1474  )
1475  );
1476 
1477  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1479  {
1480  $logresult = $ilDB->queryF("SELECT * FROM tst_tests WHERE test_id = %s",
1481  array('integer'),
1482  array($this->getTestId())
1483  );
1484  $newrow = array();
1485  if ($logresult->numRows() == 1)
1486  {
1487  $newrow = $ilDB->fetchAssoc($logresult);
1488  }
1489  $changed_fields = array();
1490  foreach ($oldrow as $key => $value)
1491  {
1492  if (strcmp($oldrow[$key], $newrow[$key]) != 0)
1493  {
1494  array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1495  }
1496  }
1497  $changes = join($changed_fields, ", ");
1498  if (count($changed_fields) > 0)
1499  {
1500  $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [".$changes."]");
1501  }
1502  }
1503  if ($this->evalTotalPersons() > 0)
1504  {
1505  // reset the finished status of participants if the nr of test passes did change
1506  if ($this->getNrOfTries() > 0)
1507  {
1508  // set all unfinished tests with nr of passes >= allowed passes finished
1509  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
1510  array('integer', 'integer', 'integer'),
1511  array($this->getTestId(), $this->getNrOfTries(), 0)
1512  );
1513  while ($row = $ilDB->fetchAssoc($aresult))
1514  {
1515  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1516  array('integer', 'timestamp', 'integer'),
1517  array(1, date('Y-m-d H:i:s'), $row["active_id"])
1518  );
1519  }
1520 
1521  // set all finished tests with nr of passes < allowed passes not finished
1522  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
1523  array('integer', 'integer', 'integer'),
1524  array($this->getTestId(), $this->getNrOfTries()-1, 1)
1525  );
1526  while ($row = $ilDB->fetchAssoc($aresult))
1527  {
1528  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1529  array('integer', 'timestamp', 'integer'),
1530  array(0, NULL, $row["active_id"])
1531  );
1532  }
1533  }
1534  else
1535  {
1536  // set all finished tests with nr of passes >= allowed passes not finished
1537  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
1538  array('integer', 'integer'),
1539  array($this->getTestId(), 1)
1540  );
1541  while ($row = $ilDB->fetchAssoc($aresult))
1542  {
1543  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1544  array('integer', 'timestamp', 'integer'),
1545  array(0, NULL, $row["active_id"])
1546  );
1547  }
1548  }
1549  }
1550  }
1551 
1552  // news item creation/update/deletion
1553  include_once 'Services/News/classes/class.ilNewsItem.php';
1554  if( !$this->getOldOnlineStatus() && $this->isOnline() )
1555  {
1556  global $ilUser;
1557  $newsItem = new ilNewsItem();
1558  $newsItem->setContext($this->getId(), 'tst');
1559  $newsItem->setPriority(NEWS_NOTICE);
1560  $newsItem->setTitle('new_test_online');
1561  $newsItem->setContentIsLangVar(true);
1562  $newsItem->setContent('');
1563  $newsItem->setUserId($ilUser->getId());
1564  $newsItem->setVisibility(NEWS_USERS);
1565  $newsItem->create();
1566  }
1567  elseif( $this->getOldOnlineStatus() && !$this->isOnline() )
1568  {
1569  ilNewsItem::deleteNewsOfContext($this->getId(), 'tst');
1570  }
1571  elseif( $this->isOnline() )
1572  {
1573  $newsId = ilNewsItem::getFirstNewsIdForContext($this->getId(), 'tst');
1574  if($newsId > 0)
1575  {
1576  $newsItem = new ilNewsItem($newsId);
1577  $newsItem->setTitle('new_test_online');
1578  $newsItem->setContentIsLangVar(true);
1579  $newsItem->setContent('');
1580  $newsItem->update();
1581  }
1582  }
1583 
1584  // moved activation to ilObjectActivation
1585  if($this->ref_id)
1586  {
1587  include_once "./Services/Object/classes/class.ilObjectActivation.php";
1588  ilObjectActivation::getItem($this->ref_id);
1589 
1590  $item = new ilObjectActivation;
1591  if(!$this->isActivationLimited())
1592  {
1594  }
1595  else
1596  {
1597  $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
1598  $item->setTimingStart($this->getActivationStartingTime());
1599  $item->setTimingEnd($this->getActivationEndingTime());
1600  $item->toggleVisible($this->getActivationVisibility());
1601  }
1602 
1603  $item->update($this->ref_id);
1604  }
1605 
1606  if (!$properties_only)
1607  {
1608  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED)
1609  {
1610  $this->saveQuestionsToDb();
1611  }
1612 
1613  $this->mark_schema->saveToDb($this->test_id);
1614  }
1615  }
1616 
1624  {
1625  global $ilDB;
1626 
1627  $oldquestions = array();
1628  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1630  {
1631  $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1632  array('integer'),
1633  array($this->getTestId())
1634  );
1635  if ($result->numRows() > 0)
1636  {
1637  while ($row = $ilDB->fetchAssoc($result))
1638  {
1639  array_push($oldquestions, $row["question_fi"]);
1640  }
1641  }
1642  }
1643  // workaround for lost obligations
1644  // this method is called if a question is removed
1645  $currentQuestionsObligationsQuery = 'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
1646  $rset = $ilDB->queryF($currentQuestionsObligationsQuery, array('integer'), array($this->getTestId()));
1647  while ($row = $ilDB->fetchAssoc($rset)) {
1648  $obligatoryQuestionState[$row['question_fi']] = $row['obligatory'];
1649  }
1650  // delete existing category relations
1651  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_question WHERE test_fi = %s",
1652  array('integer'),
1653  array($this->getTestId())
1654  );
1655  // create new category relations
1656  foreach ($this->questions as $key => $value)
1657  {
1658  // workaround for import witout obligations information
1659  if( !isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value]) )
1660  {
1661  $obligatoryQuestionState[$value] = 0;
1662  }
1663 
1664  // insert question
1665  $next_id = $ilDB->nextId('tst_test_question');
1666  $ilDB->insert('tst_test_question', array(
1667  'test_question_id' => array('integer', $next_id),
1668  'test_fi' => array('integer', $this->getTestId()),
1669  'question_fi' => array('integer', $value),
1670  'sequence' => array('integer', $key),
1671  'obligatory' => array('integer', $obligatoryQuestionState[$value]),
1672  'tstamp' => array('integer', time())
1673  ));
1674  }
1675  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1677  {
1678  $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1679  array('integer'),
1680  array($this->getTestId())
1681  );
1682  $newquestions = array();
1683  if ($result->numRows() > 0)
1684  {
1685  while ($row = $ilDB->fetchAssoc($result))
1686  {
1687  array_push($newquestions, $row["question_fi"]);
1688  }
1689  }
1690  foreach ($oldquestions as $index => $question_id)
1691  {
1692  if (strcmp($newquestions[$index], $question_id) != 0)
1693  {
1694  $pos = array_search($question_id, $newquestions);
1695  if ($pos === FALSE)
1696  {
1697  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1698  }
1699  else
1700  {
1701  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1) . " => " . ($pos+1), $question_id);
1702  }
1703  }
1704  }
1705  foreach ($newquestions as $index => $question_id)
1706  {
1707  if (array_search($question_id, $oldquestions) === FALSE)
1708  {
1709  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1), $question_id);
1710  }
1711  }
1712  }
1713  }
1714 
1720  protected function isNewRandomTest()
1721  {
1722  global $ilDB;
1723  $result = $ilDB->queryF('SELECT copy_id FROM tst_rnd_cpy WHERE tst_fi = %s',
1724  array('integer'),
1725  array($this->getTestId())
1726  );
1727  return $result->numRows() > 0;
1728  }
1729 
1742  function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = NULL)
1743  {
1744  global $rbacsystem;
1745  global $ilDB;
1746 
1747  // retrieve object id instead of ref id if necessary
1748  if (($questionpool != 0) && (!$use_obj_id)) $questionpool = ilObject::_lookupObjId($questionpool);
1749 
1750  // get original ids of all existing questions in the test
1751  $result = $ilDB->queryF("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",
1752  array("integer"),
1753  array($this->getTestId())
1754  );
1755  $original_ids = array();
1756  $paramtypes = array();
1757  $paramvalues = array();
1758  while ($row = $ilDB->fetchAssoc($result))
1759  {
1760  array_push($original_ids, $row['original_id']);
1761  }
1762 
1763  $available = "";
1764  // get a list of all available questionpools
1765  if (($questionpool == 0) && (!is_array($qpls)))
1766  {
1767  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1768  $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())));
1769  if (count($available_pools))
1770  {
1771  $available = " AND " . $ilDB->in('obj_fi', $available_pools, false, 'integer');
1772  }
1773  else
1774  {
1775  return array();
1776  }
1777  }
1778 
1779  $constraint_qpls = "";
1780  $result_array = array();
1781  if ($questionpool == 0)
1782  {
1783  if (is_array($qpls))
1784  {
1785  if (count($qpls) > 0)
1786  {
1787  $constraint_qpls = " AND " . $ilDB->in('obj_fi', $qpls, false, 'integer');
1788  }
1789  }
1790  }
1791 
1792  $original_clause = "";
1793  if (count($original_ids))
1794  {
1795  $original_clause = " AND " . $ilDB->in('question_id', $original_ids, true, 'integer');
1796  }
1797 
1798  if ($questionpool == 0)
1799  {
1800  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id IS NULL $available $constraint_qpls AND owner > %s AND complete = %s $original_clause",
1801  array('integer', 'text'),
1802  array(0, "1")
1803  );
1804  }
1805  else
1806  {
1807  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id IS NULL AND obj_fi = %s AND owner > %s AND complete = %s $original_clause",
1808  array('integer','integer', 'text'),
1809  array($questionpool, 0, "1")
1810  );
1811  }
1812  $found_ids = array();
1813  while ($row = $ilDB->fetchAssoc($result))
1814  {
1815  array_push($found_ids, $row['question_id']);
1816  }
1817  $nr_of_questions = ($nr_of_questions > count($found_ids)) ? count($found_ids) : $nr_of_questions;
1818  if ($nr_of_questions == 0) return array();
1819  $rand_keys = array_rand($found_ids, $nr_of_questions);
1820  $result = array();
1821  if (is_array($rand_keys))
1822  {
1823  foreach ($rand_keys as $key)
1824  {
1825  $result[$found_ids[$key]] = $found_ids[$key];
1826  }
1827  }
1828  else
1829  {
1830  $result[$found_ids[$rand_keys]] = $found_ids[$rand_keys];
1831  }
1832  return $result;
1833  }
1834 
1842  function getNrOfResultsForPass($active_id, $pass)
1843  {
1844  global $ilDB;
1845 
1846  $result = $ilDB->queryF("SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1847  array('integer','integer'),
1848  array($active_id, $pass)
1849  );
1850  return $result->numRows();
1851  }
1852 
1863  function hasRandomQuestionsForPass($active_id, $pass)
1864  {
1865  global $ilDB;
1866  $result = $ilDB->queryF("SELECT test_random_question_id FROM tst_test_rnd_qst WHERE active_fi = %s AND pass = %s",
1867  array('integer','integer'),
1868  array($active_id, $pass)
1869  );
1870  return ($result->numRows() > 0) ? true : false;
1871  }
1872 
1876  public function loadFromDb()
1877  {
1878  global $ilDB;
1879 
1880  $result = $ilDB->queryF("SELECT * FROM tst_tests WHERE obj_fi = %s",
1881  array('integer'),
1882  array($this->getId())
1883  );
1884  if ($result->numRows() == 1)
1885  {
1886  $data = $ilDB->fetchObject($result);
1887  $this->setTestId($data->test_id);
1888  if (strlen($this->getAuthor()) == 0)
1889  {
1890  $this->saveAuthorToMetadata($data->author);
1891  }
1892  $this->setAuthor($data->author);
1893  include_once("./Services/RTE/classes/class.ilRTE.php");
1894  $this->setIntroductionEnabled($data->intro_enabled);
1895  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc($data->introduction, 1));
1896  $this->setShowInfo($data->showinfo);
1897  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc($data->finalstatement, 1));
1898  $this->setForceJS($data->forcejs);
1899  $this->setCustomStyle($data->customstyle);
1900  $this->setShowFinalStatement($data->showfinalstatement);
1901  $this->setSequenceSettings($data->sequence_settings);
1902  $this->setScoreReporting($data->score_reporting);
1903  $this->setInstantFeedbackSolution($data->instant_verification);
1904  $this->setAnswerFeedbackPoints($data->answer_feedback_points);
1905  $this->setAnswerFeedback($data->answer_feedback);
1906  $this->setAnonymity($data->anonymity);
1907  $this->setShowCancel($data->show_cancel);
1908  $this->setShowMarker($data->show_marker);
1909  $this->setFixedParticipants($data->fixed_participants);
1910  $this->setNrOfTries($data->nr_of_tries);
1911  $this->setKiosk($data->kiosk);
1912  $this->setUsePreviousAnswers($data->use_previous_answers);
1913  $this->setRedirectionMode($data->redirection_mode);
1914  $this->setRedirectionUrl($data->redirection_url);
1915  $this->setTitleOutput($data->title_output);
1916  $this->setProcessingTime($data->processing_time);
1917  $this->setEnableProcessingTime($data->enable_processing_time);
1918  $this->setResetProcessingTime($data->reset_processing_time);
1919  $this->setReportingDate($data->reporting_date);
1920  $this->setShuffleQuestions($data->shuffle_questions);
1921  $this->setResultsPresentation($data->results_presentation);
1922  $this->setStartingTimeEnabled($data->starting_time_enabled);
1923  $this->setStartingTime($data->starting_time);
1924  $this->setEndingTimeEnabled($data->ending_time_enabled);
1925  $this->setEndingTime($data->ending_time);
1926  $this->setListOfQuestionsSettings($data->show_summary);
1927  $this->setECTSOutput($data->ects_output);
1928  $this->setECTSGrades(
1929  array(
1930  "A" => $data->ects_a,
1931  "B" => $data->ects_b,
1932  "C" => $data->ects_c,
1933  "D" => $data->ects_d,
1934  "E" => $data->ects_e
1935  )
1936  );
1937  $this->setECTSFX($data->ects_fx);
1938  $this->mark_schema->flush();
1939  $this->mark_schema->loadFromDb($this->getTestId());
1940  $this->setCountSystem($data->count_system);
1941  $this->setMCScoring($data->mc_scoring);
1942  $this->setMailNotification($data->mailnotification);
1943  $this->setMailNotificationType($data->mailnottype);
1944  $this->setExportSettings($data->exportsettings);
1945  $this->setScoreCutting($data->score_cutting);
1946  $this->setPasswordEnabled($data->password_enabled);
1947  $this->setPassword($data->password);
1948  $this->setLimitUsersEnabled($data->limit_users_enabled);
1949  $this->setAllowedUsers($data->allowedusers);
1950  $this->setAllowedUsersTimeGap($data->alloweduserstimegap);
1951  $this->setPassScoring($data->pass_scoring);
1952  $this->setObligationsEnabled($data->obligations_enabled);
1953  $this->setOfferingQuestionHintsEnabled($data->offer_question_hints);
1954  $this->setCertificateVisibility($data->certificate_visibility);
1955  $this->setEnabledViewMode($data->enabled_view_mode);
1956  $this->setTemplate($data->template_id);
1957  $this->setPoolUsage($data->pool_usage);
1958  $this->setPrintBestSolutionWithResult((bool) $data->print_bs_with_res);
1959  $this->setHighscoreEnabled((bool) $data->highscore_enabled);
1960  $this->setHighscoreAnon((bool) $data->highscore_anon);
1961  $this->setHighscoreAchievedTS((bool) $data->highscore_achieved_ts);
1962  $this->setHighscoreScore((bool) $data->highscore_score);
1963  $this->setHighscorePercentage((bool) $data->highscore_percentage);
1964  $this->setHighscoreHints((bool) $data->highscore_hints);
1965  $this->setHighscoreWTime((bool) $data->highscore_wtime);
1966  $this->setHighscoreOwnTable((bool) $data->highscore_own_table);
1967  $this->setHighscoreTopTable((bool) $data->highscore_top_table);
1968  $this->setHighscoreTopNum((int) $data->highscore_top_num);
1969  $this->setOnline((bool) $data->online_status);
1970  $this->setOldOnlineStatus((bool) $data->online_status);
1971  $this->setSpecificAnswerFeedback((int) $data->specific_feedback);
1972  $this->setAutosave((bool)$data->autosave);
1973  $this->setAutosaveIval((int)$data->autosave_ival);
1974  $this->setPassDeletionAllowed($data->pass_deletion_allowed);
1975  $this->setEnableExamview((bool)$data->enable_examview);
1976  $this->setShowExamviewHtml((bool)$data->show_examview_html);
1977  $this->setShowExamviewPdf((bool)$data->show_examview_pdf);
1978  $this->setEnableArchiving((bool)$data->enable_archiving);
1979  $this->setShowExamIdInTestPassEnabled( (bool)$data->examid_in_test_pass);
1980  $this->setShowExamIdInTestResultsEnabled( (bool)$data->examid_in_test_res);
1981  $this->setSignSubmission( (bool)$data->sign_submission );
1982  $this->setQuestionSetType($data->question_set_type);
1983  $this->setCharSelectorAvailability((int)$data->char_selector_availability);
1984  $this->setCharSelectorDefinition($data->char_selector_definition);
1985  $this->setSkillServiceEnabled((bool)$data->skill_service);
1986  $this->setResultFilterTaxIds(strlen($data->result_tax_filters) ? unserialize($data->result_tax_filters) : array());
1987  $this->setShowGradingStatusEnabled((bool)$data->show_grading_status);
1988  $this->setShowGradingMarkEnabled((bool)$data->show_grading_mark);
1989  $this->setInstantFeedbackAnswerFixationEnabled((bool)$data->inst_fb_answer_fixation);
1990  $this->setForceInstantFeedbackEnabled((bool)$data->force_inst_fb);
1991  $this->setTestFinalBroken((bool)$data->broken);
1992  $this->setPassWaiting($data->pass_waiting);
1993  $this->loadQuestions();
1994  }
1995 
1996  // moved activation to ilObjectActivation
1997  if($this->ref_id)
1998  {
1999  include_once "./Services/Object/classes/class.ilObjectActivation.php";
2000  $activation = ilObjectActivation::getItem($this->ref_id);
2001  switch($activation["timing_type"])
2002  {
2004  $this->setActivationLimited(true);
2005  $this->setActivationStartingTime($activation["timing_start"]);
2006  $this->setActivationEndingTime($activation["timing_end"]);
2007  $this->setActivationVisibility($activation["visible"]);
2008  break;
2009 
2010  default:
2011  $this->setActivationLimited(false);
2012  break;
2013  }
2014  }
2015  }
2016 
2023 function loadQuestions($active_id = "", $pass = NULL)
2024 {
2025  global $ilUser;
2026  global $ilDB;
2027 
2028  $this->questions = array();
2029  if ($this->isRandomTest())
2030  {
2031  if (strcmp($active_id, "") == 0)
2032  {
2033  $active_id = $this->getActiveIdOfUser($ilUser->getId());
2034  }
2035  if (is_null($pass))
2036  {
2037  $pass = self::_getPass($active_id);
2038  }
2039  $result = $ilDB->queryF("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",
2040  array('integer', 'integer'),
2041  array($active_id, $pass)
2042  );
2043  // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
2044  // is only one test pass (pass = 0) in tst_test_rnd_qst while with ILIAS 3.8 there are questions for every test pass.
2045  // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
2046  // no questions are present for a newer pass.
2047  if ($result->numRows() == 0)
2048  {
2049  $result = $ilDB->queryF("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",
2050  array('integer'),
2051  array($active_id)
2052  );
2053  }
2054  }
2055  else
2056  {
2057  $result = $ilDB->queryF("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",
2058  array('integer'),
2059  array($this->test_id)
2060  );
2061  }
2062  $index = 1;
2063  while ($data = $ilDB->fetchAssoc($result))
2064  {
2065  $this->questions[$index++] = $data["question_fi"];
2066  }
2067 }
2068 
2072  public function isIntroductionEnabled()
2073  {
2075  }
2076 
2081  {
2082  $this->introductionEnabled = $introductionEnabled;
2083  }
2084 
2091  public function getIntroduction()
2092  {
2093  return (strlen($this->introduction)) ? $this->introduction : NULL;
2094  }
2095 
2103  public function setIntroduction($introduction = "")
2104  {
2105  $this->introduction = $introduction;
2106  }
2107 
2108 
2116  public function setFinalStatement($a_statement = "")
2117  {
2118  $this->_finalstatement = $a_statement;
2119  }
2120 
2128  public function setShowInfo($a_info = 1)
2129  {
2130  $this->_showinfo = ($a_info) ? 1 : 0;
2131  }
2132 
2140  public function setForceJS($a_js = 1)
2141  {
2142  $this->_forcejs = ($a_js) ? 1 : 0;
2143  }
2144 
2152  public function setCustomStyle($a_customStyle = NULL)
2153  {
2154  $this->_customStyle = $a_customStyle;
2155  }
2156 
2164  public function getCustomStyle()
2165  {
2166  return (strlen($this->_customStyle)) ? $this->_customStyle : NULL;
2167  }
2168 
2176  public function getCustomStyles()
2177  {
2178  $css_path = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2179  $css_path = str_replace("ta.css", "customstyles", $css_path) . "/";
2180  $customstyles = array();
2181  if (is_dir($css_path))
2182  {
2183  $results = array();
2184  include_once "./Services/Utilities/classes/class.ilFileUtils.php";
2186  if (is_array($results["file"]))
2187  {
2188  foreach ($results["file"] as $filename)
2189  {
2190  if (strpos($filename, ".css"))
2191  {
2192  array_push($customstyles, $filename);
2193  }
2194  }
2195  }
2196  }
2197  return $customstyles;
2198  }
2199 
2207  public function getTestStyleLocation($mode = "output")
2208  {
2209  if (strlen($this->getCustomStyle()))
2210  {
2211  $default = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2212  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $default);
2213  if (file_exists($custom))
2214  {
2215  $custom = ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2216  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $custom);
2217  return $custom;
2218  }
2219  else
2220  {
2221  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2222  }
2223  }
2224  else
2225  {
2226  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2227  }
2228  }
2229 
2237  public function setShowFinalStatement($show = 0)
2238  {
2239  $this->_showfinalstatement = ($show) ? 1 : 0;
2240  }
2241 
2248  public function getFinalStatement()
2249  {
2250  return (strlen($this->_finalstatement)) ? $this->_finalstatement : NULL;
2251  }
2252 
2260  public function getShowInfo()
2261  {
2262  return ($this->_showinfo) ? 1 : 0;
2263  }
2264 
2272  public function getForceJS()
2273  {
2274  return ($this->_forcejs) ? 1 : 0;
2275  }
2276 
2284  public function getShowFinalStatement()
2285  {
2286  return ($this->_showfinalstatement) ? 1 : 0;
2287  }
2288 
2296  function getTestId()
2297  {
2298  return $this->test_id;
2299  }
2300 
2304  public function getECTSOutput()
2305  {
2306  return ($this->ects_output) ? 1 : 0;
2307  }
2308 
2312  public function setECTSOutput($a_ects_output)
2313  {
2314  $this->ects_output = $a_ects_output ? 1 : 0;
2315  }
2316 
2320  public function getECTSFX()
2321  {
2322  return (strlen($this->ects_fx)) ? $this->ects_fx : NULL;
2323  }
2324 
2328  public function setECTSFX($a_ects_fx)
2329  {
2330  $this->ects_fx = $a_ects_fx;
2331  }
2332 
2336  public function getECTSGrades()
2337  {
2338  return $this->ects_grades;
2339  }
2340 
2344  public function setECTSGrades(array $a_ects_grades)
2345  {
2346  $this->ects_grades = $a_ects_grades;
2347  }
2348 
2354  public function getSequenceSettings()
2355  {
2356  return ($this->sequence_settings) ? $this->sequence_settings : 0;
2357  }
2358 
2364  public function setSequenceSettings($sequence_settings = 0)
2365  {
2366  $this->sequence_settings = $sequence_settings;
2367  }
2368 
2372  public function isPostponingEnabled()
2373  {
2374  return (bool)$this->getSequenceSettings();
2375  }
2376 
2380  public function setPostponingEnabled($postponingEnabled)
2381  {
2382  $this->setSequenceSettings((int)$postponingEnabled);
2383  }
2384 
2392  function setScoreReporting($score_reporting = 0)
2393  {
2394  $this->score_reporting = $score_reporting;
2395  }
2396 
2404  function setInstantFeedbackSolution($instant_feedback = 0)
2405  {
2406  switch ($instant_feedback)
2407  {
2408  case 1:
2409  $this->instant_verification = 1;
2410  break;
2411  default:
2412  $this->instant_verification = 0;
2413  break;
2414  }
2415  }
2416 
2424 function setAnswerFeedback($answer_feedback = 0)
2425 {
2426  switch ($answer_feedback)
2427  {
2428  case 1:
2429  $this->answer_feedback = 1;
2430  break;
2431  default:
2432  $this->answer_feedback = 0;
2433  break;
2434  }
2435 }
2436 
2442 function setGenericAnswerFeedback($generic_answer_feedback = 0)
2443 {
2444  switch ($generic_answer_feedback)
2445  {
2446  case 1:
2447  $this->answer_feedback = 1;
2448  break;
2449  default:
2450  $this->answer_feedback = 0;
2451  break;
2452  }
2453 }
2454 
2462  function setAnswerFeedbackPoints($answer_feedback_points = 0)
2463  {
2464  switch ($answer_feedback_points)
2465  {
2466  case 1:
2467  $this->answer_feedback_points = 1;
2468  break;
2469  default:
2470  $this->answer_feedback_points = 0;
2471  break;
2472  }
2473  }
2474 
2479  public function setReportingDate($reporting_date)
2480  {
2481  if(!$reporting_date)
2482  {
2483  $this->reporting_date = '';
2484  $this->setECTSOutput(false);
2485  }
2486  else
2487  {
2488  $this->reporting_date = $reporting_date;
2489  }
2490  }
2491 
2496 
2505  {
2506  return ($this->score_reporting) ? $this->score_reporting : 0;
2507  }
2508 
2509  public function isScoreReportingEnabled()
2510  {
2511  return $this->getScoreReporting() > 0 && $this->getScoreReporting() < 4;
2512  }
2513 
2522  {
2523  return ($this->instant_verification) ? $this->instant_verification : 0;
2524  }
2525 
2534  public function getAnswerFeedback()
2535  {
2536  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2537  }
2538 
2545  public function getGenericAnswerFeedback()
2546  {
2547  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2548  }
2549 
2558 {
2559  return ($this->answer_feedback_points) ? $this->answer_feedback_points : 0;
2560 }
2561 
2569  function getCountSystem()
2570  {
2571  return ($this->count_system) ? $this->count_system : 0;
2572  }
2573 
2581  public static function _getCountSystem($active_id)
2582  {
2583  global $ilDB;
2584  $result = $ilDB->queryF("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",
2585  array('integer'),
2586  array($active_id)
2587  );
2588  if ($result->numRows())
2589  {
2590  $row = $ilDB->fetchAssoc($result);
2591  return $row["count_system"];
2592  }
2593  return FALSE;
2594  }
2595 
2603  function getMCScoring()
2604  {
2605  return ($this->mc_scoring) ? $this->mc_scoring : 0;
2606  }
2607 
2615  function getScoreCutting()
2616  {
2617  return ($this->score_cutting) ? $this->score_cutting : 0;
2618  }
2619 
2627  function getPassScoring()
2628  {
2629  return ($this->pass_scoring) ? $this->pass_scoring : 0;
2630  }
2631 
2639  public static function _getPassScoring($active_id)
2640  {
2641  global $ilDB;
2642  $result = $ilDB->queryF("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",
2643  array('integer'),
2644  array($active_id)
2645  );
2646  if ($result->numRows())
2647  {
2648  $row = $ilDB->fetchAssoc($result);
2649  return $row["pass_scoring"];
2650  }
2651  return 0;
2652  }
2653 
2661  public static function _getMCScoring($active_id)
2662  {
2663  global $ilDB;
2664  $result = $ilDB->queryF("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",
2665  array('integer'),
2666  array($active_id)
2667  );
2668  if ($result->numRows())
2669  {
2670  $row = $ilDB->fetchAssoc($result);
2671  return $row["mc_scoring"];
2672  }
2673  return FALSE;
2674  }
2675 
2683  public static function _getScoreCutting($active_id)
2684  {
2685  global $ilDB;
2686  $result = $ilDB->queryF("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",
2687  array('integer'),
2688  array($active_id)
2689  );
2690  if ($result->numRows())
2691  {
2692  $row = $ilDB->fetchAssoc($result);
2693  return $row["score_cutting"];
2694  }
2695  return FALSE;
2696  }
2697 
2705  function getReportingDate()
2706  {
2707  return (strlen($this->reporting_date)) ? $this->reporting_date : NULL;
2708  }
2709 
2717  function getNrOfTries()
2718  {
2719  return ($this->nr_of_tries) ? $this->nr_of_tries : 0;
2720  }
2721 
2729  function getKiosk()
2730  {
2731  return ($this->_kiosk) ? $this->_kiosk : 0;
2732  }
2733 
2734 
2742  function setKiosk($kiosk = 0)
2743  {
2744  $this->_kiosk = $kiosk;
2745  }
2746 
2754  function getKioskMode()
2755  {
2756  if (($this->_kiosk & 1) > 0)
2757  {
2758  return TRUE;
2759  }
2760  else
2761  {
2762  return FALSE;
2763  }
2764  }
2765 
2773  public function setKioskMode($a_kiosk = FALSE)
2774  {
2775  if ($a_kiosk)
2776  {
2777  $this->_kiosk = $this->_kiosk | 1;
2778  }
2779  else
2780  {
2781  if ($this->getKioskMode())
2782  {
2783  $this->_kiosk = $this->_kiosk ^ 1;
2784  }
2785  }
2786  }
2787 
2795  public function getShowKioskModeTitle()
2796  {
2797  if (($this->_kiosk & 2) > 0)
2798  {
2799  return TRUE;
2800  }
2801  else
2802  {
2803  return FALSE;
2804  }
2805  }
2806 
2813  public function setShowKioskModeTitle($a_title = FALSE)
2814  {
2815  if ($a_title)
2816  {
2817  $this->_kiosk = $this->_kiosk | 2;
2818  }
2819  else
2820  {
2821  if ($this->getShowKioskModeTitle())
2822  {
2823  $this->_kiosk = $this->_kiosk ^ 2;
2824  }
2825  }
2826  }
2827 
2836  {
2837  if (($this->_kiosk & 4) > 0)
2838  {
2839  return TRUE;
2840  }
2841  else
2842  {
2843  return FALSE;
2844  }
2845  }
2846 
2853  public function setShowKioskModeParticipant($a_participant = FALSE)
2854  {
2855  if ($a_participant)
2856  {
2857  $this->_kiosk = $this->_kiosk | 4;
2858  }
2859  else
2860  {
2861  if ($this->getShowKioskModeParticipant())
2862  {
2863  $this->_kiosk = $this->_kiosk ^ 4;
2864  }
2865  }
2866  }
2867 
2876  {
2877  return ($this->use_previous_answers) ? $this->use_previous_answers : 0;
2878  }
2879 
2887  function getTitleOutput()
2888  {
2889  return ($this->title_output) ? $this->title_output : 0;
2890  }
2891 
2900  function _getTitleOutput($active_id)
2901  {
2902  global $ilDB;
2903 
2904  $result = $ilDB->queryF("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",
2905  array('integer'),
2906  array($active_id)
2907  );
2908  if ($result->numRows())
2909  {
2910  $row = $ilDB->fetchAssoc($result);
2911  return $row["title_output"];
2912  }
2913  return 0;
2914  }
2915 
2916  // hey: prevPassSolutions - serious (nonstatic) identifier, for use in high level controller gui
2917  public function isPreviousSolutionReuseEnabled($activeId)
2918  {
2919  // checks if allowed in general and if enabled by participant
2920  return self::_getUsePreviousAnswers($activeId, true);
2921  }
2922  // hey.
2923 
2933  public static function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
2934  {
2935  global $ilDB;
2936  global $ilUser;
2937 
2938  $use_previous_answers = 1;
2939 
2940  $result = $ilDB->queryF("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",
2941  array("integer"),
2942  array($active_id)
2943  );
2944  if ($result->numRows())
2945  {
2946  $row = $ilDB->fetchAssoc($result);
2947  $use_previous_answers = $row["use_previous_answers"];
2948  }
2949 
2950  if ($use_previous_answers == 1)
2951  {
2952  if ($user_active_user_setting)
2953  {
2954  $res = $ilUser->getPref("tst_use_previous_answers");
2955  if ($res !== FALSE)
2956  {
2957  $use_previous_answers = $res;
2958  }
2959  }
2960  }
2961  return $use_previous_answers;
2962  }
2963 
2972  {
2973  return (strlen($this->processing_time)) ? $this->processing_time : NULL;
2974  }
2975 
2982  public function getProcessingTimeAsArray()
2983  {
2984  if (strlen($this->processing_time))
2985  {
2986  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches))
2987  {
2988  if ((int)$matches[1]+(int)$matches[2]+(int)$matches[3] == 0)
2989  {
2990  return $this->getEstimatedWorkingTime();
2991  }
2992  else
2993  {
2994  return array(
2995  'hh' => $matches[1],
2996  'mm' => $matches[2],
2997  'ss' => $matches[3],
2998  );
2999  }
3000  }
3001  }
3002  return $this->getEstimatedWorkingTime();
3003  }
3004 
3005  public function getProcessingTimeAsMinutes()
3006  {
3007  if (strlen($this->processing_time))
3008  {
3009  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches))
3010  {
3011  return ($matches[1] * 60) + $matches[2];
3012  }
3013  }
3014 
3015  return self::DEFAULT_PROCESSING_TIME_MINUTES;
3016  }
3017 
3025  function getProcessingTimeInSeconds($active_id = "")
3026  {
3027  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches))
3028  {
3029  $extratime = $this->getExtraTime($active_id) * 60;
3030  return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
3031  }
3032  else
3033  {
3034  return 0;
3035  }
3036  }
3037 
3046  {
3047  if ($this->getEndingTime() != 0)
3048  {
3049  $ending = $this->getEndingTime();
3050  $now = time();
3051  return $ending - $now;
3052  }
3053  else
3054  {
3055  return 0;
3056  }
3057  }
3058 
3067  {
3068  return ($this->enable_processing_time) ? $this->enable_processing_time : 0;
3069  }
3070 
3079  {
3080  return ($this->reset_processing_time) ? $this->reset_processing_time : 0;
3081  }
3082 
3086  public function isStartingTimeEnabled()
3087  {
3089  }
3090 
3095  {
3096  $this->starting_time_enabled = $starting_time_enabled;
3097  }
3098 
3106  public function getStartingTime()
3107  {
3108  return ($this->starting_time != 0) ? $this->starting_time : 0;
3109  }
3110 
3118  public function setStartingTime($starting_time = NULL)
3119  {
3120  $this->starting_time = $starting_time;
3121  }
3122 
3126  public function isEndingTimeEnabled()
3127  {
3129  }
3130 
3135  {
3136  $this->ending_time_enabled = $ending_time_enabled;
3137  }
3138 
3146  public function getEndingTime()
3147  {
3148  return ($this->ending_time != 0) ? $this->ending_time : 0;
3149  }
3150 
3158  public function setEndingTime($ending_time = NULL)
3159  {
3160  $this->ending_time = $ending_time;
3161  }
3162 
3170  function setNrOfTries($nr_of_tries = 0)
3171  {
3172  $this->nr_of_tries = $nr_of_tries;
3173  }
3174 
3182  function setUsePreviousAnswers($use_previous_answers = 1)
3183  {
3184  if ($use_previous_answers)
3185  {
3186  $this->use_previous_answers = 1;
3187  }
3188  else
3189  {
3190  $this->use_previous_answers = 0;
3191  }
3192  }
3193 
3195  {
3196  $this->redirection_mode = $redirection_mode;
3197  }
3199  {
3200  return $this->redirection_mode;
3201  }
3203  {
3204  $this->redirection_url = $redirection_url;
3205  }
3207  {
3208  return $this->redirection_url;
3209  }
3210 
3218  function setTitleOutput($title_output = 0)
3219  {
3220  switch ($title_output)
3221  {
3222  case 1:
3223  $this->title_output = 1;
3224  break;
3225  case 2:
3226  $this->title_output = 2;
3227  break;
3228  default:
3229  $this->title_output = 0;
3230  break;
3231  }
3232  }
3233 
3241  function setProcessingTime($processing_time = "00:00:00")
3242  {
3243  $this->processing_time = $processing_time;
3244  }
3245 
3246  public function setProcessingTimeByMinutes($minutes)
3247  {
3248  $this->processing_time = sprintf("%02d:%02d:00", floor($minutes/60), $minutes%60);
3249  }
3250 
3258  function setEnableProcessingTime($enable = 0)
3259  {
3260  if ($enable) {
3261  $this->enable_processing_time = "1";
3262  } else {
3263  $this->enable_processing_time = "0";
3264  }
3265  }
3266 
3274  function setResetProcessingTime($reset = 0)
3275  {
3276  if ($reset)
3277  {
3278  $this->reset_processing_time = 1;
3279  }
3280  else
3281  {
3282  $this->reset_processing_time = 0;
3283  }
3284  }
3285 
3293  function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3294  {
3295  $this->count_system = $a_count_system;
3296  }
3297 
3301  public function isPasswordEnabled()
3302  {
3303  return $this->passwordEnabled;
3304  }
3305 
3310  {
3311  $this->passwordEnabled = $passwordEnabled;
3312  }
3313 
3321  public function getPassword()
3322  {
3323  return (strlen($this->password)) ? $this->password : NULL;
3324  }
3325 
3333  public function setPassword($a_password = NULL)
3334  {
3335  $this->password = $a_password;
3336  }
3337 
3345  function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3346  {
3347  $this->score_cutting = $a_score_cutting;
3348  }
3349 
3358  {
3359  $this->mc_scoring = $a_mc_scoring;
3360  }
3361 
3369  function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3370  {
3371  switch ($a_pass_scoring)
3372  {
3373  case SCORE_BEST_PASS:
3374  $this->pass_scoring = SCORE_BEST_PASS;
3375  break;
3376  default:
3377  $this->pass_scoring = SCORE_LAST_PASS;
3378  break;
3379  }
3380  }
3381 
3385  public function getPassWaiting()
3386  {
3387  return $this->pass_waiting;
3388  }
3389 
3394  {
3395  $this->pass_waiting = $pass_waiting;
3396  }
3400  public function isPassWaitingEnabled()
3401  {
3402  if(array_sum(explode(':', $this->getPassWaiting())) > 0)
3403  {
3404  return true;
3405  }
3406  return false;
3407  }
3408 
3412  public function removeQuestions($removeQuestionIds)
3413  {
3414  foreach ($removeQuestionIds as $value) {
3415  $this->removeQuestion($value);
3416  }
3417 
3419  }
3420 
3428  function removeQuestion($question_id)
3429  {
3430  $question =& ilObjTest::_instanciateQuestion($question_id);
3431  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3433  {
3434  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3435  }
3436  $question->delete($question_id);
3437  }
3438 
3448  {
3449  $this->removeTestResultsByUserIds($userIds);
3450 
3451  $ilDB = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['ilDB'];
3452  $lng = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['lng'] : $GLOBALS['lng'];
3453 
3454  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3455  $participantData = new ilTestParticipantData($ilDB, $lng);
3456  $participantData->setUserIds($userIds);
3457  $participantData->load($this->getTestId());
3458 
3459  $this->removeTestActives($participantData->getActiveIds());
3460  }
3461 
3462  public function removeTestResults(ilTestParticipantData $participantData)
3463  {
3464  if( count($participantData->getAnonymousActiveIds()) )
3465  {
3466  $this->removeTestResultsByActiveIds($participantData->getAnonymousActiveIds());
3467  }
3468 
3469  if( count($participantData->getUserIds()) )
3470  {
3471  /* @var ilTestLP $testLP */
3472  require_once 'Services/Object/classes/class.ilObjectLP.php';
3473  $testLP = ilObjectLP::getInstance($this->getId());
3474  $testLP->setTestObject($this);
3475  $testLP->resetLPDataForUserIds($participantData->getUserIds(), false);
3476  }
3477 
3478  if( count($participantData->getActiveIds()) )
3479  {
3480  $this->removeTestActives($participantData->getActiveIds());
3481  }
3482  }
3483 
3484  public function removeTestResultsByUserIds($userIds)
3485  {
3486  global $ilDB, $lng;
3487 
3488  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3489  $participantData = new ilTestParticipantData($ilDB, $lng);
3490  $participantData->setUserIds($userIds);
3491  $participantData->load($this->getTestId());
3492 
3493  $IN_userIds = $ilDB->in('usr_id', $participantData->getUserIds(), false, 'integer');
3494  $ilDB->manipulateF("DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
3495  array('text'), array("tst_password_".$this->getTestId())
3496  );
3497 
3498  if( count($participantData->getActiveIds()) )
3499  {
3500  $this->removeTestResultsByActiveIds($participantData->getActiveIds());
3501  }
3502  }
3503 
3504  public function removeTestResultsByActiveIds($activeIds)
3505  {
3506  global $ilDB;
3507 
3508  $IN_activeIds = $ilDB->in('active_fi', $activeIds, false, 'integer');
3509 
3510  $ilDB->manipulate("DELETE FROM tst_solutions WHERE $IN_activeIds");
3511  $ilDB->manipulate("DELETE FROM tst_qst_solved WHERE $IN_activeIds");
3512  $ilDB->manipulate("DELETE FROM tst_test_result WHERE $IN_activeIds");
3513  $ilDB->manipulate("DELETE FROM tst_pass_result WHERE $IN_activeIds");
3514  $ilDB->manipulate("DELETE FROM tst_result_cache WHERE $IN_activeIds");
3515  $ilDB->manipulate("DELETE FROM tst_sequence WHERE $IN_activeIds");
3516  $ilDB->manipulate("DELETE FROM tst_times WHERE $IN_activeIds");
3517 
3518  if( $this->isRandomTest() )
3519  {
3520  $ilDB->manipulate("DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
3521  }
3522  elseif( $this->isDynamicTest() )
3523  {
3524  $ilDB->manipulate("DELETE FROM tst_seq_qst_tracking WHERE $IN_activeIds");
3525  $ilDB->manipulate("DELETE FROM tst_seq_qst_answstatus WHERE $IN_activeIds");
3526  $ilDB->manipulate("DELETE FROM tst_seq_qst_postponed WHERE $IN_activeIds");
3527  $ilDB->manipulate("DELETE FROM tst_seq_qst_checked WHERE $IN_activeIds");
3528  }
3529 
3530  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3531 
3532  foreach ($activeIds as $active_id)
3533  {
3534  // remove file uploads
3535  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id"))
3536  {
3537  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3538  }
3539 
3541  {
3542  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3543  }
3544  }
3545 
3546  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3548  }
3549 
3550  public function removeTestActives($activeIds)
3551  {
3552  global $ilDB;
3553 
3554  $IN_activeIds = $ilDB->in('active_id', $activeIds, false, 'integer');
3555  $ilDB->manipulate("DELETE FROM tst_active WHERE $IN_activeIds");
3556  }
3557 
3565  function questionMoveUp($question_id)
3566  {
3567  global $ilDB;
3568 
3569  // Move a question up in sequence
3570  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3571  array('integer', 'integer'),
3572  array($this->getTestId(), $question_id)
3573  );
3574  $data = $ilDB->fetchObject($result);
3575  if ($data->sequence > 1)
3576  {
3577  // OK, it's not the top question, so move it up
3578  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3579  array('integer','integer'),
3580  array($this->getTestId(), $data->sequence - 1)
3581  );
3582  $data_previous = $ilDB->fetchObject($result);
3583  // change previous dataset
3584  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3585  array('integer','integer'),
3586  array($data->sequence, $data_previous->test_question_id)
3587  );
3588  // move actual dataset up
3589  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3590  array('integer','integer'),
3591  array($data->sequence - 1, $data->test_question_id)
3592  );
3593  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3595  {
3596  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence-1), $question_id);
3597  }
3598  }
3599  $this->loadQuestions();
3600  }
3601 
3609  function questionMoveDown($question_id)
3610  {
3611  global $ilDB;
3612 
3613  // Move a question down in sequence
3614  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3615  array('integer','integer'),
3616  array($this->getTestId(), $question_id)
3617  );
3618  $data = $ilDB->fetchObject($result);
3619  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3620  array('integer','integer'),
3621  array($this->getTestId(), $data->sequence + 1)
3622  );
3623  if ($result->numRows() == 1)
3624  {
3625  // OK, it's not the last question, so move it down
3626  $data_next = $ilDB->fetchObject($result);
3627  // change next dataset
3628  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3629  array('integer','integer'),
3630  array($data->sequence, $data_next->test_question_id)
3631  );
3632  // move actual dataset down
3633  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3634  array('integer','integer'),
3635  array($data->sequence + 1, $data->test_question_id)
3636  );
3637  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3639  {
3640  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence+1), $question_id);
3641  }
3642  }
3643  $this->loadQuestions();
3644  }
3645 
3653  function duplicateQuestionForTest($question_id)
3654  {
3655  global $ilUser;
3656  $question =& ilObjTest::_instanciateQuestion($question_id);
3657  $duplicate_id = $question->duplicate(true, null, null, null, $this->getId());
3658 
3659  return $duplicate_id;
3660  }
3661 
3670  public function insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly = false)
3671  {
3672  global $ilDB;
3673 #var_dump($question_id);
3674  if ($linkOnly)
3675  {
3676  $duplicate_id = $question_id;
3677  }
3678  else
3679  {
3680  $duplicate_id = $this->duplicateQuestionForTest($question_id);
3681  }
3682 
3683  // get maximum sequence index in test
3684  $result = $ilDB->queryF("SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
3685  array('integer'),
3686  array($this->getTestId())
3687  );
3688  $sequence = 1;
3689 
3690  if ($result->numRows() == 1)
3691  {
3692  $data = $ilDB->fetchObject($result);
3693  $sequence = $data->seq + 1;
3694  }
3695 
3696  $next_id = $ilDB->nextId('tst_test_question');
3697  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
3698  array('integer', 'integer','integer','integer','integer'),
3699  array($next_id, $this->getTestId(), $duplicate_id, $sequence, time())
3700  );
3701  if ($affectedRows == 1)
3702  {
3703  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3705  {
3706  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3707  }
3708  }
3709  // remove test_active entries, because test has changed
3710  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE test_fi = %s",
3711  array('integer'),
3712  array($this->getTestId())
3713  );
3714  $this->loadQuestions();
3715  $this->saveCompleteStatus($testQuestionSetConfig);
3716  return $duplicate_id;
3717  }
3718 
3726  function &getQuestionTitles()
3727  {
3728  $titles = array();
3729  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED)
3730  {
3731  global $ilDB;
3732  $result = $ilDB->queryF("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",
3733  array('integer'),
3734  array($this->getTestId())
3735  );
3736  while ($row = $ilDB->fetchAssoc($result))
3737  {
3738  array_push($titles, $row["title"]);
3739  }
3740  }
3741  return $titles;
3742  }
3743 
3752  {
3753  $titles = array();
3754  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED)
3755  {
3756  global $ilDB;
3757  $result = $ilDB->queryF("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",
3758  array('integer'),
3759  array($this->getTestId())
3760  );
3761  while ($row = $ilDB->fetchAssoc($result))
3762  {
3763  $titles[$row['question_id']] = $row["title"];
3764  }
3765  }
3766  return $titles;
3767  }
3768 
3769 // fau: testNav - add number parameter (to show if title should not be shown)
3779  function getQuestionTitle($title, $nr = null)
3780  {
3781  if ($this->getTitleOutput() == 2)
3782  {
3783  if( $this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC )
3784  {
3785  // avoid legacy setting combination: ctm without question titles
3786  return $title;
3787  }
3788  else
3789  if (isset($nr))
3790  {
3791  return $this->lng->txt("ass_question"). ' ' . $nr;
3792  }
3793  else
3794  {
3795  return $this->lng->txt("ass_question");
3796  }
3797 
3798  }
3799  else
3800  {
3801  return $title;
3802  }
3803  }
3804 // fau.
3805 
3814  function getQuestionDataset($question_id)
3815  {
3816  global $ilDB;
3817 
3818  $result = $ilDB->queryF("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",
3819  array('integer'),
3820  array($question_id)
3821  );
3822  $row = $ilDB->fetchObject($result);
3823  return $row;
3824  }
3825 
3832  function &getExistingQuestions($pass = NULL)
3833  {
3834  global $ilUser;
3835  global $ilDB;
3836 
3837  $existing_questions = array();
3838  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3839  if ($this->isRandomTest())
3840  {
3841  if (is_null($pass)) $pass = 0;
3842  $result = $ilDB->queryF("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",
3843  array('integer','integer'),
3844  array($active_id, $pass)
3845  );
3846  }
3847  else
3848  {
3849  $result = $ilDB->queryF("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",
3850  array('integer'),
3851  array($this->getTestId())
3852  );
3853  }
3854  while ($data = $ilDB->fetchObject($result))
3855  {
3856  if( $data->original_id === null )
3857  {
3858  continue;
3859  }
3860 
3861  array_push($existing_questions, $data->original_id);
3862  }
3863  return $existing_questions;
3864  }
3865 
3873  function getQuestionType($question_id)
3874  {
3875  global $ilDB;
3876 
3877  if ($question_id < 1) return -1;
3878  $result = $ilDB->queryF("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",
3879  array('integer'),
3880  array($question_id)
3881  );
3882  if ($result->numRows() == 1)
3883  {
3884  $data = $ilDB->fetchObject($result);
3885  return $data->type_tag;
3886  }
3887  else
3888  {
3889  return "";
3890  }
3891  }
3892 
3899  function startWorkingTime($active_id, $pass)
3900  {
3901  global $ilDB;
3902 
3903  $next_id = $ilDB->nextId('tst_times');
3904  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
3905  array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'),
3906  array($next_id, $active_id, strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"), $pass, time())
3907  );
3908  return $next_id;
3909  }
3910 
3917  function updateWorkingTime($times_id)
3918  {
3919  global $ilDB;
3920 
3921  $affectedRows = $ilDB->manipulateF("UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
3922  array('timestamp', 'integer', 'integer'),
3923  array(strftime("%Y-%m-%d %H:%M:%S"), time(), $times_id)
3924  );
3925  }
3926 
3933  function &getWorkedQuestions($active_id, $pass = NULL)
3934  {
3935  global $ilUser;
3936  global $ilDB;
3937 
3938  if (is_null($pass))
3939  {
3940  $result = $ilDB->queryF("SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3941  array('integer','integer'),
3942  array($active_id, 0)
3943  );
3944  }
3945  else
3946  {
3947  $result = $ilDB->queryF("SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3948  array('integer','integer'),
3949  array($active_id, $pass)
3950  );
3951  }
3952  $result_array = array();
3953  while ($row = $ilDB->fetchAssoc($result))
3954  {
3955  array_push($result_array, $row["question_fi"]);
3956  }
3957  return $result_array;
3958  }
3959 
3968  function isTestFinishedToViewResults($active_id, $currentpass)
3969  {
3970  $num = $this->getPassFinishDate($active_id, $currentpass);
3971  return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ? true : false;
3972  }
3973 
3980  function &getAllQuestions($pass = NULL)
3981  {
3982  global $ilUser;
3983  global $ilDB;
3984 
3985  $result_array = array();
3986  if ($this->isRandomTest())
3987  {
3988  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3989  $this->loadQuestions($active_id, $pass);
3990  if (count($this->questions) == 0) return $result_array;
3991  if (is_null($pass))
3992  {
3993  $pass = self::_getPass($active_id);
3994  }
3995  $result = $ilDB->queryF("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'),
3996  array('integer','integer'),
3997  array($active_id, $pass)
3998  );
3999  }
4000  else
4001  {
4002  if (count($this->questions) == 0) return $result_array;
4003  $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'));
4004  }
4005  while ($row = $ilDB->fetchAssoc($result))
4006  {
4007  $result_array[$row["question_id"]] = $row;
4008  }
4009  return $result_array;
4010  }
4011 
4020  function getActiveIdOfUser($user_id = "", $anonymous_id = "")
4021  {
4022  global $ilDB;
4023  global $ilUser;
4024 
4025  if (!$user_id) $user_id = $ilUser->getId();
4026  if (($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()])))
4027  {
4028  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4029  array('integer','integer','text'),
4030  array($user_id, $this->test_id, $_SESSION["tst_access_code"][$this->getTestId()])
4031  );
4032  }
4033  else if (strlen($anonymous_id))
4034  {
4035  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4036  array('integer','integer','text'),
4037  array($user_id, $this->test_id, $anonymous_id)
4038  );
4039  }
4040  else
4041  {
4042  if ($GLOBALS['DIC']['ilUser']->getId() == ANONYMOUS_USER_ID)
4043  {
4044  return NULL;
4045  }
4046  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4047  array('integer','integer'),
4048  array($user_id, $this->test_id)
4049  );
4050  }
4051  if ($result->numRows())
4052  {
4053  $row = $ilDB->fetchAssoc($result);
4054  return $row["active_id"];
4055  }
4056  else
4057  {
4058  return 0;
4059  }
4060  }
4061 
4070  public static function _getActiveIdOfUser($user_id = "", $test_id = "")
4071  {
4072  global $ilDB;
4073  global $ilUser;
4074 
4075  if (!$user_id) {
4076  $user_id = $ilUser->id;
4077  }
4078  if (!$test_id)
4079  {
4080  return "";
4081  }
4082  $result = $ilDB->queryF("SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4083  array('integer', 'integer'),
4084  array($user_id, $test_id)
4085  );
4086  if ($result->numRows())
4087  {
4088  $row = $ilDB->fetchAssoc($result);
4089  return $row["active_id"];
4090  }
4091  else
4092  {
4093  return "";
4094  }
4095  }
4096 
4103  function pcArrayShuffle($array)
4104  {
4105  $keys = array_keys($array);
4106  shuffle($keys);
4107  $result = array();
4108  foreach ($keys as $key)
4109  {
4110  $result[$key] = $array[$key];
4111  }
4112  return $result;
4113  }
4114 
4122  function &getTestResult($active_id, $pass = NULL, $ordered_sequence = FALSE, $considerHiddenQuestions = true, $considerOptionalQuestions = true)
4123  {
4124  global $tree, $ilDB, $lng, $ilPluginAdmin;
4125 
4126  $results = $this->getResultsForActiveId($active_id);
4127 
4128  if( is_null($pass) )
4129  {
4130  $pass = $results['pass'];
4131  }
4132 
4133  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
4134  $testSessionFactory = new ilTestSessionFactory($this);
4135  $testSession = $testSessionFactory->getSession($active_id);
4136 
4137  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4138  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
4139  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $pass);
4140 
4141  if( $this->isDynamicTest() )
4142  {
4143  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4144  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
4145  $dynamicQuestionSetConfig->loadFromDb();
4146 
4147  $testSequence->loadFromDb($dynamicQuestionSetConfig);
4148  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4149 
4150  $sequence = $testSequence->getUserSequenceQuestions();
4151  }
4152  else
4153  {
4154  $testSequence->setConsiderHiddenQuestionsEnabled($considerHiddenQuestions);
4155  $testSequence->setConsiderOptionalQuestionsEnabled($considerOptionalQuestions);
4156 
4157  $testSequence->loadFromDb();
4158  $testSequence->loadQuestions();
4159 
4160  if( $ordered_sequence )
4161  {
4162  $sequence = $testSequence->getOrderedSequenceQuestions();
4163  }
4164  else
4165  {
4166  $sequence = $testSequence->getUserSequenceQuestions();
4167  }
4168  }
4169 
4170  $arrResults = array();
4171 
4172  $query = "
4173  SELECT tst_test_result.question_fi,
4174  tst_test_result.points reached,
4175  tst_test_result.hint_count requested_hints,
4176  tst_test_result.hint_points hint_points,
4177  tst_test_result.answered answered
4178 
4179  FROM tst_test_result
4180 
4181  LEFT JOIN tst_solutions
4182  ON tst_solutions.active_fi = tst_test_result.active_fi
4183  AND tst_solutions.question_fi = tst_test_result.question_fi
4184 
4185  WHERE tst_test_result.active_fi = %s
4186  AND tst_test_result.pass = %s
4187  ";
4188 
4189  $solutionresult = $ilDB->queryF(
4190  $query, array('integer', 'integer'), array($active_id, $pass)
4191  );
4192 
4193  while( $row = $ilDB->fetchAssoc($solutionresult) )
4194  {
4195  $arrResults[ $row['question_fi'] ] = $row;
4196  }
4197 
4198  $numWorkedThrough = count($arrResults);
4199 
4200  require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4201 
4202  $IN_question_ids = $ilDB->in('qpl_questions.question_id', $sequence, false, 'integer');
4203 
4204  $query = "
4205  SELECT qpl_questions.*,
4206  qpl_qst_type.type_tag,
4207  qpl_sol_sug.question_fi has_sug_sol
4208 
4209  FROM qpl_qst_type,
4210  qpl_questions
4211 
4212  LEFT JOIN qpl_sol_sug
4213  ON qpl_sol_sug.question_fi = qpl_questions.question_id
4214 
4215  WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi
4216  AND $IN_question_ids
4217  ";
4218 
4219  $result = $ilDB->query($query);
4220 
4221  $unordered = array();
4222 
4223  $key = 1;
4224 
4225  $obligationsAnswered = true;
4226 
4227  while( $row = $ilDB->fetchAssoc($result) )
4228  {
4229  $percentvalue = (
4230  $row['points'] ? $arrResults[ $row['question_id'] ]['reached'] / $row['points'] : 0
4231  );
4232 
4233  if( $percentvalue < 0 ) $percentvalue = 0.0;
4234 
4235  $data = array(
4236  "nr" => "$key",
4237  "title" => ilUtil::prepareFormOutput($row['title']),
4238  "max" => round($row['points'], 2),
4239  "reached" => round($arrResults[$row['question_id']]['reached'],2),
4240  'requested_hints' => $arrResults[$row['question_id']]['requested_hints'],
4241  'hint_points' => $arrResults[$row['question_id']]['hint_points'],
4242  "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4243  "solution" => ($row['has_sug_sol']) ? assQuestion::_getSuggestedSolutionOutput($row['question_id']) : '',
4244  "type" => $row["type_tag"],
4245  "qid" => $row['question_id'],
4246  "original_id" => $row["original_id"],
4247  "workedthrough" => isset($arrResults[$row['question_id']]) ? 1 : 0,
4248  'answered' => $arrResults[$row['question_id']]['answered']
4249  );
4250 
4251  if( !$arrResults[ $row['question_id'] ]['answered'] )
4252  {
4253  $obligationsAnswered = false;
4254  }
4255 
4256  $unordered[ $row['question_id'] ] = $data;
4257 
4258  $key++;
4259  }
4260 
4261  $numQuestionsTotal = count($unordered);
4262 
4263  $pass_max = 0;
4264  $pass_reached = 0;
4265  $pass_requested_hints = 0;
4266  $pass_hint_points = 0;
4267  $key = 1;
4268 
4269  $found = array();
4270 
4271  foreach( $sequence as $qid )
4272  {
4273  // building pass point sums based on prepared data
4274  // for question that exists in users qst sequence
4275  $pass_max += round($unordered[$qid]['max'], 2);
4276  $pass_reached += round($unordered[$qid]['reached'], 2);
4277  $pass_requested_hints += $unordered[$qid]['requested_hints'];
4278  $pass_hint_points += $unordered[$qid]['hint_points'];
4279 
4280  // pickup prepared data for question
4281  // that exists in users qst sequence
4282  $unordered[$qid]['nr'] = $key;
4283  array_push($found, $unordered[$qid]);
4284 
4285  // increment key counter
4286  $key++;
4287  }
4288 
4289  $unordered = null;
4290 
4291  if( $this->getScoreCutting() == 1 )
4292  {
4293  if( $results['reached_points'] < 0 )
4294  {
4295  $results['reached_points'] = 0;
4296  }
4297 
4298  if( $pass_reached < 0 ) $pass_reached = 0;
4299  }
4300 
4301  $found['pass']['total_max_points'] = $pass_max;
4302  $found['pass']['total_reached_points'] = $pass_reached;
4303  $found['pass']['total_requested_hints'] = $pass_requested_hints;
4304  $found['pass']['total_hint_points'] = $pass_hint_points;
4305  $found['pass']['percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
4306  $found['pass']['obligationsAnswered'] = $obligationsAnswered;
4307  $found['pass']['num_workedthrough'] = $numWorkedThrough;
4308  $found['pass']['num_questions_total'] = $numQuestionsTotal;
4309 
4310  $found["test"]["total_max_points"] = $results['max_points'];
4311  $found["test"]["total_reached_points"] = $results['reached_points'];
4312  $found["test"]["total_requested_hints"] = $results['hint_count'];
4313  $found["test"]["total_hint_points"] = $results['hint_points'];
4314  $found["test"]["result_pass"] = $results['pass'];
4315  $found['test']['result_tstamp'] = $results['tstamp'];
4316  $found['test']['obligations_answered'] = $results['obligations_answered'];
4317 
4318  if( (!$total_reached_points) or (!$total_max_points) )
4319  {
4320  $percentage = 0.0;
4321  }
4322  else
4323  {
4324  $percentage = ($total_reached_points / $total_max_points) * 100.0;
4325 
4326  if( $percentage < 0 ) $percentage = 0.0;
4327  }
4328 
4329  $found["test"]["passed"] = $results['passed'];
4330 
4331  return $found;
4332  }
4333 
4340  function evalTotalPersons()
4341  {
4342  global $ilDB;
4343 
4344  $result = $ilDB->queryF("SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
4345  array('integer'),
4346  array($this->getTestId())
4347  );
4348  $row = $ilDB->fetchAssoc($result);
4349  return $row["total"];
4350  }
4351 
4358  function getCompleteWorkingTime($user_id)
4359  {
4360  global $ilDB;
4361 
4362  $result = $ilDB->queryF("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",
4363  array('integer','integer'),
4364  array($this->getTestId(), $user_id)
4365  );
4366  $time = 0;
4367  while ($row = $ilDB->fetchAssoc($result))
4368  {
4369  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4370  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4371  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4372  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4373  $time += ($epoch_2 - $epoch_1);
4374  }
4375  return $time;
4376  }
4377 
4385  {
4386  return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4387  }
4388 
4397  {
4398  global $ilDB;
4399 
4400  $result = $ilDB->queryF("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",
4401  array('integer'),
4402  array($test_id)
4403  );
4404  $time = 0;
4405  $times = array();
4406  while ($row = $ilDB->fetchAssoc($result))
4407  {
4408  if (!array_key_exists($row["active_fi"], $times))
4409  {
4410  $times[$row["active_fi"]] = 0;
4411  }
4412  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4413  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4414  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4415  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4416  $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4417  }
4418  return $times;
4419  }
4420 
4428  {
4429  global $ilDB;
4430 
4431  $result = $ilDB->queryF("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",
4432  array('integer','integer'),
4433  array($this->getTestId(), $active_id)
4434  );
4435  $time = 0;
4436  while ($row = $ilDB->fetchAssoc($result))
4437  {
4438  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4439  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4440  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4441  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4442  $time += ($epoch_2 - $epoch_1);
4443  }
4444  return $time;
4445  }
4446 
4453  public static function _getWorkingTimeOfParticipantForPass($active_id, $pass)
4454  {
4455  global $ilDB;
4456 
4457  $result = $ilDB->queryF("SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4458  array('integer','integer'),
4459  array($active_id, $pass)
4460  );
4461  $time = 0;
4462  while ($row = $ilDB->fetchAssoc($result))
4463  {
4464  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4465  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4466  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4467  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4468  $time += ($epoch_2 - $epoch_1);
4469  }
4470  return $time;
4471  }
4472 
4480  function getVisitTimeOfParticipant($active_id)
4481  {
4482  return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4483  }
4484 
4493  function _getVisitTimeOfParticipant($test_id, $active_id)
4494  {
4495  global $ilDB;
4496 
4497  $result = $ilDB->queryF("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",
4498  array('integer','integer'),
4499  array($test_id, $active_id)
4500  );
4501  $firstvisit = 0;
4502  $lastvisit = 0;
4503  while ($row = $ilDB->fetchAssoc($result))
4504  {
4505  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4506  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4507  if ($firstvisit == 0 || $epoch_1 < $firstvisit) $firstvisit = $epoch_1;
4508  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4509  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4510  if ($epoch_2 > $lastvisit) $lastvisit = $epoch_2;
4511  }
4512  return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4513  }
4514 
4521  function &evalStatistical($active_id)
4522  {
4523  global $ilDB;
4524 // global $ilBench;
4525  $pass = ilObjTest::_getResultPass($active_id);
4526  $test_result =& $this->getTestResult($active_id, $pass);
4527  $result = $ilDB->queryF("SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
4528  array('integer'),
4529  array($active_id)
4530  );
4531  $times = array();
4532  $first_visit = 0;
4533  $last_visit = 0;
4534  while ($row = $ilDB->fetchObject($result))
4535  {
4536  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4537  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4538  if (!$first_visit) {
4539  $first_visit = $epoch_1;
4540  }
4541  if ($epoch_1 < $first_visit) {
4542  $first_visit = $epoch_1;
4543  }
4544  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4545  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4546  if (!$last_visit) {
4547  $last_visit = $epoch_2;
4548  }
4549  if ($epoch_2 > $last_visit) {
4550  $last_visit = $epoch_2;
4551  }
4552  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4553  }
4554  $max_time = 0;
4555  foreach ($times as $key => $value) {
4556  $max_time += $value;
4557  }
4558  if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"]))
4559  {
4560  $percentage = 0.0;
4561  }
4562  else
4563  {
4564  $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4565  if ($percentage < 0) $percentage = 0.0;
4566  }
4567  $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4568  $first_date = getdate($first_visit);
4569  $last_date = getdate($last_visit);
4570  $qworkedthrough = 0;
4571  foreach ($test_result as $key => $value)
4572  {
4573  if (preg_match("/\d+/", $key))
4574  {
4575  $qworkedthrough += $value["workedthrough"];
4576  }
4577  }
4578  if (!$qworkedthrough)
4579  {
4580  $atimeofwork = 0;
4581  }
4582  else
4583  {
4584  $atimeofwork = $max_time / $qworkedthrough;
4585  }
4586 
4587  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4588 
4589  $result_mark = "";
4590  $passed = "";
4591 
4592  if ($mark_obj)
4593  {
4594  $result_mark = $mark_obj->getShortName();
4595 
4596  if( $mark_obj->getPassed() && $obligationsAnswered )
4597  {
4598  $passed = 1;
4599  }
4600  else
4601  {
4602  $passed = 0;
4603  }
4604  }
4605  $percent_worked_through = 0;
4606  if (count($this->questions))
4607  {
4608  $percent_worked_through = $qworkedthrough / count($this->questions);
4609  }
4610  $result_array = array(
4611  "qworkedthrough" => $qworkedthrough,
4612  "qmax" => count($this->questions),
4613  "pworkedthrough" => $percent_worked_through,
4614  "timeofwork" => $max_time,
4615  "atimeofwork" => $atimeofwork,
4616  "firstvisit" => $first_date,
4617  "lastvisit" => $last_date,
4618  "resultspoints" => $test_result["test"]["total_reached_points"],
4619  "maxpoints" => $test_result["test"]["total_max_points"],
4620  "resultsmarks" => $result_mark,
4621  "passed" => $passed,
4622  "distancemedian" => "0"
4623  );
4624  foreach ($test_result as $key => $value)
4625  {
4626  if (preg_match("/\d+/", $key))
4627  {
4628  $result_array[$key] = $value;
4629  }
4630  }
4631  return $result_array;
4632  }
4633 
4642  {
4643  $totalpoints_array = array();
4644  $all_users =& $this->evalTotalParticipantsArray();
4645  foreach ($all_users as $active_id => $user_name)
4646  {
4647  $test_result =& $this->getTestResult($active_id);
4648  $reached = $test_result["test"]["total_reached_points"];
4649  $total = $test_result["test"]["total_max_points"];
4650  $percentage = $total != 0 ? $reached/$total : 0;
4651  $mark = $this->mark_schema->getMatchingMark($percentage*100.0);
4652 
4653  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4654 
4655  if ($mark)
4656  {
4657  if( $mark->getPassed() && $obligationsAnswered )
4658  {
4659  array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4660  }
4661  }
4662  }
4663  return $totalpoints_array;
4664  }
4665 
4671  public function &getParticipants()
4672  {
4673  global $ilDB;
4674  $result = $ilDB->queryF("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",
4675  array('integer'),
4676  array($this->getTestId())
4677  );
4678  $persons_array = array();
4679  while ($row = $ilDB->fetchAssoc($result))
4680  {
4681  $name = $this->lng->txt("anonymous");
4682  $fullname = $this->lng->txt("anonymous");
4683  $login = "";
4684  if (!$this->getAnonymity())
4685  {
4686  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4687  {
4688  $name = $this->lng->txt("deleted_user");
4689  $fullname = $this->lng->txt("deleted_user");
4690  $login = $this->lng->txt("unknown");
4691  }
4692  else
4693  {
4694  $login = $row["login"];
4695  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4696  {
4697  $name = $this->lng->txt("anonymous");
4698  $fullname = $this->lng->txt("anonymous");
4699  }
4700  else
4701  {
4702  $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4703  $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4704  }
4705  }
4706  }
4707  $persons_array[$row["active_id"]] = array(
4708  "name" => $name,
4709  "fullname" => $fullname,
4710  "login" => $login
4711  );
4712  }
4713  return $persons_array;
4714  }
4715 
4722  function &evalTotalPersonsArray($name_sort_order = "asc")
4723  {
4724  global $ilDB;
4725  $result = $ilDB->queryF("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),
4726  array('integer'),
4727  array($this->getTestId())
4728  );
4729  $persons_array = array();
4730  while ($row = $ilDB->fetchAssoc($result))
4731  {
4732  if ($this->getAnonymity())
4733  {
4734  $persons_array[$row["active_id"]] = $this->lng->txt("anonymous");
4735  }
4736  else
4737  {
4738  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4739  {
4740  $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4741  }
4742  else
4743  {
4744  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4745  {
4746  $persons_array[$row["active_id"]] = $row["lastname"];
4747  }
4748  else
4749  {
4750  $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4751  }
4752  }
4753  }
4754  }
4755  return $persons_array;
4756  }
4757 
4764  function &evalTotalParticipantsArray($name_sort_order = "asc")
4765  {
4766  global $ilDB;
4767  $result = $ilDB->queryF("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),
4768  array('integer'),
4769  array($this->getTestId())
4770  );
4771  $persons_array = array();
4772  while ($row = $ilDB->fetchAssoc($result))
4773  {
4774  if ($this->getAnonymity())
4775  {
4776  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("anonymous"));
4777  }
4778  else
4779  {
4780  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4781  {
4782  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4783  }
4784  else
4785  {
4786  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4787  {
4788  $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4789  }
4790  else
4791  {
4792  $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4793  }
4794  }
4795  }
4796  }
4797  return $persons_array;
4798  }
4799 
4807  {
4808  global $ilDB;
4809 
4810  $result = $ilDB->queryF("SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s AND submitted = %s",
4811  array('integer', 'integer'),
4812  array($this->getTestId(), 1)
4813  );
4814  $row = $ilDB->fetchAssoc($result);
4815  return $row["total"];
4816  }
4817 
4824  function &getQuestionsOfTest($active_id)
4825  {
4826  global $ilDB;
4827  if ($this->isRandomTest())
4828  {
4829  $ilDB->setLimit($this->getQuestionCount(), 0);
4830  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4831  "tst_test_rnd_qst.pass, qpl_questions.points " .
4832  "FROM tst_test_rnd_qst, qpl_questions " .
4833  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4834  "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4835  array('integer'),
4836  array($active_id)
4837  );
4838  }
4839  else
4840  {
4841  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4842  "qpl_questions.points " .
4843  "FROM tst_test_question, tst_active, qpl_questions " .
4844  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4845  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4846  array('integer'),
4847  array($active_id)
4848  );
4849  }
4850  $qtest = array();
4851  if ($result->numRows())
4852  {
4853  while ($row = $ilDB->fetchAssoc($result))
4854  {
4855  array_push($qtest, $row);
4856  }
4857  }
4858  return $qtest;
4859  }
4860 
4867  function &getQuestionsOfPass($active_id, $pass)
4868  {
4869  global $ilDB;
4870  if ($this->isRandomTest())
4871  {
4872  $ilDB->setLimit($this->getQuestionCount(), 0);
4873  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4874  "qpl_questions.points " .
4875  "FROM tst_test_rnd_qst, qpl_questions " .
4876  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4877  "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
4878  "ORDER BY tst_test_rnd_qst.sequence",
4879  array('integer', 'integer'),
4880  array($active_id, $pass)
4881  );
4882  }
4883  else
4884  {
4885  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4886  "qpl_questions.points " .
4887  "FROM tst_test_question, tst_active, qpl_questions " .
4888  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4889  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4890  array('integer'),
4891  array($active_id)
4892  );
4893  }
4894  $qpass = array();
4895  if ($result->numRows())
4896  {
4897  while ($row = $ilDB->fetchAssoc($result))
4898  {
4899  array_push($qpass, $row);
4900  }
4901  }
4902  return $qpass;
4903  }
4904 
4905  function getUnfilteredEvaluationData()
4906  {
4908  global $DIC;
4909 
4910  $ilDB = $DIC->database();
4911 
4912  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
4913  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
4914  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
4915 
4916  $data = new ilTestEvaluationData($this);
4917 
4918  $query = "
4919  SELECT tst_test_result.*,
4920  qpl_questions.original_id,
4921  qpl_questions.title questiontitle,
4922  qpl_questions.points maxpoints
4923 
4924  FROM tst_test_result, qpl_questions, tst_active
4925 
4926  WHERE tst_active.active_id = tst_test_result.active_fi
4927  AND qpl_questions.question_id = tst_test_result.question_fi
4928  AND tst_active.test_fi = %s
4929 
4930  ORDER BY tst_active.active_id ASC, tst_test_result.pass ASC, tst_test_result.tstamp DESC
4931  ";
4932 
4933  $result = $ilDB->queryF(
4934  $query, array('integer'), array($this->getTestId())
4935  );
4936 
4937  $pass = NULL;
4938  $checked = array();
4939  $datasets = 0;
4940  $questionData = [];
4941 
4942  while( $row = $ilDB->fetchAssoc($result) )
4943  {
4944  $participantObject = $data->getParticipant($row["active_fi"]);
4945 
4946  if( !($participantObject instanceof ilTestEvaluationUserData) )
4947  {
4948  continue;
4949  }
4950 
4951  $passObject = $participantObject->getPass($row["pass"]);
4952 
4953  if( !($passObject instanceof ilTestEvaluationPassData) )
4954  {
4955  continue;
4956  }
4957 
4958  $passObject->addAnsweredQuestion(
4959  $row["question_fi"], $row["maxpoints"], $row["points"], $row['answered'], null, $row['manual']
4960  );
4961  }
4962 
4963  foreach( array_keys($data->getParticipants()) as $active_id )
4964  {
4965  if( $this->isRandomTest() )
4966  {
4967  for( $testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++ )
4968  {
4969  $ilDB->setLimit($this->getQuestionCount(), 0);
4970  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, qpl_questions.original_id, " .
4971  "tst_test_rnd_qst.pass, qpl_questions.points, qpl_questions.title " .
4972  "FROM tst_test_rnd_qst, qpl_questions " .
4973  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4974  "AND tst_test_rnd_qst.pass = %s " .
4975  "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4976  array('integer','integer'),
4977  array($testpass, $active_id)
4978  );
4979  if ($result->numRows())
4980  {
4981  while ($row = $ilDB->fetchAssoc($result))
4982  {
4983  $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
4984  $data->getParticipant($active_id)->addQuestion($row["original_id"], $row["question_fi"], $row["points"], $row["sequence"], $tpass);
4985  $data->addQuestionTitle($row["question_fi"], $row["title"]);
4986  }
4987  }
4988  }
4989  }
4990  else if($this->isDynamicTest())
4991  {
4992  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4993  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4994  require_once 'Modules/Test/classes/class.ilTestDynamicQuestionSetFilterSelection.php';
4995 
4996  $lastPass = $data->getParticipant($active_id)->getLastPass();
4997  for($testpass = 0; $testpass <= $lastPass; $testpass++)
4998  {
4999  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
5000  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig(
5001  $DIC->repositoryTree(), $DIC->database(), $DIC['ilPluginAdmin'], $this
5002  );
5003  $dynamicQuestionSetConfig->loadFromDb();
5004 
5005  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
5006  $testSequenceFactory = new ilTestSequenceFactory($DIC->database(), $DIC->language(), $DIC['ilPluginAdmin'], $this);
5007  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $testpass);
5008 
5009  $testSequence->loadFromDb($dynamicQuestionSetConfig);
5010  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
5011 
5012  $sequence = (array)$testSequence->getUserSequenceQuestions();
5013 
5014  $questionsIdsToRequest = array_diff(array_values($sequence), array_values($questionData));
5015  if(count($questionsIdsToRequest) > 0)
5016  {
5017  $questionIdsCondition = ' ' . $DIC->database()->in('question_id', array_values($questionsIdsToRequest), false, 'integer') . ' ';
5018 
5019  $res = $DIC->database()->queryF("
5020  SELECT *
5021  FROM qpl_questions
5022  WHERE {$questionIdsCondition}",
5023  array('integer'),
5024  array($active_id)
5025  );
5026  while($row = $DIC->database()->fetchAssoc($res))
5027  {
5028  $questionData[$row['question_id']] = $row;
5029  $data->addQuestionTitle($row['question_id'], $row['title']);
5030  }
5031  }
5032 
5033  foreach($sequence as $questionId)
5034  {
5035  if(!isset($questionData[$questionId]))
5036  {
5037  continue;
5038  }
5039 
5040  $row = $questionData[$questionId];
5041 
5042  $data->getParticipant(
5043  $active_id)->addQuestion($row['original_id'], $row['question_id'], $row['points'],
5044  NULL, $testpass
5045  );
5046  }
5047  }
5048  }
5049  else
5050  {
5051  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
5052  "qpl_questions.points, qpl_questions.title, qpl_questions.original_id " .
5053  "FROM tst_test_question, tst_active, qpl_questions " .
5054  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
5055  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi ORDER BY tst_test_question.sequence",
5056  array('integer'),
5057  array($active_id)
5058  );
5059  if ($result->numRows())
5060  {
5061  $questionsbysequence = array();
5062 
5063  while ($row = $ilDB->fetchAssoc($result))
5064  {
5065  $questionsbysequence[$row["sequence"]] = $row;
5066  }
5067 
5068  $seqresult = $ilDB->queryF("SELECT * FROM tst_sequence WHERE active_fi = %s",
5069  array('integer'),
5070  array($active_id)
5071  );
5072 
5073  while ($seqrow = $ilDB->fetchAssoc($seqresult))
5074  {
5075  $questionsequence = unserialize($seqrow["sequence"]);
5076  foreach ($questionsequence as $sidx => $seq)
5077  {
5078  $data->getParticipant($active_id)->addQuestion($questionsbysequence[$seq]["original_id"], $questionsbysequence[$seq]["question_fi"], $questionsbysequence[$seq]["points"], $sidx + 1, $seqrow["pass"]);
5079  $data->addQuestionTitle($questionsbysequence[$seq]["question_fi"], $questionsbysequence[$seq]["title"]);
5080  }
5081  }
5082  }
5083  }
5084  }
5085 
5086  if($this->getECTSOutput())
5087  {
5088  $passed_array =& $this->getTotalPointsPassedArray();
5089  }
5090 
5091  foreach( array_keys($data->getParticipants()) as $active_id )
5092  {
5093  $tstUserData = $data->getParticipant($active_id);
5094 
5095  $percentage = $tstUserData->getReachedPointsInPercent();
5096 
5097  $obligationsAnswered = $tstUserData->areObligationsAnswered();
5098 
5099  $mark = $this->mark_schema->getMatchingMark($percentage);
5100 
5101  if (is_object($mark))
5102  {
5103  $tstUserData->setMark($mark->getShortName());
5104  $tstUserData->setMarkOfficial($mark->getOfficialName());
5105 
5106  $tstUserData->setPassed(
5107  $mark->getPassed() && $tstUserData->areObligationsAnswered()
5108  );
5109  }
5110 
5111  if($this->getECTSOutput())
5112  {
5113  $ects_mark = $this->getECTSGrade(
5114  $passed_array, $tstUserData->getReached(), $tstUserData->getMaxPoints()
5115  );
5116 
5117  $tstUserData->setECTSMark($ects_mark);
5118  }
5119 
5120  $visitingTime =& $this->getVisitTimeOfParticipant($active_id);
5121 
5122  $tstUserData->setFirstVisit($visitingTime["firstvisit"]);
5123  $tstUserData->setLastVisit($visitingTime["lastvisit"]);
5124  }
5125 
5126  return $data;
5127  }
5128 
5129  public static function _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
5130  {
5131  global $ilDB;
5132 
5134 
5135  switch( $questionSetType )
5136  {
5138 
5139  $res = $ilDB->queryF("
5140  SELECT COUNT(qpl_questions.question_id) qcount,
5141  SUM(qpl_questions.points) qsum
5142  FROM tst_active
5143  INNER JOIN tst_tests
5144  ON tst_tests.test_id = tst_active.test_fi
5145  INNER JOIN tst_dyn_quest_set_cfg
5146  ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
5147  INNER JOIN qpl_questions
5148  ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
5149  AND qpl_questions.original_id IS NULL
5150  AND qpl_questions.complete = %s
5151  WHERE tst_active.active_id = %s
5152  ",
5153  array('integer', 'integer'),
5154  array(1, $active_id)
5155  );
5156 
5157  break;
5158 
5160 
5161  $res = $ilDB->queryF("
5162  SELECT tst_test_rnd_qst.pass,
5163  COUNT(tst_test_rnd_qst.question_fi) qcount,
5164  SUM(qpl_questions.points) qsum
5165 
5166  FROM tst_test_rnd_qst,
5167  qpl_questions
5168 
5169  WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
5170  AND tst_test_rnd_qst.active_fi = %s
5171  AND pass = %s
5172 
5173  GROUP BY tst_test_rnd_qst.active_fi,
5174  tst_test_rnd_qst.pass
5175  ",
5176  array('integer', 'integer'),
5177  array($active_id, $pass)
5178  );
5179 
5180  break;
5181 
5183 
5184  $res = $ilDB->queryF("
5185  SELECT COUNT(tst_test_question.question_fi) qcount,
5186  SUM(qpl_questions.points) qsum
5187 
5188  FROM tst_test_question,
5189  qpl_questions,
5190  tst_active
5191 
5192  WHERE tst_test_question.question_fi = qpl_questions.question_id
5193  AND tst_test_question.test_fi = tst_active.test_fi
5194  AND tst_active.active_id = %s
5195 
5196  GROUP BY tst_test_question.test_fi
5197  ",
5198  array('integer'),
5199  array($active_id)
5200  );
5201 
5202  break;
5203 
5204  default:
5205 
5206  throw new ilTestException("not supported question set type: $questionSetType");
5207  }
5208 
5209  $row = $ilDB->fetchAssoc($res);
5210 
5211  if( is_array($row) )
5212  {
5213  return array("count" => $row["qcount"], "points" => $row["qsum"]);
5214  }
5215 
5216  return array("count" => 0, "points" => 0);
5217  }
5218 
5219  function &getCompleteEvaluationData($withStatistics = TRUE, $filterby = "", $filtertext = "")
5220  {
5221  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5222  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5223  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5224  $data = $this->getUnfilteredEvaluationData();
5225  if ($withStatistics)
5226  {
5227  $data->calculateStatistics();
5228  }
5229  $data->setFilter($filterby, $filtertext);
5230  return $data;
5231  }
5232 
5240  {
5241  return $this->_evalResultsOverview($this->getTestId());
5242  }
5243 
5250  function &_evalResultsOverview($test_id)
5251  {
5252  global $ilDB;
5253 
5254  $result = $ilDB->queryF("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5255  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5256  "qpl_questions.points maxpoints " .
5257  "FROM tst_test_result, qpl_questions, tst_active " .
5258  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5259  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5260  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5261  "AND tst_active.test_fi = %s " .
5262  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5263  array('integer'),
5264  array($test_id)
5265  );
5266  $overview = array();
5267  while ($row = $ilDB->fetchAssoc($result))
5268  {
5269  if (!array_key_exists($row["active_fi"], $overview))
5270  {
5271  $overview[$row["active_fi"]] = array();
5272  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5273  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5274  $overview[$row["active_fi"]]["title"] = $row["title"];
5275  $overview[$row["active_fi"]]["login"] = $row["login"];
5276  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5277  $overview[$row["active_fi"]]["started"] = $row["started"];
5278  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5279  }
5280  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5281  {
5282  $overview[$row["active_fi"]][$row["pass"]] = array();
5283  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5284  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5285  }
5286  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5287  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5288  }
5289  return $overview;
5290  }
5291 
5299  function &evalResultsOverviewOfParticipant($active_id)
5300  {
5301  global $ilDB;
5302 
5303  $result = $ilDB->queryF("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5304  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5305  "qpl_questions.points maxpoints " .
5306  "FROM tst_test_result, qpl_questions, tst_active " .
5307  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5308  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5309  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5310  "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5311  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5312  array('integer', 'integer'),
5313  array($this->getTestId(), $active_id)
5314  );
5315  $overview = array();
5316  while ($row = $ilDB->fetchAssoc($result))
5317  {
5318  if (!array_key_exists($row["active_fi"], $overview))
5319  {
5320  $overview[$row["active_fi"]] = array();
5321  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5322  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5323  $overview[$row["active_fi"]]["title"] = $row["title"];
5324  $overview[$row["active_fi"]]["login"] = $row["login"];
5325  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5326  $overview[$row["active_fi"]]["started"] = $row["started"];
5327  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5328  }
5329  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5330  {
5331  $overview[$row["active_fi"]][$row["pass"]] = array();
5332  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5333  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5334  }
5335  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5336  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5337  }
5338  return $overview;
5339  }
5340 
5352  function buildName($user_id, $firstname, $lastname, $title)
5353  {
5354  $name = "";
5355  if (strlen($firstname.$lastname.$title) == 0)
5356  {
5357  $name = $this->lng->txt("deleted_user");
5358  }
5359  else
5360  {
5361  if ($user_id == ANONYMOUS_USER_ID)
5362  {
5363  $name = $lastname;
5364  }
5365  else
5366  {
5367  $name = trim($lastname . ", " . $firstname . " " . $title);
5368  }
5369  if ($this->getAnonymity())
5370  {
5371  $name = $this->lng->txt("anonymous");
5372  }
5373  }
5374  return $name;
5375  }
5376 
5389  function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5390  {
5391  global $lng;
5392  $name = "";
5393  if (strlen($firstname.$lastname.$title) == 0)
5394  {
5395  $name = $lng->txt("deleted_user");
5396  }
5397  else
5398  {
5399  if ($user_id == ANONYMOUS_USER_ID)
5400  {
5401  $name = $lastname;
5402  }
5403  else
5404  {
5405  $name = trim($lastname . ", " . $firstname . " " . $title);
5406  }
5407  if ($is_anonymous)
5408  {
5409  $name = $lng->txt("anonymous");
5410  }
5411  }
5412  return $name;
5413  }
5414 
5422  {
5423  global $ilDB;
5424 
5425  $result = $ilDB->queryF("SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi",
5426  array('integer'),
5427  array($this->getTestId())
5428  );
5429  $times = array();
5430  while ($row = $ilDB->fetchObject($result))
5431  {
5432  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5433  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5434  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5435  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5436  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5437  }
5438  $max_time = 0;
5439  $counter = 0;
5440  foreach ($times as $key => $value)
5441  {
5442  $max_time += $value;
5443  $counter++;
5444  }
5445  if ($counter)
5446  {
5447  $average_time = round($max_time / $counter);
5448  }
5449  else
5450  {
5451  $average_time = 0;
5452  }
5453  return $average_time;
5454  }
5455 
5462  function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = FALSE, $with_questioncount = FALSE, $permission = "read")
5463  {
5464  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5465  return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5466  }
5467 
5475  {
5476  $time_in_seconds = 0;
5477  foreach ($this->questions as $question_id)
5478  {
5479  $question =& ilObjTest::_instanciateQuestion($question_id);
5480  $est_time = $question->getEstimatedWorkingTime();
5481  $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5482  }
5483  $hours = (int)($time_in_seconds / 3600) ;
5484  $time_in_seconds = $time_in_seconds - ($hours * 3600);
5485  $minutes = (int)($time_in_seconds / 60);
5486  $time_in_seconds = $time_in_seconds - ($minutes * 60);
5487  $result = array("hh" => $hours, "mm" => $minutes, "ss" => $time_in_seconds);
5488  return $result;
5489  }
5490 
5497  function getImagePath()
5498  {
5499  return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5500  }
5501 
5508  function getImagePathWeb()
5509  {
5510  include_once "./Services/Utilities/classes/class.ilUtil.php";
5511  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
5512  return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir);
5513  }
5514 
5523  function &createQuestionGUI($question_type, $question_id = -1)
5524  {
5525  if ((!$question_type) and ($question_id > 0))
5526  {
5527  $question_type = $this->getQuestionType($question_id);
5528  }
5529 
5530  if (!strlen($question_type)) return null;
5531 
5532  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5533  assQuestion::_includeClass($question_type, 1);
5534 
5535  $question_type_gui = assQuestion::getGuiClassNameByQuestionType($question_type);
5536  $question = new $question_type_gui();
5537 
5538  if ($question_id > 0)
5539  {
5540  $question->object->loadFromDb($question_id);
5541 
5542  global $ilCtrl, $ilDB, $ilUser, $lng;
5543 
5544  $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
5545  $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
5546 
5547  $assSettings = new ilSetting('assessment');
5548  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
5549  $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
5550  $processLockerFactory->setQuestionId($question->object->getId());
5551  $processLockerFactory->setUserId($ilUser->getId());
5552  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
5553  $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
5554  $question->object->setProcessLocker($processLockerFactory->getLocker());
5555  }
5556 
5557  return $question;
5558  }
5559 
5569  public static function _instanciateQuestion($question_id)
5570  {
5571  if (strcmp($question_id, "") != 0)
5572  {
5573  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5574  return assQuestion::_instanciateQuestion($question_id);
5575  }
5576  }
5577 
5586  function moveQuestions($move_questions, $target_index, $insert_mode)
5587  {
5588  $this->questions = array_values($this->questions);
5589  $array_pos = array_search($target_index, $this->questions);
5590  if ($insert_mode == 0)
5591  {
5592  $part1 = array_slice($this->questions, 0, $array_pos);
5593  $part2 = array_slice($this->questions, $array_pos);
5594  }
5595  else if ($insert_mode == 1)
5596  {
5597  $part1 = array_slice($this->questions, 0, $array_pos + 1);
5598  $part2 = array_slice($this->questions, $array_pos + 1);
5599  }
5600  foreach ($move_questions as $question_id)
5601  {
5602  if (!(array_search($question_id, $part1) === FALSE))
5603  {
5604  unset($part1[array_search($question_id, $part1)]);
5605  }
5606  if (!(array_search($question_id, $part2) === FALSE))
5607  {
5608  unset($part2[array_search($question_id, $part2)]);
5609  }
5610  }
5611  $part1 = array_values($part1);
5612  $part2 = array_values($part2);
5613  $new_array = array_values(array_merge($part1, $move_questions, $part2));
5614  $this->questions = array();
5615  $counter = 1;
5616  foreach ($new_array as $question_id)
5617  {
5618  $this->questions[$counter] = $question_id;
5619  $counter++;
5620  }
5621  $this->saveQuestionsToDb();
5622  }
5623 
5624 
5633  {
5634  if( $this->isStartingTimeEnabled() && $this->getStartingTime() != 0 )
5635  {
5636  $now = time();
5637  if ($now < $this->getStartingTime())
5638  {
5639  return false;
5640  }
5641  }
5642  return true;
5643  }
5644 
5653  {
5654  if( $this->isEndingTimeEnabled() && $this->getEndingTime() != 0 )
5655  {
5656  $now = time();
5657  if ($now > $this->getEndingTime())
5658  {
5659  return true;
5660  }
5661  }
5662  return false;
5663  }
5664 
5670  function getAvailableQuestions($arrFilter, $completeonly = 0)
5671  {
5672  $pluginAdmin = $GLOBALS['DIC'] ? $GLOBALS['DIC']['ilPluginAdmin'] : $GLOBALS['ilPluginAdmin'];
5673  $lng = $GLOBALS['DIC'] ? $GLOBALS['DIC']['lng'] : $GLOBALS['lng'];
5674  global $ilUser;
5675  global $ilDB;
5676 
5677  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5678  $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = TRUE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE));
5679  $available = "";
5680  if (count($available_pools))
5681  {
5682  $available = " AND " . $ilDB->in('qpl_questions.obj_fi', $available_pools, false, 'integer');
5683  }
5684  else
5685  {
5686  return array();
5687  }
5688  if ($completeonly)
5689  {
5690  $available .= " AND qpl_questions.complete = " . $ilDB->quote("1", 'text');
5691  }
5692 
5693  $where = "";
5694  if (is_array($arrFilter))
5695  {
5696  if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title']))
5697  {
5698  $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
5699  }
5700  if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description']))
5701  {
5702  $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
5703  }
5704  if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author']))
5705  {
5706  $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
5707  }
5708  if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type']))
5709  {
5710  $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
5711  }
5712  if (array_key_exists('qpl', $arrFilter) && strlen($arrFilter['qpl']))
5713  {
5714  $where .= " AND " . $ilDB->like('object_data.title', 'text', "%%" . $arrFilter['qpl'] . "%%");
5715  }
5716  }
5717 
5718  $original_ids =& $this->getExistingQuestions();
5719  $original_clause = " qpl_questions.original_id IS NULL";
5720  if (count($original_ids))
5721  {
5722  $original_clause = " qpl_questions.original_id IS NULL AND " . $ilDB->in('qpl_questions.question_id', $original_ids, true, 'integer');
5723  }
5724 
5725  $query_result = $ilDB->query("
5726  SELECT qpl_questions.*, qpl_questions.tstamp,
5727  qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,
5728  object_data.title parent_title
5729  FROM qpl_questions, qpl_qst_type, object_data
5730  WHERE $original_clause $available
5731  AND object_data.obj_id = qpl_questions.obj_fi
5732  AND qpl_questions.tstamp > 0
5733  AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
5734  $where
5735  ");
5736  $rows = array();
5737  $types = $this->getQuestionTypeTranslations();
5738  if ($query_result->numRows())
5739  {
5740  while ($row = $ilDB->fetchAssoc($query_result))
5741  {
5743 
5744  if( !$row['plugin'] )
5745  {
5746  $row[ 'ttype' ] = $lng->txt($row[ "type_tag" ]);
5747 
5748  $rows[] = $row;
5749  continue;
5750  }
5751 
5752  if( !$pluginAdmin->isActive(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name']) )
5753  {
5754  continue;
5755  }
5756 
5757  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $row['plugin_name']);
5758  $row[ 'ttype' ] = $pl->getQuestionTypeTranslation();
5759 
5760  $rows[] = $row;
5761  }
5762  }
5763  return $rows;
5764  }
5765 
5770  public function fromXML(ilQTIAssessment $assessment)
5771  {
5772  unset($_SESSION["import_mob_xhtml"]);
5773 
5774  $this->setDescription($assessment->getComment());
5775  $this->setTitle($assessment->getTitle());
5776 
5777  $this->setIntroductionEnabled(false);
5778  foreach ($assessment->objectives as $objectives)
5779  {
5780  foreach ($objectives->materials as $material)
5781  {
5782  $intro = $this->QTIMaterialToString($material);
5783  $this->setIntroduction($intro);
5784  $this->setIntroductionEnabled(strlen($intro) > 0);
5785  }
5786  }
5787 
5788  if(
5789  $assessment->getPresentationMaterial() &&
5790  $assessment->getPresentationMaterial()->getFlowMat(0) &&
5791  $assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)
5792  )
5793  {
5794  $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)));
5795  }
5796 
5797  foreach ($assessment->assessmentcontrol as $assessmentcontrol)
5798  {
5799  switch ($assessmentcontrol->getSolutionswitch())
5800  {
5801  case "Yes":
5802  $this->setInstantFeedbackSolution(1);
5803  break;
5804  default:
5805  $this->setInstantFeedbackSolution(0);
5806  break;
5807  }
5808  }
5809 
5810  $this->setStartingTimeEnabled(false);
5811  $this->setEndingTimeEnabled(false);
5812  $this->setPasswordEnabled(false);
5813  $this->setLimitUsersEnabled(false);
5814 
5815  foreach ($assessment->qtimetadata as $metadata)
5816  {
5817  switch ($metadata["label"])
5818  {
5819  case "test_type":
5820  // for old tests with a test type
5821  $type = $metadata["entry"];
5822  switch ($type)
5823  {
5824  case 1:
5825  // assessment
5826  $this->setAnonymity(1);
5827  break;
5828  case 2:
5829  // self assessment
5830  break;
5831  case 4:
5832  // online exam
5833  $this->setFixedParticipants(1);
5834  $this->setListOfQuestionsSettings(7);
5835  $this->setShowSolutionPrintview(1);
5836  break;
5837  case 5:
5838  // varying random test
5839  break;
5840  }
5841  break;
5842  case "sequence_settings":
5843  $this->setSequenceSettings($metadata["entry"]);
5844  break;
5845  case "solution_details":
5846  $this->setShowSolutionDetails((int)$metadata["entry"]);
5847  break;
5848  case "print_bs_with_res":
5849  $this->setPrintBestSolutionWithResult((int)$metadata["entry"]);
5850  break;
5851  case "author":
5852  $this->setAuthor($metadata["entry"]);
5853  break;
5854  case "nr_of_tries":
5855  $this->setNrOfTries($metadata["entry"]);
5856  break;
5857  case "pass_waiting":
5858  $this->setPassWaiting($metadata["entry"]);
5859  break;
5860  case "kiosk":
5861  $this->setKiosk($metadata["entry"]);
5862  break;
5863  case "showfinalstatement":
5864  $this->setShowFinalStatement($metadata["entry"]);
5865  break;
5866  case "showinfo":
5867  $this->setShowInfo($metadata["entry"]);
5868  break;
5869  case "forcejs":
5870  $this->setForceJS($metadata["entry"]);
5871  break;
5872  case "customstyle":
5873  $this->setCustomStyle($metadata["entry"]);
5874  break;
5875 
5876  case "highscore_enabled":
5877  $this->setHighscoreEnabled($metadata["entry"]);
5878  break;
5879 
5880  case "highscore_anon":
5881  $this->setHighscoreAnon($metadata["entry"]);
5882  break;
5883 
5884  case "highscore_achieved_ts":
5885  $this->setHighscoreAchievedTS($metadata["entry"]);
5886  break;
5887 
5888  case "highscore_score":
5889  $this->setHighscoreScore($metadata["entry"]);
5890  break;
5891 
5892  case "highscore_percentage":
5893  $this->setHighscorePercentage($metadata["entry"]);
5894  break;
5895 
5896  case "highscore_hints":
5897  $this->setHighscoreHints($metadata["entry"]);
5898  break;
5899 
5900  case "highscore_wtime":
5901  $this->setHighscoreWTime($metadata["entry"]);
5902  break;
5903 
5904  case "highscore_own_table":
5905  $this->setHighscoreOwnTable($metadata["entry"]);
5906  break;
5907 
5908  case "highscore_top_table":
5909  $this->setHighscoreTopTable($metadata["entry"]);
5910  break;
5911 
5912  case "highscore_top_num":
5913  $this->setHighscoreTopNum($metadata["entry"]);
5914  break;
5915 
5916  case "hide_previous_results":
5917  if ($metadata["entry"] == 0)
5918  {
5919  $this->setUsePreviousAnswers(1);
5920  }
5921  else
5922  {
5923  $this->setUsePreviousAnswers(0);
5924  }
5925  break;
5926  case "use_previous_answers":
5927  $this->setUsePreviousAnswers($metadata["entry"]);
5928  break;
5929  case "answer_feedback":
5930  $this->setAnswerFeedback($metadata["entry"]);
5931  break;
5932  case "hide_title_points":
5933  $this->setTitleOutput($metadata["entry"]);
5934  break;
5935  case "title_output":
5936  $this->setTitleOutput($metadata["entry"]);
5937  break;
5938  case "question_set_type":
5939  $this->setQuestionSetType($metadata["entry"]);
5940  break;
5941  case "random_test":
5942  if( $metadata["entry"] )
5943  {
5944  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
5945  }
5946  else
5947  {
5948  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
5949  }
5950  break;
5951  case "results_presentation":
5952  $this->setResultsPresentation($metadata["entry"]);
5953  break;
5954  case "reset_processing_time":
5955  $this->setResetProcessingTime($metadata["entry"]);
5956  break;
5957  case "instant_verification":
5958  $this->setInstantFeedbackSolution($metadata["entry"]);
5959  break;
5960  case "instant_feedback_answer_fixation":
5961  $this->setInstantFeedbackAnswerFixationEnabled((bool)$metadata["entry"]);
5962  break;
5963  case "force_instant_feedback":
5964  $this->setForceInstantFeedbackEnabled((bool)$metadata["entry"]);
5965  break;
5966  case "answer_feedback_points":
5967  $this->setAnswerFeedbackPoints($metadata["entry"]);
5968  break;
5969  case "anonymity":
5970  $this->setAnonymity($metadata["entry"]);
5971  break;
5972  case "use_pool":
5973  $this->setPoolUsage((int)$metadata["entry"]);
5974  break;
5975  case "show_cancel":
5976  $this->setShowCancel($metadata["entry"]);
5977  break;
5978  case "show_marker":
5979  $this->setShowMarker($metadata["entry"]);
5980  break;
5981  case "fixed_participants":
5982  $this->setFixedParticipants($metadata["entry"]);
5983  break;
5984  case "score_reporting":
5985  $this->setScoreReporting($metadata["entry"]);
5986  break;
5987  case "shuffle_questions":
5988  $this->setShuffleQuestions($metadata["entry"]);
5989  break;
5990  case "count_system":
5991  $this->setCountSystem($metadata["entry"]);
5992  break;
5993  case "mc_scoring":
5994  $this->setMCScoring($metadata["entry"]);
5995  break;
5996  case "mailnotification":
5997  $this->setMailNotification($metadata["entry"]);
5998  break;
5999  case "mailnottype":
6000  $this->setMailNotificationType($metadata["entry"]);
6001  break;
6002  case "exportsettings":
6003  $this->setExportSettings($metadata['entry']);
6004  break;
6005  case "score_cutting":
6006  $this->setScoreCutting($metadata["entry"]);
6007  break;
6008  case "password":
6009  $this->setPassword($metadata["entry"]);
6010  $this->setPasswordEnabled(strlen($metadata["entry"]) > 0);
6011  break;
6012  case "allowedUsers":
6013  $this->setAllowedUsers($metadata["entry"]);
6014  $this->setLimitUsersEnabled((int)$metadata["entry"] > 0);
6015  break;
6016  case "allowedUsersTimeGap":
6017  $this->setAllowedUsersTimeGap($metadata["entry"]);
6018  break;
6019  case "pass_scoring":
6020  $this->setPassScoring($metadata["entry"]);
6021  break;
6022  case 'pass_deletion_allowed':
6023  $this->setPassDeletionAllowed((int)$metadata['entry']);
6024  break;
6025  case "show_summary":
6026  $this->setListOfQuestionsSettings($metadata["entry"]);
6027  break;
6028  case "reporting_date":
6029  $iso8601period = $metadata["entry"];
6030  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6031  {
6032  $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6033  }
6034  break;
6035  case 'enable_processing_time':
6036  $this->setEnableProcessingTime($metadata['entry']);
6037  break;
6038  case "processing_time":
6039  $this->setProcessingTime($metadata['entry']);
6040  break;
6041  case "starting_time":
6042  $iso8601period = $metadata["entry"];
6043  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6044  {
6045  $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);
6046  $this->setStartingTime($date_time->get(IL_CAL_UNIX));
6047  $this->setStartingTimeEnabled(true);
6048  }
6049  break;
6050  case "ending_time":
6051  $iso8601period = $metadata["entry"];
6052  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6053  {
6054  $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);
6055  $this->setEndingTime($date_time->get(IL_CAL_UNIX));
6056  $this->setEndingTimeEnabled(true);
6057  }
6058  break;
6059  case "enable_examview":
6060  $this->setEnableExamview($metadata["entry"]);
6061  break;
6062  case 'show_examview_html':
6063  $this->setShowExamviewHtml($metadata['entry']);
6064  break;
6065  case 'show_examview_pdf':
6066  $this->setShowExamviewPdf($metadata['entry']);
6067  break;
6068  case 'redirection_mode':
6069  $this->setRedirectionMode($metadata['entry']);
6070  break;
6071  case 'redirection_url':
6072  $this->setRedirectionUrl($metadata['entry']);
6073  break;
6074  case 'examid_in_kiosk':
6075  case 'examid_in_test_pass':
6076  $this->setShowExamIdInTestPassEnabled($metadata['entry']);
6077  break;
6078  case 'show_exam_id':
6079  case 'examid_in_test_res':
6080  $this->setShowExamIdInTestResultsEnabled($metadata['entry']);
6081  break;
6082  case 'enable_archiving':
6083  $this->setEnableArchiving($metadata['entry']);
6084  break;
6085  case 'sign_submission':
6086  $this->setSignSubmission($metadata['entry']);
6087  break;
6088  case 'char_selector_availability':
6089  $this->setCharSelectorAvailability($metadata['entry']);
6090  break;
6091  case 'char_selector_definition':
6092  $this->setCharSelectorDefinition($metadata['entry']);
6093  break;
6094  case 'skill_service':
6095  $this->setSkillServiceEnabled((bool)$metadata['entry']);
6096  break;
6097  case 'result_tax_filters':
6098  $this->setResultFilterTaxIds(strlen($metadata['entry']) ? unserialize($metadata['entry']) : array());
6099  break;
6100  case 'show_grading_status':
6101  $this->setShowGradingStatusEnabled((bool)$metadata['entry']);
6102  break;
6103  case 'show_grading_mark':
6104  $this->setShowGradingMarkEnabled((bool)$metadata['entry']);
6105  break;
6106  case 'activation_limited':
6107  $this->setActivationLimited($metadata['entry']);
6108  break;
6109  case 'activation_start_time':
6110  $this->setActivationStartingTime($metadata['entry']);
6111  break;
6112  case 'activation_end_time':
6113  $this->setActivationEndingTime($metadata['entry']);
6114  break;
6115  case 'activation_visibility':
6116  $this->setActivationVisibility($metadata['entry']);
6117  break;
6118  case 'autosave':
6119  $this->setAutosave($metadata['entry']);
6120  break;
6121  case 'autosave_ival':
6122  $this->setAutosaveIval($metadata['entry']);
6123  break;
6124  case 'offer_question_hints':
6125  $this->setOfferingQuestionHintsEnabled($metadata['entry']);
6126  break;
6127  case 'instant_feedback_specific':
6128  $this->setSpecificAnswerFeedback($metadata['entry']);
6129  break;
6130  case 'obligations_enabled':
6131  $this->setObligationsEnabled($metadata['entry']);
6132  break;
6133  }
6134  if (preg_match("/mark_step_\d+/", $metadata["label"]))
6135  {
6136  $xmlmark = $metadata["entry"];
6137  preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
6138  $mark_short = $matches[1];
6139  preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
6140  $mark_official = $matches[1];
6141  preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
6142  $mark_percentage = $matches[1];
6143  preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
6144  $mark_passed = $matches[1];
6145  $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
6146  }
6147  }
6148  // handle the import of media objects in XHTML code
6149  if (is_array($_SESSION["import_mob_xhtml"]))
6150  {
6151  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6152  include_once "./Services/RTE/classes/class.ilRTE.php";
6153  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
6154  foreach ($_SESSION["import_mob_xhtml"] as $mob)
6155  {
6156  $importfile = ilObjTest::_getImportDirectory() . '/' . $_SESSION["tst_import_subdir"] . '/' . $mob["uri"];
6157  if (file_exists($importfile))
6158  {
6159  $media_object =& ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, FALSE);
6160  ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
6161  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
6162  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
6163  }
6164  else
6165  {
6166  global $ilLog;
6167  $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
6168  }
6169  }
6170  $this->saveToDb();
6171  }
6172  }
6173 
6179  public function toXML()
6180  {
6181  include_once("./Services/Xml/classes/class.ilXmlWriter.php");
6182  $a_xml_writer = new ilXmlWriter;
6183  // set xml header
6184  $a_xml_writer->xmlHeader();
6185  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
6186  $a_xml_writer->xmlStartTag("questestinterop");
6187 
6188  $attrs = array(
6189  "ident" => "il_".IL_INST_ID."_tst_".$this->getTestId(),
6190  "title" => $this->getTitle()
6191  );
6192  $a_xml_writer->xmlStartTag("assessment", $attrs);
6193  // add qti comment
6194  $a_xml_writer->xmlElement("qticomment", NULL, $this->getDescription());
6195 
6196  // add qti duration
6197  if ($this->enable_processing_time)
6198  {
6199  preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
6200  $a_xml_writer->xmlElement("duration", NULL, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
6201  }
6202 
6203  // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
6204  $a_xml_writer->xmlStartTag("qtimetadata");
6205  $a_xml_writer->xmlStartTag("qtimetadatafield");
6206  $a_xml_writer->xmlElement("fieldlabel", NULL, "ILIAS_VERSION");
6207  $a_xml_writer->xmlElement("fieldentry", NULL, $this->ilias->getSetting("ilias_version"));
6208  $a_xml_writer->xmlEndTag("qtimetadatafield");
6209 
6210  // anonymity
6211  $a_xml_writer->xmlStartTag("qtimetadatafield");
6212  $a_xml_writer->xmlElement("fieldlabel", NULL, "anonymity");
6213  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnonymity()));
6214  $a_xml_writer->xmlEndTag("qtimetadatafield");
6215 
6216  $a_xml_writer->xmlStartTag("qtimetadatafield");
6217  $a_xml_writer->xmlElement("fieldlabel", NULL, "use_pool");
6218  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPoolUsage() ? 1 : 0);
6219  $a_xml_writer->xmlEndTag("qtimetadatafield");
6220 
6221  // question set type (fixed, random, dynamic, ...)
6222  $a_xml_writer->xmlStartTag("qtimetadatafield");
6223  $a_xml_writer->xmlElement("fieldlabel", NULL, "question_set_type");
6224  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getQuestionSetType());
6225  $a_xml_writer->xmlEndTag("qtimetadatafield");
6226 
6227  // sequence settings
6228  $a_xml_writer->xmlStartTag("qtimetadatafield");
6229  $a_xml_writer->xmlElement("fieldlabel", NULL, "sequence_settings");
6230  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getSequenceSettings());
6231  $a_xml_writer->xmlEndTag("qtimetadatafield");
6232 
6233  // author
6234  $a_xml_writer->xmlStartTag("qtimetadatafield");
6235  $a_xml_writer->xmlElement("fieldlabel", NULL, "author");
6236  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAuthor());
6237  $a_xml_writer->xmlEndTag("qtimetadatafield");
6238 
6239  // reset processing time
6240  $a_xml_writer->xmlStartTag("qtimetadatafield");
6241  $a_xml_writer->xmlElement("fieldlabel", NULL, "reset_processing_time");
6242  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getResetProcessingTime());
6243  $a_xml_writer->xmlEndTag("qtimetadatafield");
6244 
6245  // count system
6246  $a_xml_writer->xmlStartTag("qtimetadatafield");
6247  $a_xml_writer->xmlElement("fieldlabel", NULL, "count_system");
6248  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCountSystem());
6249  $a_xml_writer->xmlEndTag("qtimetadatafield");
6250 
6251  // multiple choice scoring
6252  $a_xml_writer->xmlStartTag("qtimetadatafield");
6253  $a_xml_writer->xmlElement("fieldlabel", NULL, "mc_scoring");
6254  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMCScoring());
6255  $a_xml_writer->xmlEndTag("qtimetadatafield");
6256 
6257  // multiple choice scoring
6258  $a_xml_writer->xmlStartTag("qtimetadatafield");
6259  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_cutting");
6260  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getScoreCutting());
6261  $a_xml_writer->xmlEndTag("qtimetadatafield");
6262 
6263  // multiple choice scoring
6264  $a_xml_writer->xmlStartTag("qtimetadatafield");
6265  $a_xml_writer->xmlElement("fieldlabel", NULL, "password");
6266  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassword());
6267  $a_xml_writer->xmlEndTag("qtimetadatafield");
6268 
6269  // allowed users
6270  $a_xml_writer->xmlStartTag("qtimetadatafield");
6271  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsers");
6272  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsers());
6273  $a_xml_writer->xmlEndTag("qtimetadatafield");
6274 
6275  // allowed users time gap
6276  $a_xml_writer->xmlStartTag("qtimetadatafield");
6277  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsersTimeGap");
6278  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsersTimeGap());
6279  $a_xml_writer->xmlEndTag("qtimetadatafield");
6280 
6281  // pass scoring
6282  $a_xml_writer->xmlStartTag("qtimetadatafield");
6283  $a_xml_writer->xmlElement("fieldlabel", NULL, "pass_scoring");
6284  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassScoring());
6285  $a_xml_writer->xmlEndTag("qtimetadatafield");
6286 
6287  $a_xml_writer->xmlStartTag('qtimetadatafield');
6288  $a_xml_writer->xmlElement('fieldlabel', NULL, 'pass_deletion_allowed');
6289  $a_xml_writer->xmlElement('fieldentry', NULL, (int)$this->isPassDeletionAllowed());
6290  $a_xml_writer->xmlEndTag('qtimetadatafield');
6291 
6292  // score reporting date
6293  if ($this->getReportingDate())
6294  {
6295  $a_xml_writer->xmlStartTag("qtimetadatafield");
6296  $a_xml_writer->xmlElement("fieldlabel", NULL, "reporting_date");
6297  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6298  $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]));
6299  $a_xml_writer->xmlEndTag("qtimetadatafield");
6300  }
6301  // number of tries
6302  $a_xml_writer->xmlStartTag("qtimetadatafield");
6303  $a_xml_writer->xmlElement("fieldlabel", NULL, "nr_of_tries");
6304  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getNrOfTries()));
6305  $a_xml_writer->xmlEndTag("qtimetadatafield");
6306 
6307  // pass_waiting
6308  $a_xml_writer->xmlStartTag("qtimetadatafield");
6309  $a_xml_writer->xmlElement("fieldlabel", NULL, "pass_waiting");
6310  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassWaiting());
6311  $a_xml_writer->xmlEndTag("qtimetadatafield");
6312 
6313  // kiosk
6314  $a_xml_writer->xmlStartTag("qtimetadatafield");
6315  $a_xml_writer->xmlElement("fieldlabel", NULL, "kiosk");
6316  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getKiosk()));
6317  $a_xml_writer->xmlEndTag("qtimetadatafield");
6318 
6319 
6320  //redirection_mode
6321  $a_xml_writer->xmlStartTag('qtimetadatafield');
6322  $a_xml_writer->xmlElement("fieldlabel", NULL, "redirection_mode");
6323  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getRedirectionMode());
6324  $a_xml_writer->xmlEndTag("qtimetadatafield");
6325 
6326  //redirection_url
6327  $a_xml_writer->xmlStartTag('qtimetadatafield');
6328  $a_xml_writer->xmlElement("fieldlabel", NULL, "redirection_url");
6329  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getRedirectionUrl());
6330  $a_xml_writer->xmlEndTag("qtimetadatafield");
6331 
6332  // use previous answers
6333  $a_xml_writer->xmlStartTag("qtimetadatafield");
6334  $a_xml_writer->xmlElement("fieldlabel", NULL, "use_previous_answers");
6335  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getUsePreviousAnswers());
6336  $a_xml_writer->xmlEndTag("qtimetadatafield");
6337 
6338  // hide title points
6339  $a_xml_writer->xmlStartTag("qtimetadatafield");
6340  $a_xml_writer->xmlElement("fieldlabel", NULL, "title_output");
6341  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getTitleOutput()));
6342  $a_xml_writer->xmlEndTag("qtimetadatafield");
6343 
6344  // results presentation
6345  $a_xml_writer->xmlStartTag("qtimetadatafield");
6346  $a_xml_writer->xmlElement("fieldlabel", NULL, "results_presentation");
6347  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getResultsPresentation()));
6348  $a_xml_writer->xmlEndTag("qtimetadatafield");
6349 
6350  // examid in test pass
6351  $a_xml_writer->xmlStartTag("qtimetadatafield");
6352  $a_xml_writer->xmlElement("fieldlabel", NULL, "examid_in_test_pass");
6353  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->isShowExamIdInTestPassEnabled()));
6354  $a_xml_writer->xmlEndTag("qtimetadatafield");
6355 
6356  // examid in kiosk
6357  $a_xml_writer->xmlStartTag("qtimetadatafield");
6358  $a_xml_writer->xmlElement("fieldlabel", NULL, "examid_in_test_res");
6359  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->isShowExamIdInTestResultsEnabled()));
6360  $a_xml_writer->xmlEndTag("qtimetadatafield");
6361 
6362  // solution details
6363  $a_xml_writer->xmlStartTag("qtimetadatafield");
6364  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_summary");
6365  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getListOfQuestionsSettings()));
6366  $a_xml_writer->xmlEndTag("qtimetadatafield");
6367 
6368  // solution details
6369  $a_xml_writer->xmlStartTag("qtimetadatafield");
6370  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_reporting");
6371  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getScoreReporting()));
6372  $a_xml_writer->xmlEndTag("qtimetadatafield");
6373 
6374  $a_xml_writer->xmlStartTag("qtimetadatafield");
6375  $a_xml_writer->xmlElement("fieldlabel", NULL, "solution_details");
6376  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowSolutionDetails());
6377  $a_xml_writer->xmlEndTag("qtimetadatafield");
6378  $a_xml_writer->xmlStartTag("qtimetadatafield");
6379  $a_xml_writer->xmlElement("fieldlabel", NULL, "print_bs_with_res");
6380  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowSolutionDetails() ? (int)$this->isBestSolutionPrintedWithResult() : 0);
6381  $a_xml_writer->xmlEndTag("qtimetadatafield");
6382 
6383  // solution details
6384  $a_xml_writer->xmlStartTag("qtimetadatafield");
6385  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_verification");
6386  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getInstantFeedbackSolution()));
6387  $a_xml_writer->xmlEndTag("qtimetadatafield");
6388 
6389  // answer specific feedback
6390  $a_xml_writer->xmlStartTag("qtimetadatafield");
6391  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback");
6392  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedback()));
6393  $a_xml_writer->xmlEndTag("qtimetadatafield");
6394 
6395  // answer specific feedback of reached points
6396  $a_xml_writer->xmlStartTag("qtimetadatafield");
6397  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback_points");
6398  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedbackPoints()));
6399  $a_xml_writer->xmlEndTag("qtimetadatafield");
6400 
6401  // instant response answer freezing
6402  $a_xml_writer->xmlStartTag("qtimetadatafield");
6403  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_feedback_answer_fixation");
6404  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isInstantFeedbackAnswerFixationEnabled());
6405  $a_xml_writer->xmlEndTag("qtimetadatafield");
6406 
6407  // instant response forced
6408  $a_xml_writer->xmlStartTag("qtimetadatafield");
6409  $a_xml_writer->xmlElement("fieldlabel", NULL, "force_instant_feedback");
6410  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isForceInstantFeedbackEnabled());
6411  $a_xml_writer->xmlEndTag("qtimetadatafield");
6412 
6413 
6414  // highscore
6415  $highscore_metadata = array(
6416  'highscore_enabled' => array('value' => $this->getHighscoreEnabled()),
6417  'highscore_anon' => array('value' => $this->getHighscoreAnon()),
6418  'highscore_achieved_ts' => array('value' => $this->getHighscoreAchievedTS()),
6419  'highscore_score' => array('value' => $this->getHighscoreScore()),
6420  'highscore_percentage' => array('value' => $this->getHighscorePercentage()),
6421  'highscore_hints' => array('value' => $this->getHighscoreHints()),
6422  'highscore_wtime' => array('value' => $this->getHighscoreWTime()),
6423  'highscore_own_table' => array('value' => $this->getHighscoreOwnTable()),
6424  'highscore_top_table' => array('value' => $this->getHighscoreTopTable()),
6425  'highscore_top_num' => array('value' => $this->getHighscoreTopNum()),
6426  );
6427  foreach($highscore_metadata as $label => $data)
6428  {
6429  $a_xml_writer->xmlStartTag("qtimetadatafield");
6430  $a_xml_writer->xmlElement("fieldlabel", NULL, $label);
6431  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $data['value']));
6432  $a_xml_writer->xmlEndTag("qtimetadatafield");
6433  }
6434 
6435  // show cancel
6436  $a_xml_writer->xmlStartTag("qtimetadatafield");
6437  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_cancel");
6438  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowCancel()));
6439  $a_xml_writer->xmlEndTag("qtimetadatafield");
6440 
6441  // show marker
6442  $a_xml_writer->xmlStartTag("qtimetadatafield");
6443  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_marker");
6444  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowMarker()));
6445  $a_xml_writer->xmlEndTag("qtimetadatafield");
6446 
6447  // fixed participants
6448  $a_xml_writer->xmlStartTag("qtimetadatafield");
6449  $a_xml_writer->xmlElement("fieldlabel", NULL, "fixed_participants");
6450  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getFixedParticipants()));
6451  $a_xml_writer->xmlEndTag("qtimetadatafield");
6452 
6453  // show final statement
6454  $a_xml_writer->xmlStartTag("qtimetadatafield");
6455  $a_xml_writer->xmlElement("fieldlabel", NULL, "showfinalstatement");
6456  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6457  $a_xml_writer->xmlEndTag("qtimetadatafield");
6458 
6459  // show introduction only
6460  $a_xml_writer->xmlStartTag("qtimetadatafield");
6461  $a_xml_writer->xmlElement("fieldlabel", NULL, "showinfo");
6462  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6463  $a_xml_writer->xmlEndTag("qtimetadatafield");
6464 
6465  // mail notification
6466  $a_xml_writer->xmlStartTag("qtimetadatafield");
6467  $a_xml_writer->xmlElement("fieldlabel", NULL, "mailnotification");
6468  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMailNotification());
6469  $a_xml_writer->xmlEndTag("qtimetadatafield");
6470 
6471  // mail notification type
6472  $a_xml_writer->xmlStartTag("qtimetadatafield");
6473  $a_xml_writer->xmlElement("fieldlabel", NULL, "mailnottype");
6474  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMailNotificationType());
6475  $a_xml_writer->xmlEndTag("qtimetadatafield");
6476 
6477  // export settings
6478  $a_xml_writer->xmlStartTag("qtimetadatafield");
6479  $a_xml_writer->xmlElement("fieldlabel", NULL, "exportsettings");
6480  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getExportSettings());
6481  $a_xml_writer->xmlEndTag("qtimetadatafield");
6482 
6483  // force JavaScript
6484  $a_xml_writer->xmlStartTag("qtimetadatafield");
6485  $a_xml_writer->xmlElement("fieldlabel", NULL, "forcejs");
6486  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6487  $a_xml_writer->xmlEndTag("qtimetadatafield");
6488 
6489  // custom style
6490  $a_xml_writer->xmlStartTag("qtimetadatafield");
6491  $a_xml_writer->xmlElement("fieldlabel", NULL, "customstyle");
6492  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCustomStyle());
6493  $a_xml_writer->xmlEndTag("qtimetadatafield");
6494 
6495  // shuffle questions
6496  $a_xml_writer->xmlStartTag("qtimetadatafield");
6497  $a_xml_writer->xmlElement("fieldlabel", NULL, "shuffle_questions");
6498  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShuffleQuestions()));
6499  $a_xml_writer->xmlEndTag("qtimetadatafield");
6500 
6501  // processing time
6502  $a_xml_writer->xmlStartTag("qtimetadatafield");
6503  $a_xml_writer->xmlElement("fieldlabel", NULL, "processing_time");
6504  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getProcessingTime());
6505  $a_xml_writer->xmlEndTag("qtimetadatafield");
6506 
6507  // enable_examview
6508  $a_xml_writer->xmlStartTag("qtimetadatafield");
6509  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_examview");
6510  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableExamview());
6511  $a_xml_writer->xmlEndTag("qtimetadatafield");
6512 
6513  // show_examview_html
6514  $a_xml_writer->xmlStartTag("qtimetadatafield");
6515  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_examview_html");
6516  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowExamviewHtml());
6517  $a_xml_writer->xmlEndTag("qtimetadatafield");
6518 
6519  // show_examview_pdf
6520  $a_xml_writer->xmlStartTag("qtimetadatafield");
6521  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_examview_pdf");
6522  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowExamviewPdf());
6523  $a_xml_writer->xmlEndTag("qtimetadatafield");
6524 
6525  // enable_archiving
6526  $a_xml_writer->xmlStartTag("qtimetadatafield");
6527  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_archiving");
6528  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableArchiving());
6529  $a_xml_writer->xmlEndTag("qtimetadatafield");
6530 
6531  // sign_submission
6532  $a_xml_writer->xmlStartTag("qtimetadatafield");
6533  $a_xml_writer->xmlElement("fieldlabel", NULL, "sign_submission");
6534  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getSignSubmission());
6535  $a_xml_writer->xmlEndTag("qtimetadatafield");
6536 
6537  // char_selector_availability
6538  $a_xml_writer->xmlStartTag("qtimetadatafield");
6539  $a_xml_writer->xmlElement("fieldlabel", NULL, "char_selector_availability");
6540  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getCharSelectorAvailability()));
6541  $a_xml_writer->xmlEndTag("qtimetadatafield");
6542 
6543  // char_selector_definition
6544  $a_xml_writer->xmlStartTag("qtimetadatafield");
6545  $a_xml_writer->xmlElement("fieldlabel", NULL, "char_selector_definition");
6546  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCharSelectorDefinition());
6547  $a_xml_writer->xmlEndTag("qtimetadatafield");
6548 
6549  // skill_service
6550  $a_xml_writer->xmlStartTag("qtimetadatafield");
6551  $a_xml_writer->xmlElement("fieldlabel", NULL, "skill_service");
6552  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isSkillServiceEnabled());
6553  $a_xml_writer->xmlEndTag("qtimetadatafield");
6554 
6555  // result_tax_filters
6556  $a_xml_writer->xmlStartTag("qtimetadatafield");
6557  $a_xml_writer->xmlElement("fieldlabel", NULL, "result_tax_filters");
6558  $a_xml_writer->xmlElement("fieldentry", NULL, serialize((array)$this->getResultFilterTaxIds()));
6559  $a_xml_writer->xmlEndTag("qtimetadatafield");
6560 
6561  // show_grading_status
6562  $a_xml_writer->xmlStartTag("qtimetadatafield");
6563  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_grading_status");
6564  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isShowGradingStatusEnabled());
6565  $a_xml_writer->xmlEndTag("qtimetadatafield");
6566 
6567  // show_grading_mark
6568  $a_xml_writer->xmlStartTag("qtimetadatafield");
6569  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_grading_mark");
6570  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isShowGradingMarkEnabled());
6571  $a_xml_writer->xmlEndTag("qtimetadatafield");
6572 
6573 
6574  // starting time
6575  if ($this->getStartingTime())
6576  {
6577  $a_xml_writer->xmlStartTag("qtimetadatafield");
6578  $a_xml_writer->xmlElement("fieldlabel", NULL, "starting_time");
6579  $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->starting_time);
6580  $a_xml_writer->xmlElement("fieldentry", NULL, $backward_compatibility_format);
6581  $a_xml_writer->xmlEndTag("qtimetadatafield");
6582  }
6583  // ending time
6584  if ($this->getEndingTime())
6585  {
6586  $a_xml_writer->xmlStartTag("qtimetadatafield");
6587  $a_xml_writer->xmlElement("fieldlabel", NULL, "ending_time");
6588  $backward_compatibility_format = $this->buildIso8601PeriodFromUnixtimeForExportCompatibility($this->ending_time);
6589  $a_xml_writer->xmlElement("fieldentry", NULL, $backward_compatibility_format);
6590  $a_xml_writer->xmlEndTag("qtimetadatafield");
6591  }
6592 
6593 
6594  //activation_limited
6595  $a_xml_writer->xmlStartTag("qtimetadatafield");
6596  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_limited");
6597  $a_xml_writer->xmlElement("fieldentry", NULL,(int)$this->isActivationLimited());
6598  $a_xml_writer->xmlEndTag("qtimetadatafield");
6599 
6600  //activation_start_time
6601  $a_xml_writer->xmlStartTag("qtimetadatafield");
6602  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_start_time");
6603  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationStartingTime());
6604  $a_xml_writer->xmlEndTag("qtimetadatafield");
6605 
6606  //activation_end_time
6607  $a_xml_writer->xmlStartTag("qtimetadatafield");
6608  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_end_time");
6609  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationEndingTime());
6610  $a_xml_writer->xmlEndTag("qtimetadatafield");
6611 
6612  //activation_visibility
6613  $a_xml_writer->xmlStartTag("qtimetadatafield");
6614  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_visibility");
6615  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationVisibility());
6616  $a_xml_writer->xmlEndTag("qtimetadatafield");
6617 
6618  // autosave
6619  $a_xml_writer->xmlStartTag("qtimetadatafield");
6620  $a_xml_writer->xmlElement("fieldlabel", NULL, "autosave");
6621  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getAutosave());
6622  $a_xml_writer->xmlEndTag("qtimetadatafield");
6623 
6624  // autosave_ival
6625  $a_xml_writer->xmlStartTag("qtimetadatafield");
6626  $a_xml_writer->xmlElement("fieldlabel", NULL, "autosave_ival");
6627  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getAutosaveIval());
6628  $a_xml_writer->xmlEndTag("qtimetadatafield");
6629 
6630  //offer_question_hints
6631  $a_xml_writer->xmlStartTag("qtimetadatafield");
6632  $a_xml_writer->xmlElement("fieldlabel", NULL, "offer_question_hints");
6633  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isOfferingQuestionHintsEnabled());
6634  $a_xml_writer->xmlEndTag("qtimetadatafield");
6635 
6636  //instant_feedback_specific
6637  $a_xml_writer->xmlStartTag("qtimetadatafield");
6638  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_feedback_specific");
6639  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getSpecificAnswerFeedback());
6640  $a_xml_writer->xmlEndTag("qtimetadatafield");
6641 
6642  //instant_feedback_answer_fixation
6643  $a_xml_writer->xmlStartTag("qtimetadatafield");
6644  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_feedback_answer_fixation");
6645  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isInstantFeedbackAnswerFixationEnabled());
6646  $a_xml_writer->xmlEndTag("qtimetadatafield");
6647 
6648  //obligations_enabled
6649  $a_xml_writer->xmlStartTag("qtimetadatafield");
6650  $a_xml_writer->xmlElement("fieldlabel", NULL, "obligations_enabled");
6651  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->areObligationsEnabled());
6652  $a_xml_writer->xmlEndTag("qtimetadatafield");
6653 
6654  //enable_processing_time
6655  $a_xml_writer->xmlStartTag("qtimetadatafield");
6656  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_processing_time");
6657  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableProcessingTime());
6658  $a_xml_writer->xmlEndTag("qtimetadatafield");
6659 
6660  foreach ($this->mark_schema->mark_steps as $index => $mark)
6661  {
6662  // mark steps
6663  $a_xml_writer->xmlStartTag("qtimetadatafield");
6664  $a_xml_writer->xmlElement("fieldlabel", NULL, "mark_step_$index");
6665  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf(
6666  "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
6667  $mark->getShortName(), $mark->getOfficialName(), $mark->getMinimumLevel(), $mark->getPassed()
6668  ));
6669  $a_xml_writer->xmlEndTag("qtimetadatafield");
6670  }
6671  $a_xml_writer->xmlEndTag("qtimetadata");
6672 
6673  // add qti objectives
6674  $a_xml_writer->xmlStartTag("objectives");
6675  $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6676  $a_xml_writer->xmlEndTag("objectives");
6677 
6678  // add qti assessmentcontrol
6679  if ($this->getInstantFeedbackSolution() == 1)
6680  {
6681  $attrs = array(
6682  "solutionswitch" => "Yes"
6683  );
6684  }
6685  else
6686  {
6687  $attrs = NULL;
6688  }
6689  $a_xml_writer->xmlElement("assessmentcontrol", $attrs, NULL);
6690 
6691  if (strlen($this->getFinalStatement()))
6692  {
6693  // add qti presentation_material
6694  $a_xml_writer->xmlStartTag("presentation_material");
6695  $a_xml_writer->xmlStartTag("flow_mat");
6696  $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6697  $a_xml_writer->xmlEndTag("flow_mat");
6698  $a_xml_writer->xmlEndTag("presentation_material");
6699  }
6700 
6701  $attrs = array(
6702  "ident" => "1"
6703  );
6704  $a_xml_writer->xmlElement("section", $attrs, NULL);
6705  $a_xml_writer->xmlEndTag("assessment");
6706  $a_xml_writer->xmlEndTag("questestinterop");
6707 
6708  $xml = $a_xml_writer->xmlDumpMem(FALSE);
6709  return $xml;
6710  }
6711 
6716  protected function buildIso8601PeriodFromUnixtimeForExportCompatibility($unix_timestamp)
6717  {
6718  $date_time_unix = new ilDateTime($unix_timestamp, IL_CAL_UNIX);
6719  $date_time = $date_time_unix->get(IL_CAL_DATETIME);
6720  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $date_time, $matches);
6721  $iso8601_period = sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]);
6722  return $iso8601_period;
6723  }
6724 
6731  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6732  {
6733  global $ilBench;
6734 
6735  $this->mob_ids = array();
6736  $this->file_ids = array();
6737 
6738  // MetaData
6739  $this->exportXMLMetaData($a_xml_writer);
6740 
6741  // PageObjects
6742  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
6743  $ilBench->start("ContentObjectExport", "exportPageObjects");
6744  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6745  $ilBench->stop("ContentObjectExport", "exportPageObjects");
6746  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
6747 
6748  // MediaObjects
6749  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
6750  $ilBench->start("ContentObjectExport", "exportMediaObjects");
6751  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6752  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6753  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
6754 
6755  // FileItems
6756  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
6757  $ilBench->start("ContentObjectExport", "exportFileItems");
6758  $this->exportFileItems($a_target_dir, $expLog);
6759  $ilBench->stop("ContentObjectExport", "exportFileItems");
6760  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
6761  }
6762 
6769  function exportXMLMetaData(&$a_xml_writer)
6770  {
6771  include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6772  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6773  $md2xml->setExportMode(true);
6774  $md2xml->startExport();
6775  $a_xml_writer->appendXML($md2xml->getXML());
6776  }
6777 
6783  function modifyExportIdentifier($a_tag, $a_param, $a_value)
6784  {
6785  if ($a_tag == "Identifier" && $a_param == "Entry")
6786  {
6787  include_once "./Services/Utilities/classes/class.ilUtil.php";
6788  $a_value = ilUtil::insertInstIntoID($a_value);
6789  }
6790 
6791  return $a_value;
6792  }
6793 
6794 
6801  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6802  {
6803  global $ilBench;
6804 
6805  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6806 
6807  foreach ($this->questions as $question_id)
6808  {
6809  $ilBench->start("ContentObjectExport", "exportPageObject");
6810  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
6811 
6812  $attrs = array();
6813  $a_xml_writer->xmlStartTag("PageObject", $attrs);
6814 
6815 
6816  // export xml to writer object
6817  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6818  include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
6819  $page_object = new ilAssQuestionPage($question_id);
6820  $page_object->buildDom();
6821  $page_object->insertInstIntoIDs($a_inst);
6822  $mob_ids = $page_object->collectMediaObjects(false);
6823  require_once 'Services/COPage/classes/class.ilPCFileList.php';
6824  $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
6825  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6826  $xml = str_replace("&","&amp;", $xml);
6827  $a_xml_writer->appendXML($xml);
6828  $page_object->freeDom();
6829  unset ($page_object);
6830 
6831  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6832 
6833  // collect media objects
6834  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6835  //$mob_ids = $page_obj->getMediaObjectIDs();
6836  foreach($mob_ids as $mob_id)
6837  {
6838  $this->mob_ids[$mob_id] = $mob_id;
6839  }
6840  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6841 
6842  // collect all file items
6843  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6844  //$file_ids = $page_obj->getFileItemIds();
6845  foreach($file_ids as $file_id)
6846  {
6847  $this->file_ids[$file_id] = $file_id;
6848  }
6849  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6850 
6851  $a_xml_writer->xmlEndTag("PageObject");
6852  //unset($page_obj);
6853 
6854  $ilBench->stop("ContentObjectExport", "exportPageObject");
6855 
6856 
6857  }
6858  }
6859 
6866  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6867  {
6868  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6869 
6870  foreach ($this->mob_ids as $mob_id)
6871  {
6872  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
6873  if (ilObjMediaObject::_exists($mob_id))
6874  {
6875  $media_obj = new ilObjMediaObject($mob_id);
6876  $media_obj->exportXML($a_xml_writer, $a_inst);
6877  $media_obj->exportFiles($a_target_dir);
6878  unset($media_obj);
6879  }
6880  }
6881  }
6882 
6887  function exportFileItems($a_target_dir, &$expLog)
6888  {
6889  include_once "./Modules/File/classes/class.ilObjFile.php";
6890 
6891  foreach ($this->file_ids as $file_id)
6892  {
6893  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
6894  $file_obj = new ilObjFile($file_id, false);
6895  $file_obj->export($a_target_dir);
6896  unset($file_obj);
6897  }
6898  }
6899 
6904  function getImportMapping()
6905  {
6906  if (!is_array($this->import_mapping))
6907  {
6908  return array();
6909  }
6910  else
6911  {
6912  return $this->import_mapping;
6913  }
6914  }
6915 
6919  public function canEditEctsGrades()
6920  {
6921  return $this->canShowEctsGrades() && $this->canEditMarks();
6922  }
6923 
6927  public function canShowEctsGrades()
6928  {
6929  return $this->getReportingDate();
6930  }
6931 
6935  public function getECTSGrade($passed_array, $reached_points, $max_points)
6936  {
6937  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);
6938  }
6939 
6943  public static function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6944  {
6945  include_once "./Modules/Test/classes/class.ilStatistics.php";
6946  // calculate the median
6947  $passed_statistics = new ilStatistics();
6948  $passed_statistics->setData($points_passed);
6949  $ects_percentiles = array
6950  (
6951  "A" => $passed_statistics->quantile($a),
6952  "B" => $passed_statistics->quantile($b),
6953  "C" => $passed_statistics->quantile($c),
6954  "D" => $passed_statistics->quantile($d),
6955  "E" => $passed_statistics->quantile($e)
6956  );
6957  if (count($points_passed) && ($reached_points >= $ects_percentiles["A"]))
6958  {
6959  return "A";
6960  }
6961  else if (count($points_passed) && ($reached_points >= $ects_percentiles["B"]))
6962  {
6963  return "B";
6964  }
6965  else if (count($points_passed) && ($reached_points >= $ects_percentiles["C"]))
6966  {
6967  return "C";
6968  }
6969  else if (count($points_passed) && ($reached_points >= $ects_percentiles["D"]))
6970  {
6971  return "D";
6972  }
6973  else if (count($points_passed) && ($reached_points >= $ects_percentiles["E"]))
6974  {
6975  return "E";
6976  }
6977  else if (strcmp($fx, "") != 0)
6978  {
6979  if ($max_points > 0)
6980  {
6981  $percentage = ($reached_points / $max_points) * 100.0;
6982  if ($percentage < 0) $percentage = 0.0;
6983  }
6984  else
6985  {
6986  $percentage = 0.0;
6987  }
6988  if ($percentage >= $fx)
6989  {
6990  return "FX";
6991  }
6992  else
6993  {
6994  return "F";
6995  }
6996  }
6997  else
6998  {
6999  return "F";
7000  }
7001  }
7002 
7006  public function checkMarks()
7007  {
7008  return $this->mark_schema->checkMarks();
7009  }
7010 
7014  public function getMarkSchema()
7015  {
7016  return $this->mark_schema;
7017  }
7018 
7022  public function getMarkSchemaForeignId()
7023  {
7024  return $this->getTestId();
7025  }
7026 
7029  public function onMarkSchemaSaved()
7030  {
7036  global $ilDB, $ilPluginAdmin, $tree;
7037 
7038  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
7039  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7040  $this->saveCompleteStatus($testQuestionSetConfigFactory->getQuestionSetConfig());
7041 
7042  if( $this->participantDataExist() )
7043  {
7044  $this->recalculateScores(true);
7045  }
7046  }
7047 
7051  public function canEditMarks()
7052  {
7053  $total = $this->evalTotalPersons();
7054  if($total > 0)
7055  {
7056  if($this->getReportingDate())
7057  {
7058  if(preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
7059  {
7060  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
7061  $now = time();
7062  if($now < $epoch_time)
7063  {
7064  return true;
7065  }
7066  }
7067  }
7068  return false;
7069  }
7070  else
7071  {
7072  return true;
7073  }
7074  }
7075 
7083  function setAuthor($author = "")
7084  {
7085  $this->author = $author;
7086  }
7087 
7097  function saveAuthorToMetadata($a_author = "")
7098  {
7099  $md = new ilMD($this->getId(), 0, $this->getType());
7100  $md_life =& $md->getLifecycle();
7101  if (!$md_life)
7102  {
7103  if (strlen($a_author) == 0)
7104  {
7105  global $ilUser;
7106  $a_author = $ilUser->getFullname();
7107  }
7108 
7109  $md_life =& $md->addLifecycle();
7110  $md_life->save();
7111  $con =& $md_life->addContribute();
7112  $con->setRole("Author");
7113  $con->save();
7114  $ent =& $con->addEntity();
7115  $ent->setEntity($a_author);
7116  $ent->save();
7117  }
7118  }
7119 
7125  function createMetaData()
7126  {
7127  parent::createMetaData();
7128  $this->saveAuthorToMetadata();
7129  }
7130 
7138  function getAuthor()
7139  {
7140  $author = array();
7141  include_once "./Services/MetaData/classes/class.ilMD.php";
7142  $md = new ilMD($this->getId(), 0, $this->getType());
7143  $md_life =& $md->getLifecycle();
7144  if ($md_life)
7145  {
7146  $ids =& $md_life->getContributeIds();
7147  foreach ($ids as $id)
7148  {
7149  $md_cont =& $md_life->getContribute($id);
7150  if (strcmp($md_cont->getRole(), "Author") == 0)
7151  {
7152  $entids =& $md_cont->getEntityIds();
7153  foreach ($entids as $entid)
7154  {
7155  $md_ent =& $md_cont->getEntity($entid);
7156  array_push($author, $md_ent->getEntity());
7157  }
7158  }
7159  }
7160  }
7161  return join($author, ",");
7162  }
7163 
7171  public static function _lookupAuthor($obj_id)
7172  {
7173  $author = array();
7174  include_once "./Services/MetaData/classes/class.ilMD.php";
7175  $md = new ilMD($obj_id, 0, "tst");
7176  $md_life =& $md->getLifecycle();
7177  if ($md_life)
7178  {
7179  $ids =& $md_life->getContributeIds();
7180  foreach ($ids as $id)
7181  {
7182  $md_cont =& $md_life->getContribute($id);
7183  if (strcmp($md_cont->getRole(), "Author") == 0)
7184  {
7185  $entids =& $md_cont->getEntityIds();
7186  foreach ($entids as $entid)
7187  {
7188  $md_ent =& $md_cont->getEntity($entid);
7189  array_push($author, $md_ent->getEntity());
7190  }
7191  }
7192  }
7193  }
7194  return join($author, ",");
7195  }
7196 
7203  public static function _getAvailableTests($use_object_id = FALSE)
7204  {
7205  global $ilUser;
7206  global $ilDB;
7207 
7208  $result_array = array();
7209  $tests = ilUtil::_getObjectsByOperations("tst","write", $ilUser->getId(), -1);
7210  if (count($tests))
7211  {
7212  $titles = ilObject::_prepareCloneSelection($tests, "tst");
7213  foreach ($tests as $ref_id)
7214  {
7215  if ($use_object_id)
7216  {
7217  $obj_id = ilObject::_lookupObjId($ref_id);
7218  $result_array[$obj_id] = $titles[$ref_id];
7219  }
7220  else
7221  {
7222  $result_array[$ref_id] = $titles[$ref_id];
7223  }
7224  }
7225  }
7226  return $result_array;
7227  }
7228 
7237  public function cloneObject($a_target_id,$a_copy_id = 0, $a_omit_tree = false)
7238  {
7239  global $ilLog, $tree, $ilDB, $ilPluginAdmin;
7240 
7241  $this->loadFromDb();
7242 
7243  // Copy settings
7245  $newObj = parent::cloneObject($a_target_id,$a_copy_id, $a_omit_tree);
7246  $newObj->setTmpCopyWizardCopyId($a_copy_id);
7247  $this->cloneMetaData($newObj);
7248 
7249  //copy online status if object is not the root copy object
7250  $cp_options = ilCopyWizardOptions::_getInstance($a_copy_id);
7251 
7252  if(!$cp_options->isRootNode($this->getRefId()))
7253  {
7254  $newObj->setOnline($this->isOnline());
7255  }
7256 
7257  $newObj->setAnonymity($this->getAnonymity());
7258  $newObj->setAnswerFeedback($this->getAnswerFeedback());
7259  $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
7260  $newObj->setAuthor($this->getAuthor());
7261  $newObj->setLimitUsersEnabled($this->isLimitUsersEnabled());
7262  $newObj->setAllowedUsers($this->getAllowedUsers());
7263  $newObj->setAllowedUsersTimeGap($this->getAllowedUsersTimeGap());
7264  $newObj->setCountSystem($this->getCountSystem());
7265  $newObj->setECTSFX($this->getECTSFX());
7266  $newObj->setECTSGrades($this->getECTSGrades());
7267  $newObj->setECTSOutput($this->getECTSOutput());
7268  $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
7269  $newObj->setEndingTimeEnabled($this->isEndingTimeEnabled());
7270  $newObj->setEndingTime($this->getEndingTime());
7271  $newObj->setFixedParticipants($this->getFixedParticipants());
7272  $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
7273  $newObj->setIntroductionEnabled($this->isIntroductionEnabled());
7274  $newObj->setIntroduction($this->getIntroduction());
7275  $newObj->setFinalStatement($this->getFinalStatement());
7276  $newObj->setShowInfo($this->getShowInfo());
7277  $newObj->setForceJS($this->getForceJS());
7278  $newObj->setCustomStyle($this->getCustomStyle());
7279  $newObj->setKiosk($this->getKiosk());
7280  $newObj->setShowFinalStatement($this->getShowFinalStatement());
7281  $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
7282  $newObj->setMCScoring($this->getMCScoring());
7283  $newObj->setMailNotification($this->getMailNotification());
7284  $newObj->setMailNotificationType($this->getMailNotificationType());
7285  $newObj->setNrOfTries($this->getNrOfTries());
7286  $newObj->setPassScoring($this->getPassScoring());
7287  $newObj->setPasswordEnabled($this->isPasswordEnabled());
7288  $newObj->setPassword($this->getPassword());
7289  $newObj->setProcessingTime($this->getProcessingTime());
7290  $newObj->setQuestionSetType($this->getQuestionSetType());
7291  $newObj->setReportingDate($this->getReportingDate());
7292  $newObj->setResetProcessingTime($this->getResetProcessingTime());
7293  $newObj->setResultsPresentation($this->getResultsPresentation());
7294  $newObj->setScoreCutting($this->getScoreCutting());
7295  $newObj->setScoreReporting($this->getScoreReporting());
7296  $newObj->setSequenceSettings($this->getSequenceSettings());
7297  $newObj->setShowCancel($this->getShowCancel());
7298  $newObj->setShowMarker($this->getShowMarker());
7299  $newObj->setShuffleQuestions($this->getShuffleQuestions());
7300  $newObj->setStartingTimeEnabled($this->isStartingTimeEnabled());
7301  $newObj->setStartingTime($this->getStartingTime());
7302  $newObj->setTitleOutput($this->getTitleOutput());
7303  $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
7304  $newObj->setRedirectionMode($this->getRedirectionMode());
7305  $newObj->setRedirectionUrl($this->getRedirectionUrl());
7306  $newObj->setCertificateVisibility($this->getCertificateVisibility());
7307  $newObj->mark_schema = clone $this->mark_schema;
7308  $newObj->setEnabledViewMode($this->getEnabledViewMode());
7309  $newObj->setTemplate($this->getTemplate());
7310  $newObj->setPoolUsage($this->getPoolUsage());
7311  $newObj->setPrintBestSolutionWithResult($this->isBestSolutionPrintedWithResult());
7312  $newObj->setShowExamIdInTestPassEnabled($this->isShowExamIdInTestPassEnabled());
7313  $newObj->setShowExamIdInTestResultsEnabled($this->isShowExamIdInTestResultsEnabled());
7314  $newObj->setEnableExamView($this->getEnableExamview());
7315  $newObj->setShowExamViewHtml($this->getShowExamviewHtml());
7316  $newObj->setShowExamViewPdf($this->getShowExamviewPdf());
7317  $newObj->setEnableArchiving($this->getEnableArchiving());
7318  $newObj->setSignSubmission($this->getSignSubmission());
7319  $newObj->setCharSelectorAvailability((int)$this->getCharSelectorAvailability());
7320  $newObj->setCharSelectorDefinition($this->getCharSelectorDefinition());
7321  $newObj->setSkillServiceEnabled($this->isSkillServiceEnabled());
7322  $newObj->setResultFilterTaxIds($this->getResultFilterTaxIds());
7323  $newObj->setInstantFeedbackAnswerFixationEnabled($this->isInstantFeedbackAnswerFixationEnabled());
7324  $newObj->setForceInstantFeedbackEnabled($this->isForceInstantFeedbackEnabled());
7325  $newObj->setAutosave($this->getAutosave());
7326  $newObj->setAutosaveIval($this->getAutosaveIval());
7327  $newObj->setOfferingQuestionHintsEnabled($this->isOfferingQuestionHintsEnabled());
7328  $newObj->setSpecificAnswerFeedback($this->getSpecificAnswerFeedback());
7329  $newObj->setObligationsEnabled($this->areObligationsEnabled());
7330  $newObj->saveToDb();
7331 
7332  // clone certificate
7333  include_once "./Services/Certificate/classes/class.ilCertificate.php";
7334  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
7335  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
7336  $newcert = new ilCertificate(new ilTestCertificateAdapter($newObj));
7337  $cert->cloneCertificate($newcert);
7338 
7339  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
7340  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7341  $testQuestionSetConfigFactory->getQuestionSetConfig()->cloneQuestionSetRelatedData($newObj);
7342 
7343  require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdList.php';
7344  $skillLevelThresholdList = new ilTestSkillLevelThresholdList($ilDB);
7345  $skillLevelThresholdList->setTestId($this->getTestId());
7346  $skillLevelThresholdList->loadFromDb();
7347  $skillLevelThresholdList->cloneListForTest($newObj->getTestId());
7348 
7349  $newObj->saveToDb();
7350  $newObj->updateMetaData();// #14467
7351 
7352  include_once('./Services/Tracking/classes/class.ilLPObjSettings.php');
7353  $obj_settings = new ilLPObjSettings($this->getId());
7354  $obj_settings->cloneSettings($newObj->getId());
7355 
7356  return $newObj;
7357  }
7358 
7365  function getQuestionCount()
7366  {
7367  $num = 0;
7368 
7369  if( $this->isRandomTest() )
7370  {
7371  global $tree, $ilDB, $ilPluginAdmin;
7372 
7373  $questionSetConfig = new ilTestRandomQuestionSetConfig(
7374  $tree, $ilDB, $ilPluginAdmin, $this
7375  );
7376 
7377  $questionSetConfig->loadFromDb();
7378 
7379  if( $questionSetConfig->isQuestionAmountConfigurationModePerPool() )
7380  {
7381  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php';
7382  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetBuilderWithAmountPerPool.php';
7383  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php';
7384 
7385  $sourcePoolDefinitionList = new ilTestRandomQuestionSetSourcePoolDefinitionList(
7386  $ilDB, $this, new ilTestRandomQuestionSetSourcePoolDefinitionFactory($ilDB, $this)
7387  );
7388 
7389  $sourcePoolDefinitionList->loadDefinitions();
7390 
7391  $num = $sourcePoolDefinitionList->getQuestionAmount();
7392  }
7393  else
7394  {
7395  $num = $questionSetConfig->getQuestionAmountPerTest();
7396  }
7397  }
7398  else
7399  {
7400  $num = count($this->questions);
7401  }
7402 
7403  return $num;
7404  }
7405 
7413  function logAction($logtext = "", $question_id = "")
7414  {
7415  global $ilUser;
7416 
7417  $original_id = "";
7418  if (strcmp($question_id, "") != 0)
7419  {
7420  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7421  $original_id = assQuestion::_getOriginalId($question_id);
7422  }
7423  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7424  ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, TRUE, $this->getRefId());
7425  }
7426 
7434  public static function _getObjectIDFromTestID($test_id)
7435  {
7436  global $ilDB;
7437  $object_id = FALSE;
7438  $result = $ilDB->queryF("SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7439  array('integer'),
7440  array($test_id)
7441  );
7442  if ($result->numRows())
7443  {
7444  $row = $ilDB->fetchAssoc($result);
7445  $object_id = $row["obj_fi"];
7446  }
7447  return $object_id;
7448  }
7449 
7457  public static function _getObjectIDFromActiveID($active_id)
7458  {
7459  global $ilDB;
7460  $object_id = FALSE;
7461  $result = $ilDB->queryF("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",
7462  array('integer'),
7463  array($active_id)
7464  );
7465  if ($result->numRows())
7466  {
7467  $row = $ilDB->fetchAssoc($result);
7468  $object_id = $row["obj_fi"];
7469  }
7470  return $object_id;
7471  }
7472 
7480  public static function _getTestIDFromObjectID($object_id)
7481  {
7482  global $ilDB;
7483  $test_id = FALSE;
7484  $result = $ilDB->queryF("SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7485  array('integer'),
7486  array($object_id)
7487  );
7488  if ($result->numRows())
7489  {
7490  $row = $ilDB->fetchAssoc($result);
7491  $test_id = $row["test_id"];
7492  }
7493  return $test_id;
7494  }
7495 
7504  function getTextAnswer($active_id, $question_id, $pass = NULL)
7505  {
7506  global $ilDB;
7507 
7508  $res = "";
7509  if (($active_id) && ($question_id))
7510  {
7511  if (is_null($pass))
7512  {
7513  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7514  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7515  }
7516  $result = $ilDB->queryF("SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7517  array('integer', 'integer', 'integer'),
7518  array($active_id, $question_id, $pass)
7519  );
7520  if ($result->numRows() == 1)
7521  {
7522  $row = $ilDB->fetchAssoc($result);
7523  $res = $row["value1"];
7524  }
7525  }
7526  return $res;
7527  }
7528 
7536  function getQuestiontext($question_id)
7537  {
7538  global $ilDB;
7539 
7540  $res = "";
7541  if ($question_id)
7542  {
7543  $result = $ilDB->queryF("SELECT question_text FROM qpl_questions WHERE question_id = %s",
7544  array('integer'),
7545  array($question_id)
7546  );
7547  if ($result->numRows() == 1)
7548  {
7549  $row = $ilDB->fetchAssoc($result);
7550  $res = $row["question_text"];
7551  }
7552  }
7553  return $res;
7554  }
7555 
7562  function &getInvitedUsers($user_id="", $order="login, lastname, firstname")
7563  {
7564  global $ilDB;
7565 
7566  $result_array = array();
7567 
7568  if ($this->getAnonymity())
7569  {
7570  if (is_numeric($user_id))
7571  {
7572  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7573  "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 " .
7574  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7575  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7576  "ORDER BY $order",
7577  array('text', 'text', 'text', 'integer', 'integer'),
7578  array("", $this->lng->txt("anonymous"), "", $this->getTestId(), $user_id)
7579  );
7580  }
7581  else
7582  {
7583  $result = $ilDB->queryF("SELECT tst_active.active_id, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7584  "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 " .
7585  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7586  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7587  "ORDER BY $order",
7588  array('text', 'text', 'text', 'integer'),
7589  array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7590  );
7591  }
7592  }
7593  else
7594  {
7595  if (is_numeric($user_id))
7596  {
7597  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7598  "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 " .
7599  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7600  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7601  "ORDER BY $order",
7602  array('integer', 'integer'),
7603  array($this->getTestId(), $user_id)
7604  );
7605  }
7606  else
7607  {
7608  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7609  "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 " .
7610  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7611  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7612  "ORDER BY $order",
7613  array('integer'),
7614  array($this->getTestId())
7615  );
7616  }
7617  }
7618  $result_array = array();
7619  while ($row = $ilDB->fetchAssoc($result))
7620  {
7621  $result_array[$row['usr_id']]= $row;
7622  }
7623  return $result_array;
7624  }
7625 
7633  {
7634  global $ilDB;
7635 
7636  if ($this->getAnonymity())
7637  {
7638  $query = "
7639  SELECT tst_active.active_id,
7640  tst_active.tries,
7641  tst_active.user_fi usr_id,
7642  %s login,
7643  %s lastname,
7644  %s firstname,
7645  tst_active.submitted test_finished,
7646  usr_data.matriculation,
7647  usr_data.active,
7648  tst_active.lastindex,
7649  COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7650  FROM tst_active
7651  LEFT JOIN usr_data
7652  ON tst_active.user_fi = usr_data.usr_id
7653  WHERE tst_active.test_fi = %s
7654  ORDER BY usr_data.lastname
7655  ";
7656  $result = $ilDB->queryF($query,
7657  array('text', 'text', 'text', 'integer'),
7658  array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7659  );
7660  }
7661  else
7662  {
7663  $query = "
7664  SELECT tst_active.active_id,
7665  tst_active.tries,
7666  tst_active.user_fi usr_id,
7667  usr_data.login,
7668  usr_data.lastname,
7669  usr_data.firstname,
7670  tst_active.submitted test_finished,
7671  usr_data.matriculation,
7672  usr_data.active,
7673  tst_active.lastindex,
7674  COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
7675  FROM tst_active
7676  LEFT JOIN usr_data
7677  ON tst_active.user_fi = usr_data.usr_id
7678  WHERE tst_active.test_fi = %s
7679  ORDER BY usr_data.lastname
7680  ";
7681  $result = $ilDB->queryF(
7682  $query, array('integer'), array($this->getTestId())
7683  );
7684  }
7685  $data = array();
7686  while ($row = $ilDB->fetchAssoc($result))
7687  {
7688  $data[$row['active_id']] = $row;
7689  }
7690  foreach ($data as $index => $participant)
7691  {
7692  if (strlen(trim($participant["firstname"].$participant["lastname"])) == 0)
7693  {
7694  $data[$index]["lastname"] = $this->lng->txt("deleted_user");
7695  }
7696  }
7697  return $data;
7698  }
7699 
7700  public function getTestParticipantsForManualScoring($filter = NULL)
7701  {
7702  global $ilDB;
7703 
7704  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7706  if (count($scoring) == 0) return array();
7707 
7708  $participants =& $this->getTestParticipants();
7709  $filtered_participants = array();
7710  foreach ($participants as $active_id => $participant)
7711  {
7712  $qstType_IN_manScoreableQstTypes = $ilDB->in('qpl_questions.question_type_fi', $scoring, false, 'integer');
7713 
7714  $queryString = "
7715  SELECT tst_test_result.manual
7716 
7717  FROM tst_test_result
7718 
7719  INNER JOIN qpl_questions
7720  ON tst_test_result.question_fi = qpl_questions.question_id
7721 
7722  WHERE tst_test_result.active_fi = %s
7723  AND $qstType_IN_manScoreableQstTypes
7724  ";
7725 
7726  $result = $ilDB->queryF(
7727  $queryString, array("integer"), array($active_id)
7728  );
7729 
7730  $count = $result->numRows();
7731 
7732  if ($count > 0)
7733  {
7734  switch ($filter)
7735  {
7736  case 1: // only active users
7737  if ($participant->active) $filtered_participants[$active_id] = $participant;
7738  break;
7739  case 2: // only inactive users
7740  if (!$participant->active) $filtered_participants[$active_id] = $participant;
7741  break;
7742  case 3: // all users
7743  $filtered_participants[$active_id] = $participant;
7744  break;
7745  case 4:
7746  // already scored participants
7747  //$found = 0;
7748  //while ($row = $ilDB->fetchAssoc($result))
7749  //{
7750  // if ($row["manual"]) $found++;
7751  //}
7752  //if ($found == $count)
7753  //{
7754  //$filtered_participants[$active_id] = $participant;
7755  //}
7756  //else
7757  //{
7758  $assessmentSetting = new ilSetting("assessment");
7759  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7760  if ($manscoring_done) $filtered_participants[$active_id] = $participant;
7761  //}
7762  break;
7763  case 5:
7764  // unscored participants
7765  //$found = 0;
7766  //while ($row = $ilDB->fetchAssoc($result))
7767  //{
7768  // if ($row["manual"]) $found++;
7769  //}
7770  //if ($found == 0)
7771  //{
7772  $assessmentSetting = new ilSetting("assessment");
7773  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7774  if (!$manscoring_done) $filtered_participants[$active_id] = $participant;
7775  //}
7776  break;
7777  case 6:
7778  // partially scored participants
7779  $found = 0;
7780  while ($row = $ilDB->fetchAssoc($result))
7781  {
7782  if ($row["manual"]) $found++;
7783  }
7784  if (($found > 0) && ($found < $count)) $filtered_participants[$active_id] = $participant;
7785  break;
7786  default:
7787  $filtered_participants[$active_id] = $participant;
7788  break;
7789  }
7790  }
7791  }
7792  return $filtered_participants;
7793  }
7794 
7802  function &getUserData($ids)
7803  {
7804  global $ilDB;
7805 
7806  if (!is_array($ids) || count($ids) ==0) return array();
7807 
7808  if ($this->getAnonymity())
7809  {
7810  $result = $ilDB->queryF("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",
7811  array('text', 'text', 'text'),
7812  array("", $this->lng->txt("anonymous"), "")
7813  );
7814  }
7815  else
7816  {
7817  $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");
7818  }
7819 
7820  $result_array = array();
7821  while ($row = $ilDB->fetchAssoc($result))
7822  {
7823  $result_array[$row["usr_id"]]= $row;
7824  }
7825  return $result_array;
7826  }
7827 
7828  function &getGroupData($ids)
7829  {
7830  if (!is_array($ids) || count($ids) ==0) return array();
7831  $result = array();
7832  foreach ($ids as $ref_id)
7833  {
7834  $obj_id = ilObject::_lookupObjId($ref_id);
7835  $result[$ref_id] = array("ref_id" => $ref_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7836  }
7837  return $result;
7838  }
7839 
7840  function &getRoleData($ids)
7841  {
7842  if (!is_array($ids) || count($ids) ==0) return array();
7843  $result = array();
7844  foreach ($ids as $obj_id)
7845  {
7846  $result[$obj_id] = array("obj_id" => $obj_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7847  }
7848  return $result;
7849  }
7850 
7851 
7858  function inviteGroup($group_id)
7859  {
7860  include_once "./Modules/Group/classes/class.ilObjGroup.php";
7861  $group = new ilObjGroup($group_id);
7862  $members = $group->getGroupMemberIds();
7863  include_once './Services/User/classes/class.ilObjUser.php';
7864  foreach ($members as $user_id)
7865  {
7866  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7867  }
7868  }
7869 
7876  function inviteRole($role_id)
7877  {
7878  global $rbacreview;
7879  $members = $rbacreview->assignedUsers($role_id);
7880  include_once './Services/User/classes/class.ilObjUser.php';
7881  foreach ($members as $user_id)
7882  {
7883  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7884  }
7885  }
7886 
7887 
7888 
7895  function disinviteUser($user_id)
7896  {
7897  global $ilDB;
7898 
7899  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7900  array('integer', 'integer'),
7901  array($this->getTestId(), $user_id)
7902  );
7903  }
7904 
7911  function inviteUser($user_id, $client_ip="")
7912  {
7913  global $ilDB;
7914 
7915  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7916  array('integer', 'integer'),
7917  array($this->getTestId(), $user_id)
7918  );
7919  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
7920  array('integer', 'integer', 'text', 'integer'),
7921  array($this->getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : NULL, time())
7922  );
7923  }
7924 
7925 
7926  function setClientIP($user_id, $client_ip)
7927  {
7928  global $ilDB;
7929 
7930  $affectedRows = $ilDB->manipulateF("UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
7931  array('text', 'integer', 'integer', 'integer'),
7932  array((strlen($client_ip)) ? $client_ip : NULL, time(), $this->getTestId(), $user_id)
7933  );
7934  }
7935 
7941  public static function _getSolvedQuestions($active_id, $question_fi = null)
7942  {
7943  global $ilDB;
7944  if (is_numeric($question_fi))
7945  {
7946  $result = $ilDB->queryF("SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
7947  array('integer', 'integer'),
7948  array($active_id, $question_fi)
7949  );
7950  }
7951  else
7952  {
7953  $result = $ilDB->queryF("SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
7954  array('integer'),
7955  array($active_id)
7956  );
7957  }
7958  $result_array = array();
7959  while ($row = $ilDB->fetchAssoc($result))
7960  {
7961  $result_array[$row["question_fi"]]= $row;
7962  }
7963  return $result_array;
7964  }
7965 
7966 
7970  function setQuestionSetSolved($value, $question_id, $user_id)
7971  {
7972  global $ilDB;
7973 
7974  $active_id = $this->getActiveIdOfUser($user_id);
7975  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
7976  array('integer', 'integer'),
7977  array($active_id, $question_id)
7978  );
7979  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
7980  array('integer', 'integer', 'integer'),
7981  array($value, $question_id, $active_id)
7982  );
7983  }
7984 
7988  function isTestFinished($active_id)
7989  {
7990  global $ilDB;
7991 
7992  $result = $ilDB->queryF("SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
7993  array('integer', 'integer'),
7994  array($active_id, 1)
7995  );
7996  return $result->numRows() == 1;
7997  }
7998 
8002  function isActiveTestSubmitted($user_id = null)
8003  {
8004  global $ilUser;
8005  global $ilDB;
8006 
8007  if (!is_numeric($user_id))
8008  $user_id = $ilUser->getId();
8009 
8010  $result = $ilDB->queryF("SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
8011  array('integer', 'integer', 'integer'),
8012  array($this->getTestId(), $user_id, 1)
8013  );
8014  return $result->numRows() == 1;
8015  }
8016 
8021  {
8022  return $this->getNrOfTries() != 0;
8023  }
8024 
8025 
8031  function isNrOfTriesReached($tries)
8032  {
8033  return $tries >= (int) $this->getNrOfTries();
8034  }
8035 
8036 
8045  function getAllTestResults($participants, $prepareForCSV = true)
8046  {
8047  $results = array();
8048  $row = array(
8049  "user_id" => $this->lng->txt("user_id"),
8050  "matriculation" => $this->lng->txt("matriculation"),
8051  "lastname" => $this->lng->txt("lastname"),
8052  "firstname" => $this->lng->txt("firstname"),
8053  "login" =>$this->lng->txt("login"),
8054  "reached_points" => $this->lng->txt("tst_reached_points"),
8055  "max_points" => $this->lng->txt("tst_maximum_points"),
8056  "percent_value" => $this->lng->txt("tst_percent_solved"),
8057  "mark" => $this->lng->txt("tst_mark"),
8058  "ects" => $this->lng->txt("ects_grade")
8059  );
8060  $results[] = $row;
8061  if (count($participants))
8062  {
8063  if($this->getECTSOutput())
8064  {
8065  $passed_array =& $this->getTotalPointsPassedArray();
8066  }
8067  foreach ($participants as $active_id => $user_rec)
8068  {
8069  $mark = $ects_mark = '';
8070  $row = array();
8071  $reached_points = 0;
8072  $max_points = 0;
8073  foreach ($this->questions as $value)
8074  {
8075  $question =& ilObjTest::_instanciateQuestion($value);
8076  if (is_object($question))
8077  {
8078  $max_points += $question->getMaximumPoints();
8079  $reached_points += $question->getReachedPoints($active_id);
8080  }
8081  }
8082  if ($max_points > 0)
8083  {
8084  $percentvalue = $reached_points / $max_points;
8085  if ($percentvalue < 0) $percentvalue = 0.0;
8086  }
8087  else
8088  {
8089  $percentvalue = 0;
8090  }
8091  $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
8092  $passed = "";
8093  if ($mark_obj)
8094  {
8095  $mark = $mark_obj->getOfficialName();
8096  if($this->getECTSOutput())
8097  {
8098  $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
8099  }
8100  }
8101  if ($this->getAnonymity())
8102  {
8103  $user_rec['firstname'] = "";
8104  $user_rec['lastname'] = $this->lng->txt("anonymous");
8105  }
8106  $row = array(
8107  "user_id"=>$user_rec['usr_id'],
8108  "matriculation" => $user_rec['matriculation'],
8109  "lastname" => $user_rec['lastname'],
8110  "firstname" => $user_rec['firstname'],
8111  "login"=>$user_rec['login'],
8112  "reached_points" => $reached_points,
8113  "max_points" => $max_points,
8114  "percent_value" => $percentvalue,
8115  "mark" => $mark,
8116  "ects" => $ects_mark
8117  );
8118  $results[] = $prepareForCSV ? $this->processCSVRow ($row, true) : $row;
8119  }
8120  }
8121  return $results;
8122  }
8123 
8134  function &processCSVRow($row, $quoteAll = FALSE, $separator = ";")
8135  {
8136  $resultarray = array();
8137  foreach ($row as $rowindex => $entry)
8138  {
8139  $surround = FALSE;
8140  if ($quoteAll)
8141  {
8142  $surround = TRUE;
8143  }
8144  if (strpos($entry, "\"") !== FALSE)
8145  {
8146  $entry = str_replace("\"", "\"\"", $entry);
8147  $surround = TRUE;
8148  }
8149  if (strpos($entry, $separator) !== FALSE)
8150  {
8151  $surround = TRUE;
8152  }
8153  // replace all CR LF with LF (for Excel for Windows compatibility
8154  $entry = str_replace(chr(13).chr(10), chr(10), $entry);
8155 
8156  if ($surround)
8157  {
8158  $entry = "\"" . $entry . "\"";
8159  }
8160 
8161  $resultarray[$rowindex] = $entry;
8162  }
8163  return $resultarray;
8164  }
8165 
8174  public static function _getPass($active_id)
8175  {
8176  global $ilDB;
8177  $result = $ilDB->queryF("SELECT tries FROM tst_active WHERE active_id = %s",
8178  array('integer'),
8179  array($active_id)
8180  );
8181  if ($result->numRows())
8182  {
8183  $row = $ilDB->fetchAssoc($result);
8184  return $row["tries"];
8185  }
8186  else
8187  {
8188  return 0;
8189  }
8190  }
8191 
8201  public static function _getMaxPass($active_id)
8202  {
8203  global $ilDB;
8204  $result = $ilDB->queryF("SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
8205  array('integer'),
8206  array($active_id)
8207  );
8208  if ($result->numRows())
8209  {
8210  $row = $ilDB->fetchAssoc($result);
8211  $max = $row["maxpass"];
8212  }
8213  else
8214  {
8215  $max = NULL;
8216  }
8217  return $max;
8218  }
8219 
8225  public static function _getBestPass($active_id)
8226  {
8227  global $ilDB;
8228 
8229  $result = $ilDB->queryF("SELECT * FROM tst_pass_result WHERE active_fi = %s",
8230  array('integer'),
8231  array($active_id)
8232  );
8233  if ($result->numRows())
8234  {
8235  $bestrow = null;
8236  $bestfactor = 0;
8237  while ($row = $ilDB->fetchAssoc($result))
8238  {
8239  if($row["maxpoints"] > 0)
8240  {
8241  $factor = $row["points"] / $row["maxpoints"];
8242  }
8243  else
8244  {
8245  $factor = 0;
8246  }
8247 
8248  if($factor > $bestfactor)
8249  {
8250  $bestrow = $row;
8251  $bestfactor = $factor;
8252  }
8253  }
8254  if (is_array($bestrow))
8255  {
8256  return $bestrow["pass"];
8257  }
8258  else
8259  {
8260  return 0;
8261  }
8262  }
8263  else
8264  {
8265  return 0;
8266  }
8267  }
8268 
8277  public static function _getResultPass($active_id)
8278  {
8279  $counted_pass = NULL;
8280  if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS)
8281  {
8282  $counted_pass = ilObjTest::_getBestPass($active_id);
8283  }
8284  else
8285  {
8286  $counted_pass = ilObjTest::_getMaxPass($active_id);
8287  }
8288  return $counted_pass;
8289  }
8290 
8300  function getAnsweredQuestionCount($active_id, $pass = NULL)
8301  {
8302  if( $this->isDynamicTest() )
8303  {
8304  global $tree, $ilDB, $lng, $ilPluginAdmin;
8305 
8306  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
8307  $testSessionFactory = new ilTestSessionFactory($this);
8308  $testSession = $testSessionFactory->getSession($active_id);
8309 
8310  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
8311  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
8312  $testSequence = $testSequenceFactory->getSequenceByTestSession($testSession);
8313 
8314  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
8315  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
8316  $dynamicQuestionSetConfig->loadFromDb();
8317 
8318  $testSequence->loadFromDb($dynamicQuestionSetConfig);
8319  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
8320 
8321  return $testSequence->getTrackedQuestionCount();
8322  }
8323 
8324  if ($this->isRandomTest())
8325  {
8326  $this->loadQuestions($active_id, $pass);
8327  }
8328  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
8329  $workedthrough = 0;
8330  foreach ($this->questions as $value)
8331  {
8332  if (assQuestion::_isWorkedThrough($active_id, $value, $pass))
8333  {
8334  $workedthrough += 1;
8335  }
8336  }
8337  return $workedthrough;
8338  }
8339 
8349  function getPassFinishDate($active_id, $pass)
8350  {
8351  global $ilDB;
8352 
8353  if (is_null($pass))
8354  {
8355  $pass = 0;
8356  }
8357 
8358  $query = "
8359  SELECT tst_pass_result.tstamp pass_res_tstamp,
8360  tst_test_result.tstamp quest_res_tstamp
8361 
8362  FROM tst_pass_result
8363 
8364  LEFT JOIN tst_test_result
8365  ON tst_test_result.active_fi = tst_pass_result.active_fi
8366  AND tst_test_result.pass = tst_pass_result.pass
8367 
8368  WHERE tst_pass_result.active_fi = %s
8369  AND tst_pass_result.pass = %s
8370 
8371  ORDER BY tst_test_result.tstamp DESC
8372  ";
8373 
8374  $result = $ilDB->queryF($query,
8375  array('integer', 'integer'),
8376  array($active_id, $pass)
8377  );
8378 
8379  while( $row = $ilDB->fetchAssoc($result) )
8380  {
8381  if( $row['qres_tstamp'] )
8382  {
8383  return $row['quest_res_tstamp'];
8384  }
8385 
8386  return $row['pass_res_tstamp'];
8387  }
8388 
8389  return 0;
8390  }
8391 
8400  function isExecutable($testSession, $user_id, $allowPassIncrease = FALSE)
8401  {
8402  $result = array(
8403  "executable" => true,
8404  "errormessage" => ""
8405  );
8406  if (!$this->startingTimeReached())
8407  {
8408  $result["executable"] = false;
8409  $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getStartingTime(), IL_CAL_UNIX)));
8410  return $result;
8411  }
8412  if ($this->endingTimeReached())
8413  {
8414  $result["executable"] = false;
8415  $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilDatePresentation::formatDate(new ilDateTime($this->getEndingTime(), IL_CAL_UNIX)));
8416  return $result;
8417  }
8418 
8419  $active_id = $this->getActiveIdOfUser($user_id);
8420 
8421  if ($this->getEnableProcessingTime())
8422  {
8423  if ($active_id > 0)
8424  {
8425  $starting_time = $this->getStartingTimeOfUser($active_id);
8426  if ($starting_time !== FALSE)
8427  {
8428  if ($this->isMaxProcessingTimeReached($starting_time, $active_id))
8429  {
8430  if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > (self::_getPass($active_id)+1))))
8431  {
8432  // a test pass was quitted because the maximum processing time was reached, but the time
8433  // will be resetted for future passes, so if there are more passes allowed, the participant may
8434  // start the test again.
8435  // This code block is only called when $allowPassIncrease is TRUE which only happens when
8436  // the test info page is opened. Otherwise this will lead to unexpected results!
8437  $testSession->increasePass();
8438  $testSession->setLastSequence(0);
8439  $testSession->saveToDb();
8440  }
8441  else
8442  {
8443  $result["executable"] = false;
8444  $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8445  }
8446  return $result;
8447  }
8448  }
8449  }
8450  }
8451  require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8452  $testPassesSelector = new ilTestPassesSelector($GLOBALS['ilDB'], $this);
8453  $testPassesSelector->setActiveId($active_id);
8454  $testPassesSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8455 
8456  if ($this->hasNrOfTriesRestriction() && ($active_id > 0))
8457  {
8458  $closedPasses = $testPassesSelector->getClosedPasses();
8459 
8460  if( count($closedPasses) >= $this->getNrOfTries() )
8461  {
8462  $result["executable"] = false;
8463  $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8464  return $result;
8465  }
8466  }
8467  if($this->isPassWaitingEnabled() && $testPassesSelector->getLastFinishedPass() !== null)
8468  {
8469  $lastPass = $testPassesSelector->getLastFinishedPassTimestamp();
8470  if($lastPass && strlen($this->getPassWaiting()))
8471  {
8472  $pass_waiting_string = $this->getPassWaiting();
8473  $time_values = explode(":", $pass_waiting_string);
8474  $next_pass_allowed = strtotime('+ ' . $time_values[0] . ' Months + ' . $time_values[1] . ' Days + ' . $time_values[2] . ' Hours' . $time_values[3] . ' Minutes', $lastPass);
8475 
8476  if(time() < $next_pass_allowed)
8477  {
8478  $date = ilDatePresentation::formatDate(new ilDateTime($next_pass_allowed, IL_CAL_UNIX));
8479 
8480  $result["executable"] = false;
8481  $result["errormessage"] = sprintf($this->lng->txt('wait_for_next_pass_hint_msg'), $date);
8482  return $result;
8483  }
8484  }
8485  }
8486  return $result;
8487  }
8488 
8496  function canViewResults()
8497  {
8498  // this logic was implemented before, it got stabled only for now
8499  // this method is not as exact as it's required, it's to be replaced in the long time
8500 
8501  switch( $this->getScoreReporting() )
8502  {
8503  case self::SCORE_REPORTING_IMMIDIATLY:
8504  case self::SCORE_REPORTING_FINISHED: // this isn't excact enough
8505 
8506  return true;
8507 
8508  case self::SCORE_REPORTING_DATE:
8509 
8510  if (!$this->getReportingDate())
8511  {
8512  return false;
8513  }
8514 
8515  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
8516  {
8517  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8518  $now = time();
8519  if ($now < $epoch_time)
8520  {
8521  return false;
8522  }
8523  }
8524 
8525  return true;
8526  }
8527 
8528  return false;
8529  }
8530 
8531  function canShowTestResults($testSession)
8532  {
8533  $active_id = $testSession->getActiveId();
8534  if ($active_id > 0)
8535  {
8536  $starting_time = $this->getStartingTimeOfUser($active_id);
8537  }
8538  $notimeleft = FALSE;
8539  if ($starting_time !== FALSE)
8540  {
8541  if ($this->isMaxProcessingTimeReached($starting_time, $active_id))
8542  {
8543  $notimeleft = TRUE;
8544  }
8545  }
8546  $result = TRUE;
8547  if (!$this->isTestFinishedToViewResults($active_id, $testSession->getPass()) && ($this->getScoreReporting() == REPORT_AFTER_TEST))
8548  {
8549  $result = FALSE;
8550  }
8551  if (($this->endingTimeReached()) || $notimeleft) $result = TRUE;
8552  $result = $result & $this->canViewResults();
8553  return $result;
8554  }
8555 
8563  function getStartingTimeOfUser($active_id, $pass = null)
8564  {
8565  global $ilDB;
8566 
8567  if ($active_id < 1) return FALSE;
8568  if($pass === null)
8569  {
8570  $pass = ($this->getResetProcessingTime()) ? self::_getPass($active_id) : 0;
8571  }
8572  $result = $ilDB->queryF("SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
8573  array('integer', 'integer'),
8574  array($active_id, $pass)
8575  );
8576  if ($result->numRows())
8577  {
8578  $row = $ilDB->fetchAssoc($result);
8579  if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches))
8580  {
8581  return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8582  }
8583  else
8584  {
8585  return time();
8586  }
8587  }
8588  else
8589  {
8590  return time();
8591  }
8592  }
8593 
8603  {
8604  if ($this->getEnableProcessingTime())
8605  {
8606  $processing_time = $this->getProcessingTimeInSeconds($active_id);
8607  $now = time();
8608  if ($now > ($starting_time + $processing_time))
8609  {
8610  return TRUE;
8611  }
8612  else
8613  {
8614  return FALSE;
8615  }
8616  }
8617  else
8618  {
8619  return FALSE;
8620  }
8621  }
8622 
8623  function &getTestQuestions()
8624  {
8625  global $ilDB;
8626 
8627  $query = "
8628  SELECT questions.*,
8629  questtypes.type_tag,
8630  tstquest.sequence,
8631  tstquest.obligatory,
8632  origquest.obj_fi orig_obj_fi
8633 
8634  FROM qpl_questions questions
8635 
8636  INNER JOIN qpl_qst_type questtypes
8637  ON questtypes.question_type_id = questions.question_type_fi
8638 
8639  INNER JOIN tst_test_question tstquest
8640  ON tstquest.question_fi = questions.question_id
8641 
8642  LEFT JOIN qpl_questions origquest
8643  ON origquest.question_id = questions.original_id
8644 
8645  WHERE tstquest.test_fi = %s
8646 
8647  ORDER BY tstquest.sequence
8648  ";
8649 
8650  $query_result = $ilDB->queryF(
8651  $query, array('integer'), array($this->getTestId())
8652  );
8653 
8654  $questions = array();
8655 
8656  while ($row = $ilDB->fetchAssoc($query_result))
8657  {
8658  $question = $row;
8659 
8660  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8661 
8662  $questions[] = $question;
8663  }
8664 
8665  return $questions;
8666  }
8667 
8668  public function checkQuestionParent($questionId)
8669  {
8670  global $DIC; /* @var ILIAS\DI\Container $DIC */
8671 
8672  $row = $DIC->database()->fetchAssoc($DIC->database()->queryF(
8673  "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
8674  array('integer', 'integer'), array($questionId, $this->getId())
8675  ));
8676 
8677  return (bool)$row['cnt'];
8678  }
8679 
8683  public function getPotentialRandomTestQuestions()
8684  {
8688  global $ilDB;
8689 
8690  $query = "
8691  SELECT questions.*,
8692  questtypes.type_tag,
8693  origquest.obj_fi orig_obj_fi
8694 
8695  FROM qpl_questions questions
8696 
8697  INNER JOIN qpl_qst_type questtypes
8698  ON questtypes.question_type_id = questions.question_type_fi
8699 
8700  INNER JOIN tst_rnd_cpy tstquest
8701  ON tstquest.qst_fi = questions.question_id
8702 
8703  LEFT JOIN qpl_questions origquest
8704  ON origquest.question_id = questions.original_id
8705 
8706  WHERE tstquest.tst_fi = %s
8707  ";
8708 
8709  $query_result = $ilDB->queryF(
8710  $query, array('integer'), array($this->getTestId())
8711  );
8712 
8713  $questions = array();
8714 
8715  while ($row = $ilDB->fetchAssoc($query_result))
8716  {
8717  $question = $row;
8718 
8719  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8720 
8721  $questions[] = $question;
8722  }
8723 
8724  return $questions;
8725  }
8726 
8734  {
8735  return ($this->shuffle_questions) ? 1 : 0;
8736  }
8737 
8744  function setShuffleQuestions($a_shuffle)
8745  {
8746  $this->shuffle_questions = ($a_shuffle) ? 1 : 0;
8747  }
8748 
8762  {
8763  return ($this->show_summary) ? $this->show_summary : 0;
8764  }
8765 
8778  function setListOfQuestionsSettings($a_value = 0)
8779  {
8780  $this->show_summary = $a_value;
8781  }
8782 
8790  {
8791  if (($this->show_summary & 1) > 0)
8792  {
8793  return TRUE;
8794  }
8795  else
8796  {
8797  return FALSE;
8798  }
8799  }
8800 
8807  function setListOfQuestions($a_value = TRUE)
8808  {
8809  if ($a_value)
8810  {
8811  $this->show_summary = 1;
8812  }
8813  else
8814  {
8815  $this->show_summary = 0;
8816  }
8817  }
8818 
8826  {
8827  if (($this->show_summary & 2) > 0)
8828  {
8829  return TRUE;
8830  }
8831  else
8832  {
8833  return FALSE;
8834  }
8835  }
8836 
8843  function setListOfQuestionsStart($a_value = TRUE)
8844  {
8845  if ($a_value && $this->getListOfQuestions())
8846  {
8847  $this->show_summary = $this->show_summary | 2;
8848  }
8849  if (!$a_value && $this->getListOfQuestions())
8850  {
8851  if ($this->getListOfQuestionsStart())
8852  {
8853  $this->show_summary = $this->show_summary ^ 2;
8854  }
8855  }
8856  }
8857 
8865  {
8866  if (($this->show_summary & 4) > 0)
8867  {
8868  return TRUE;
8869  }
8870  else
8871  {
8872  return FALSE;
8873  }
8874  }
8875 
8882  function setListOfQuestionsEnd($a_value = TRUE)
8883  {
8884  if ($a_value && $this->getListOfQuestions())
8885  {
8886  $this->show_summary = $this->show_summary | 4;
8887  }
8888  if (!$a_value && $this->getListOfQuestions())
8889  {
8890  if ($this->getListOfQuestionsEnd())
8891  {
8892  $this->show_summary = $this->show_summary ^ 4;
8893  }
8894  }
8895  }
8896 
8904  {
8905  if (($this->show_summary & 8) > 0)
8906  {
8907  return TRUE;
8908  }
8909  else
8910  {
8911  return FALSE;
8912  }
8913  }
8914 
8921  function setListOfQuestionsDescription($a_value = TRUE)
8922  {
8923  if ($a_value && $this->getListOfQuestions())
8924  {
8925  $this->show_summary = $this->show_summary | 8;
8926  }
8927  if (!$a_value && $this->getListOfQuestions())
8928  {
8929  if ($this->getListOfQuestionsDescription())
8930  {
8931  $this->show_summary = $this->show_summary ^ 8;
8932  }
8933  }
8934  }
8935 
8943  {
8944  return ($this->results_presentation) ? $this->results_presentation : 0;
8945  }
8946 
8954  {
8955  if (($this->results_presentation & 1) > 0)
8956  {
8957  return TRUE;
8958  }
8959  else
8960  {
8961  return FALSE;
8962  }
8963  }
8964 
8972  {
8973  if (($this->results_presentation & 2) > 0)
8974  {
8975  return TRUE;
8976  }
8977  else
8978  {
8979  return FALSE;
8980  }
8981  }
8982 
8990  {
8991  if (($this->results_presentation & 4) > 0)
8992  {
8993  return TRUE;
8994  }
8995  else
8996  {
8997  return FALSE;
8998  }
8999  }
9000 
9008  {
9009  if (($this->results_presentation & 8) > 0)
9010  {
9011  return TRUE;
9012  }
9013  else
9014  {
9015  return FALSE;
9016  }
9017  }
9018 
9026  {
9027  if (($this->results_presentation & 16) > 0)
9028  {
9029  return TRUE;
9030  }
9031  else
9032  {
9033  return FALSE;
9034  }
9035  }
9036 
9044  {
9045  if (($this->results_presentation & 32) > 0)
9046  {
9047  return TRUE;
9048  }
9049  else
9050  {
9051  return FALSE;
9052  }
9053  }
9054 
9060  {
9061  if (($this->results_presentation & 64) > 0)
9062  {
9063  return TRUE;
9064  }
9065  else
9066  {
9067  return FALSE;
9068  }
9069  }
9070 
9076  {
9077  if(($this->results_presentation & 128) > 0)
9078  {
9079  return TRUE;
9080  }
9081  else
9082  {
9083  return FALSE;
9084  }
9085  }
9086 
9093  function setResultsPresentation($a_results_presentation = 3)
9094  {
9095  $this->results_presentation = $a_results_presentation;
9096  }
9097 
9106  function setShowPassDetails($a_details = 1)
9107  {
9108  if ($a_details)
9109  {
9110  $this->results_presentation = $this->results_presentation | 1;
9111  }
9112  else
9113  {
9114  if ($this->getShowPassDetails())
9115  {
9116  $this->results_presentation = $this->results_presentation ^ 1;
9117  }
9118  }
9119  }
9120 
9127  function setShowSolutionDetails($a_details = 1)
9128  {
9129  if ($a_details)
9130  {
9131  $this->results_presentation = $this->results_presentation | 2;
9132  }
9133  else
9134  {
9135  if ($this->getShowSolutionDetails())
9136  {
9137  $this->results_presentation = $this->results_presentation ^ 2;
9138  }
9139  }
9140  }
9141 
9148  function canShowSolutionPrintview($user_id = NULL)
9149  {
9150  return $this->getShowSolutionPrintview();
9151  }
9152 
9159  function setShowSolutionPrintview($a_printview = 1)
9160  {
9161  if ($a_printview)
9162  {
9163  $this->results_presentation = $this->results_presentation | 4;
9164  }
9165  else
9166  {
9167  if ($this->getShowSolutionPrintview())
9168  {
9169  $this->results_presentation = $this->results_presentation ^ 4;
9170  }
9171  }
9172  }
9173 
9180  function setShowSolutionFeedback($a_feedback = TRUE)
9181  {
9182  if ($a_feedback)
9183  {
9184  $this->results_presentation = $this->results_presentation | 8;
9185  }
9186  else
9187  {
9188  if ($this->getShowSolutionFeedback())
9189  {
9190  $this->results_presentation = $this->results_presentation ^ 8;
9191  }
9192  }
9193  }
9194 
9201  function setShowSolutionAnswersOnly($a_full = TRUE)
9202  {
9203  if ($a_full)
9204  {
9205  $this->results_presentation = $this->results_presentation | 16;
9206  }
9207  else
9208  {
9209  if ($this->getShowSolutionAnswersOnly())
9210  {
9211  $this->results_presentation = $this->results_presentation ^ 16;
9212  }
9213  }
9214  }
9215 
9222  function setShowSolutionSignature($a_signature = FALSE)
9223  {
9224  if ($a_signature)
9225  {
9226  $this->results_presentation = $this->results_presentation | 32;
9227  }
9228  else
9229  {
9230  if ($this->getShowSolutionSignature())
9231  {
9232  $this->results_presentation = $this->results_presentation ^ 32;
9233  }
9234  }
9235  }
9236 
9243  function setShowSolutionSuggested($a_solution = FALSE)
9244  {
9245  if ($a_solution)
9246  {
9247  $this->results_presentation = $this->results_presentation | 64;
9248  }
9249  else
9250  {
9251  if ($this->getShowSolutionSuggested())
9252  {
9253  $this->results_presentation = $this->results_presentation ^ 64;
9254  }
9255  }
9256  }
9257 
9263  public function setShowSolutionListComparison($a_comparison = FALSE)
9264  {
9265  if($a_comparison)
9266  {
9267  $this->results_presentation = $this->results_presentation | 128;
9268  }
9269  else
9270  {
9271  if($this->getShowSolutionListComparison())
9272  {
9273  $this->results_presentation = $this->results_presentation ^ 128;
9274  }
9275  }
9276  }
9277 
9281  public static function _getUserIdFromActiveId($active_id)
9282  {
9283  global $ilDB;
9284  $result = $ilDB->queryF("SELECT user_fi FROM tst_active WHERE active_id = %s",
9285  array('integer'),
9286  array($active_id)
9287  );
9288  if ($result->numRows())
9289  {
9290  $row = $ilDB->fetchAssoc($result);
9291  return $row["user_fi"];
9292  }
9293  else
9294  {
9295  return -1;
9296  }
9297  }
9298 
9302  public function isLimitUsersEnabled()
9303  {
9304  return $this->limitUsersEnabled;
9305  }
9306 
9311  {
9312  $this->limitUsersEnabled = $limitUsersEnabled;
9313  }
9314 
9315  public function getAllowedUsers()
9316  {
9317  return ($this->allowedUsers) ? $this->allowedUsers : 0;
9318  }
9319 
9320  public function setAllowedUsers($a_allowed_users)
9321  {
9322  $this->allowedUsers = $a_allowed_users;
9323  }
9324 
9325  public function getAllowedUsersTimeGap()
9326  {
9327  return ($this->allowedUsersTimeGap) ? $this->allowedUsersTimeGap : 0;
9328  }
9329 
9330  public function setAllowedUsersTimeGap($a_allowed_users_time_gap)
9331  {
9332  $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
9333  }
9334 
9336  {
9337  global $ilDB;
9338 
9339  $nr_of_users = $this->getAllowedUsers();
9340  $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
9341  if (($nr_of_users > 0) && ($time_gap > 0))
9342  {
9343  $now = time();
9344  $time_border = $now - $time_gap;
9345  $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
9346  $query = "
9347  SELECT DISTINCT tst_times.active_fi
9348  FROM tst_times
9349  INNER JOIN tst_active
9350  ON tst_times.active_fi = tst_active.active_id
9351  AND (
9352  tst_times.pass > tst_active.last_finished_pass OR tst_active.last_finished_pass IS NULL
9353  )
9354  WHERE tst_times.tstamp > %s
9355  AND tst_active.test_fi = %s
9356  ";
9357  $result = $ilDB->queryF($query, array('integer', 'integer'), array($time_border, $this->getTestId()));
9358  if ($result->numRows() >= $nr_of_users)
9359  {
9360  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
9362  {
9363  $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
9364  }
9365  return FALSE;
9366  }
9367  else
9368  {
9369  return TRUE;
9370  }
9371  }
9372  return TRUE;
9373  }
9374 
9375  function _getLastAccess($active_id)
9376  {
9377  global $ilDB;
9378 
9379  $result = $ilDB->queryF("SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
9380  array('integer'),
9381  array($active_id)
9382  );
9383  if ($result->numRows())
9384  {
9385  $row = $ilDB->fetchAssoc($result);
9386  return $row["finished"];
9387  }
9388  return "";
9389  }
9390 
9398  function isHTML($a_text)
9399  {
9400  if (preg_match("/<[^>]*?>/", $a_text))
9401  {
9402  return TRUE;
9403  }
9404  else
9405  {
9406  return FALSE;
9407  }
9408  }
9409 
9417  function QTIMaterialToString($a_material)
9418  {
9419  $result = "";
9420  for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
9421  {
9422  $material = $a_material->getMaterial($i);
9423  if (strcmp($material["type"], "mattext") == 0)
9424  {
9425  $result .= $material["material"]->getContent();
9426  }
9427  if (strcmp($material["type"], "matimage") == 0)
9428  {
9429  $matimage = $material["material"];
9430  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
9431  {
9432  // import an mediaobject which was inserted using tiny mce
9433  if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
9434  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
9435  }
9436  }
9437  }
9438  global $ilLog;
9439  $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
9440  return $result;
9441  }
9442 
9451  function addQTIMaterial(&$a_xml_writer, $a_material)
9452  {
9453  include_once "./Services/RTE/classes/class.ilRTE.php";
9454  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9455 
9456  $a_xml_writer->xmlStartTag("material");
9457  $attrs = array(
9458  "texttype" => "text/plain"
9459  );
9460  if ($this->isHTML($a_material))
9461  {
9462  $attrs["texttype"] = "text/xhtml";
9463  }
9464  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
9465 
9466  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9467  foreach ($mobs as $mob)
9468  {
9469  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9470  if (strpos($a_material, "mm_$mob") !== FALSE)
9471  {
9472  if (ilObjMediaObject::_exists($mob))
9473  {
9474  $mob_obj = new ilObjMediaObject($mob);
9475  $imgattrs = array(
9476  "label" => $moblabel,
9477  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9478  );
9479  }
9480  $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
9481  }
9482  }
9483  $a_xml_writer->xmlEndTag("material");
9484  }
9485 
9492  function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE, $omitNl2BrWhenTextArea = false)
9493  {
9494  include_once "./Services/Utilities/classes/class.ilUtil.php";
9495  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output, $omitNl2BrWhenTextArea);
9496  }
9497 
9504  function saveCertificateVisibility($a_value)
9505  {
9506  global $ilDB;
9507 
9508  $affectedRows = $ilDB->manipulateF("UPDATE tst_tests SET certificate_visibility = %s, tstamp = %s WHERE test_id = %s",
9509  array('text', 'integer', 'integer'),
9510  array($a_value, time(), $this->getTestId())
9511  );
9512  }
9513 
9521  {
9522  return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0;
9523  }
9524 
9531  function setCertificateVisibility($a_value)
9532  {
9533  $this->certificate_visibility = $a_value;
9534  }
9535 
9542  function getAnonymity()
9543  {
9544  return ($this->anonymity) ? 1 : 0;
9545  }
9546 
9553  function setAnonymity($a_value = 0)
9554  {
9555  switch ($a_value)
9556  {
9557  case 1:
9558  $this->anonymity = 1;
9559  break;
9560  default:
9561  $this->anonymity = 0;
9562  break;
9563  }
9564  }
9565 
9572  function getShowCancel()
9573  {
9574  return ($this->show_cancel) ? 1 : 0;
9575  }
9576 
9583  function setShowCancel($a_value = 1)
9584  {
9585  switch ($a_value)
9586  {
9587  case 1:
9588  $this->show_cancel = 1;
9589  break;
9590  default:
9591  $this->show_cancel = 0;
9592  break;
9593  }
9594  }
9595 
9602  function getShowMarker()
9603  {
9604  return ($this->show_marker) ? 1 : 0;
9605  }
9606 
9613  function setShowMarker($a_value = 1)
9614  {
9615  switch ($a_value)
9616  {
9617  case 1:
9618  $this->show_marker = 1;
9619  break;
9620  default:
9621  $this->show_marker = 0;
9622  break;
9623  }
9624  }
9625 
9633  {
9634  return ($this->fixed_participants) ? 1 : 0;
9635  }
9636 
9643  function setFixedParticipants($a_value = 1)
9644  {
9645  switch ($a_value)
9646  {
9647  case 1:
9648  $this->fixed_participants = 1;
9649  break;
9650  default:
9651  $this->fixed_participants = 0;
9652  break;
9653  }
9654  }
9655 
9663  public static function _lookupAnonymity($a_obj_id)
9664  {
9665  global $ilDB;
9666 
9667  $result = $ilDB->queryF("SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
9668  array('integer'),
9669  array($a_obj_id)
9670  );
9671  while($row = $ilDB->fetchAssoc($result))
9672  {
9673  return $row['anonymity'];
9674  }
9675  return 0;
9676  }
9677 
9684  public static function lookupQuestionSetTypeByActiveId($active_id)
9685  {
9686  global $ilDB;
9687 
9688  $query = "
9689  SELECT tst_tests.question_set_type
9690  FROM tst_active
9691  INNER JOIN tst_tests
9692  ON tst_active.test_fi = tst_tests.test_id
9693  WHERE tst_active.active_id = %s
9694  ";
9695 
9696  $res = $ilDB->queryF( $query, array('integer'), array($active_id) );
9697 
9698  while($row = $ilDB->fetchAssoc($res))
9699  {
9700  return $row['question_set_type'];
9701  }
9702 
9703  return null;
9704  }
9705 
9714  function _lookupRandomTestFromActiveId($active_id)
9715  {
9716  throw new Exception(__METHOD__.' is deprecated ... use ilObjTest::lookupQuestionSetTypeByActiveId() instead!');
9717 
9718  global $ilDB;
9719 
9720  $result = $ilDB->queryF("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",
9721  array('integer'),
9722  array($active_id)
9723  );
9724  while($row = $ilDB->fetchAssoc($result))
9725  {
9726  return $row['random_test'];
9727  }
9728  return 0;
9729  }
9730 
9741  function userLookupFullName($user_id, $overwrite_anonymity = FALSE, $sorted_order = FALSE, $suffix = "")
9742  {
9743  if ($this->getAnonymity() && !$overwrite_anonymity)
9744  {
9745  return $this->lng->txt("anonymous") . $suffix;
9746  }
9747  else
9748  {
9749  include_once './Services/User/classes/class.ilObjUser.php';
9750  $uname = ilObjUser::_lookupName($user_id);
9751  if (strlen($uname["firstname"].$uname["lastname"]) == 0) $uname["firstname"] = $this->lng->txt("deleted_user");
9752  if ($sorted_order)
9753  {
9754  return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9755  }
9756  else
9757  {
9758  return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9759  }
9760  }
9761  }
9762 
9770  function getStartTestLabel($active_id)
9771  {
9772  if ($this->getNrOfTries() == 1)
9773  {
9774  return $this->lng->txt("tst_start_test");
9775  }
9776  $active_pass = self::_getPass($active_id);
9777  $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9778  if ($res == 0)
9779  {
9780  if ($active_pass == 0)
9781  {
9782  return $this->lng->txt("tst_start_test");
9783  }
9784  else
9785  {
9786  return $this->lng->txt("tst_start_new_test_pass");
9787  }
9788  }
9789  else
9790  {
9791  return $this->lng->txt("tst_resume_test");
9792  }
9793  }
9794 
9800  public function getAvailableDefaults()
9801  {
9806  global $ilDB, $ilUser;
9807 
9808  $result = $ilDB->queryF(
9809  "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
9810  array('integer'),
9811  array($ilUser->getId())
9812  );
9813  $defaults = array();
9814  while($row = $ilDB->fetchAssoc($result))
9815  {
9816  $defaults[$row["test_defaults_id"]] = $row;
9817  }
9818  return $defaults;
9819  }
9820 
9828  function &getTestDefaults($test_defaults_id)
9829  {
9830  return self::_getTestDefaults($test_defaults_id);
9831  }
9832 
9833  public static function _getTestDefaults($test_defaults_id)
9834  {
9835  global $ilDB;
9836 
9837  $result = $ilDB->queryF("SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9838  array('integer'),
9839  array($test_defaults_id)
9840  );
9841  if ($result->numRows() == 1)
9842  {
9843  $row = $ilDB->fetchAssoc($result);
9844  return $row;
9845  }
9846  else
9847  {
9848  return NULL;
9849  }
9850  }
9851 
9858  function deleteDefaults($test_default_id)
9859  {
9860  global $ilDB;
9861  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9862  array('integer'),
9863  array($test_default_id)
9864  );
9865  }
9866 
9873  function addDefaults($a_name)
9874  {
9875  global $ilDB;
9876  global $ilUser;
9877  $testsettings = array(
9878  "TitleOutput" => $this->getTitleOutput(),
9879  "PassScoring" => $this->getPassScoring(),
9880  "IntroEnabled" => $this->isIntroductionEnabled(),
9881  "Introduction" => $this->getIntroduction(),
9882  "FinalStatement" => $this->getFinalStatement(),
9883  "ShowInfo" => $this->getShowInfo(),
9884  "ForceJS" => $this->getForceJS(),
9885  "CustomStyle" => $this->getCustomStyle(),
9886  "ShowFinalStatement" => $this->getShowFinalStatement(),
9887  "SequenceSettings" => $this->getSequenceSettings(),
9888  "ScoreReporting" => $this->getScoreReporting(),
9889  "ScoreCutting" => $this->getScoreCutting(),
9890  'SpecificAnswerFeedback' => $this->getSpecificAnswerFeedback(),
9891  'PrintBsWithRes' => (int)$this->isBestSolutionPrintedWithResult(),
9892  "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9893  "AnswerFeedback" => $this->getAnswerFeedback(),
9894  "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9895  "ResultsPresentation" => $this->getResultsPresentation(),
9896  "Anonymity" => $this->getAnonymity(),
9897  "ShowCancel" => $this->getShowCancel(),
9898  "ShowMarker" => $this->getShowMarker(),
9899  "ReportingDate" => $this->getReportingDate(),
9900  "NrOfTries" => $this->getNrOfTries(),
9901  "Shuffle" => $this->getShuffleQuestions(),
9902  "Kiosk" => $this->getKiosk(),
9903  "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9904  "ProcessingTime" => $this->getProcessingTime(),
9905  "EnableProcessingTime" => $this->getEnableProcessingTime(),
9906  "ResetProcessingTime" => $this->getResetProcessingTime(),
9907  "StartingTimeEnabled" => $this->isStartingTimeEnabled(),
9908  "StartingTime" => $this->getStartingTime(),
9909  "EndingTimeEnabled" => $this->isEndingTimeEnabled(),
9910  "EndingTime" => $this->getEndingTime(),
9911  "ECTSOutput" => $this->getECTSOutput(),
9912  "ECTSFX" => $this->getECTSFX(),
9913  "ECTSGrades" => $this->getECTSGrades(),
9914  "questionSetType" => $this->getQuestionSetType(),
9915  "CountSystem" => $this->getCountSystem(),
9916  "MCScoring" => $this->getMCScoring(),
9917  "mailnotification" => $this->getMailNotification(),
9918  "mailnottype" => $this->getMailNotificationType(),
9919  "exportsettings" => $this->getExportSettings(),
9920  "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings(),
9921  'obligations_enabled' => (int)$this->areObligationsEnabled(),
9922  'offer_question_hints' => (int)$this->isOfferingQuestionHintsEnabled(),
9923  'pass_deletion_allowed' => (int)$this->isPassDeletionAllowed(),
9924  'enable_examview' => $this->getEnableExamview(),
9925  'show_examview_html' => $this->getShowExamviewHtml(),
9926  'show_examview_pdf' => $this->getShowExamviewPdf(),
9927  'char_selector_availability' => $this->getCharSelectorAvailability(),
9928  'char_selector_definition' => $this->getCharSelectorDefinition(),
9929  'skill_service' => (int)$this->isSkillServiceEnabled(),
9930  'result_tax_filters' => (array)$this->getResultFilterTaxIds(),
9931  'show_grading_status' => (int)$this->isShowGradingStatusEnabled(),
9932  'show_grading_mark' => (int)$this->isShowGradingMarkEnabled(),
9933 
9934  'inst_fb_answer_fixation' => $this->isInstantFeedbackAnswerFixationEnabled(),
9935  'force_inst_fb' => $this->isForceInstantFeedbackEnabled(),
9936  'redirection_mode' => $this->getRedirectionMode(),
9937  'redirection_url' => $this->getRedirectionUrl(),
9938  'sign_submission' => $this->getSignSubmission(),
9939  'autosave' => (int)$this->getAutosave(),
9940  'autosave_ival' => (int)$this->getAutosaveIval(),
9941  'examid_in_test_pass' => (int)$this->isShowExamIdInTestPassEnabled(),
9942  'examid_in_test_res' => (int)$this->isShowExamIdInTestResultsEnabled(),
9943 
9944  'enable_archiving' => (int)$this->getEnableArchiving(),
9945  'password_enabled' => (int)$this->isPasswordEnabled(),
9946  'password' => (string)$this->getPassword(),
9947  'fixed_participants' => $this->getFixedParticipants(),
9948  'limit_users_enabled' => $this->isLimitUsersEnabled(),
9949  'allowedusers' => $this->getAllowedUsers(),
9950  'alloweduserstimegap' => $this->getAllowedUsersTimeGap(),
9951  'pool_usage' => $this->getPoolUsage(),
9952  'activation_limited' => $this->isActivationLimited(),
9953  'activation_start_time' => $this->getActivationStartingTime(),
9954  'activation_end_time' => $this->getActivationEndingTime(),
9955  'activation_visibility' => $this->getActivationVisibility(),
9956  'highscore_enabled' => $this->getHighscoreEnabled(),
9957  'highscore_anon' => $this->getHighscoreAnon(),
9958  'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
9959  'highscore_score' => $this->getHighscoreScore(),
9960  'highscore_percentage' => $this->getHighscorePercentage(),
9961  'highscore_hints' => $this->getHighscoreHints(),
9962  'highscore_wtime' => $this->getHighscoreWTime(),
9963  'highscore_own_table' => $this->getHighscoreOwnTable(),
9964  'highscore_top_table' => $this->getHighscoreTopTable(),
9965  'highscore_top_num' => $this->getHighscoreTopNum(),
9966  'use_previous_answers' => (string)$this->getUsePreviousAnswers(),
9967  'pass_waiting' => $this->getPassWaiting()
9968  );
9969 
9970  $next_id = $ilDB->nextId('tst_test_defaults');
9971  $ilDB->insert(
9972  'tst_test_defaults',
9973  array(
9974  'test_defaults_id' => array('integer', $next_id),
9975  'name' => array('text', $a_name),
9976  'user_fi' => array('integer', $ilUser->getId()),
9977  'defaults' => array('clob', serialize($testsettings)),
9978  'marks' => array('clob', serialize($this->mark_schema)),
9979  'tstamp' => array('integer', time())
9980  )
9981  );
9982  }
9983 
9991  public function applyDefaults($test_defaults)
9992  {
9993  $testsettings = unserialize($test_defaults["defaults"]);
9994  include_once "./Modules/Test/classes/class.assMarkSchema.php";
9995  $this->mark_schema = unserialize($test_defaults["marks"]);
9996 
9997  $this->setTitleOutput($testsettings["TitleOutput"]);
9998  $this->setPassScoring($testsettings["PassScoring"]);
9999  $this->setIntroductionEnabled($testsettings["IntroEnabled"]);
10000  $this->setIntroduction($testsettings["Introduction"]);
10001  $this->setFinalStatement($testsettings["FinalStatement"]);
10002  $this->setShowInfo($testsettings["ShowInfo"]);
10003  $this->setForceJS($testsettings["ForceJS"]);
10004  $this->setCustomStyle($testsettings["CustomStyle"]);
10005  $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
10006  $this->setSequenceSettings($testsettings["SequenceSettings"]);
10007  $this->setScoreReporting($testsettings["ScoreReporting"]);
10008  $this->setScoreCutting($testsettings['ScoreCutting']);
10009  $this->setSpecificAnswerFeedback($testsettings['SpecificAnswerFeedback']);
10010  $this->setPrintBestSolutionWithResult((bool)$testsettings['PrintBsWithRes']);
10011  $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
10012  $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
10013  $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
10014  $this->setResultsPresentation($testsettings["ResultsPresentation"]);
10015  $this->setAnonymity($testsettings["Anonymity"]);
10016  $this->setShowCancel($testsettings["ShowCancel"]);
10017  $this->setShuffleQuestions($testsettings["Shuffle"]);
10018  $this->setShowMarker($testsettings["ShowMarker"]);
10019  $this->setReportingDate($testsettings["ReportingDate"]);
10020  $this->setNrOfTries($testsettings["NrOfTries"]);
10021  $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
10022  $this->setRedirectionMode($testsettings['redirection_mode']);
10023  $this->setRedirectionUrl($testsettings['redirection_url']);
10024  $this->setProcessingTime($testsettings["ProcessingTime"]);
10025  $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
10026  $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
10027  $this->setStartingTimeEnabled($testsettings["StartingTimeEnabled"]);
10028  $this->setStartingTime($testsettings["StartingTime"]);
10029  $this->setKiosk($testsettings["Kiosk"]);
10030  $this->setEndingTimeEnabled($testsettings["EndingTimeEnabled"]);
10031  $this->setEndingTime($testsettings["EndingTime"]);
10032  $this->setECTSOutput($testsettings["ECTSOutput"]);
10033  $this->setECTSFX($testsettings["ECTSFX"]);
10034  $this->setECTSGrades($testsettings["ECTSGrades"]);
10035  if( isset($testsettings["isRandomTest"]) )
10036  {
10037  if( $testsettings["isRandomTest"] )
10038  {
10039  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
10040  }
10041  else
10042  {
10043  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
10044  }
10045  }
10046  elseif( isset($testsettings["questionSetType"]) )
10047  {
10048  $this->setQuestionSetType($testsettings["questionSetType"]);
10049  }
10050  $this->setCountSystem($testsettings["CountSystem"]);
10051  $this->setMCScoring($testsettings["MCScoring"]);
10052  $this->setMailNotification($testsettings["mailnotification"]);
10053  $this->setMailNotificationType($testsettings["mailnottype"]);
10054  $this->setExportSettings($testsettings['exportsettings']);
10055  $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
10056  $this->setObligationsEnabled($testsettings["obligations_enabled"]);
10057  $this->setOfferingQuestionHintsEnabled($testsettings["offer_question_hints"]);
10058  $this->setHighscoreEnabled($testsettings['highscore_enabled']);
10059  $this->setHighscoreAnon($testsettings['highscore_anon']);
10060  $this->setHighscoreAchievedTS($testsettings['highscore_achieved_ts']);
10061  $this->setHighscoreScore($testsettings['highscore_score']);
10062  $this->setHighscorePercentage($testsettings['highscore_percentage']);
10063  $this->setHighscoreHints($testsettings['highscore_hints']);
10064  $this->setHighscoreWTime($testsettings['highscore_wtime']);
10065  $this->setHighscoreOwnTable($testsettings['highscore_own_table']);
10066  $this->setHighscoreTopTable($testsettings['highscore_top_table']);
10067  $this->setHighscoreTopNum($testsettings['highscore_top_num']);
10068  $this->setPassDeletionAllowed($testsettings['pass_deletion_allowed']);
10069  if( isset($testsettings['examid_in_kiosk']) )
10070  {
10071  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_kiosk']);
10072  }
10073  else
10074  {
10075  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_test_pass']);
10076  }
10077  if( isset($testsettings['show_exam_id']) )
10078  {
10079  $this->setShowExamIdInTestResultsEnabled($testsettings['show_exam_id']);
10080  }
10081  else
10082  {
10083  $this->setShowExamIdInTestResultsEnabled($testsettings['examid_in_test_res']);
10084  }
10085  $this->setEnableExamview($testsettings['enable_examview']);
10086  $this->setShowExamviewHtml($testsettings['show_examview_html']);
10087  $this->setShowExamviewPdf($testsettings['show_examview_pdf']);
10088  $this->setEnableArchiving($testsettings['enable_archiving']);
10089  $this->setSignSubmission($testsettings['sign_submission']);
10090  $this->setCharSelectorAvailability($testsettings['char_selector_availability']);
10091  $this->setCharSelectorDefinition($testsettings['char_selector_definition']);
10092  $this->setSkillServiceEnabled((bool)$testsettings['skill_service']);
10093  $this->setResultFilterTaxIds((array)$testsettings['result_tax_filters']);
10094  $this->setShowGradingStatusEnabled((bool)$testsettings['show_grading_status']);
10095  $this->setShowGradingMarkEnabled((bool)$testsettings['show_grading_mark']);
10096 
10097  $this->setInstantFeedbackAnswerFixationEnabled($testsettings['inst_fb_answer_fixation']);
10098  $this->setForceInstantFeedbackEnabled($testsettings['force_inst_fb']);
10099  $this->setRedirectionMode($testsettings['redirection_mode']);
10100  $this->setRedirectionUrl($testsettings['redirection_url']);
10101 
10102  $this->setAutosave($testsettings['autosave']);
10103  $this->setAutosaveIval($testsettings['autosave_ival']);
10104  $this->setShowExamIdInTestResultsEnabled((int)$testsettings['examid_in_test_res']);
10105  $this->setPasswordEnabled($testsettings['password_enabled']);
10106  $this->setPassword($testsettings['password']);
10107  $this->setFixedParticipants($testsettings['fixed_participants'] );
10108  $this->setLimitUsersEnabled($testsettings['limit_users_enabled']);
10109  $this->setAllowedUsers($testsettings['allowedusers']);
10110  $this->setAllowedUsersTimeGap($testsettings['alloweduserstimegap']);
10111  $this->setUsePreviousAnswers($testsettings['use_previous_answers']);
10112  $this->setPoolUsage($testsettings['pool_usage']);
10113  $this->setActivationLimited($testsettings['activation_limited']);
10114  $this->setActivationStartingTime($testsettings['activation_start_time']);
10115  $this->setActivationEndingTime($testsettings['activation_end_time']);
10116  $this->setActivationVisibility($testsettings['activation_visibility']);
10117  $this->setPassWaiting($testsettings['pass_waiting']);
10118 
10119  $this->saveToDb();
10120 
10121  return true;
10122  }
10123 
10131  function processPrintoutput2FO($print_output)
10132  {
10133  if (extension_loaded("tidy"))
10134  {
10135  $config = array(
10136  "indent" => false,
10137  "output-xml" => true,
10138  "numeric-entities" => true
10139  );
10140  $tidy = new tidy();
10141  $tidy->parseString($print_output, $config, 'utf8');
10142  $tidy->cleanRepair();
10143  $print_output = tidy_get_output($tidy);
10144  $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
10145  }
10146  else
10147  {
10148  $print_output = str_replace("&nbsp;", "&#160;", $print_output);
10149  $print_output = str_replace("&otimes;", "X", $print_output);
10150  }
10151  $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
10152 
10153  // additional font support
10154  $xsl = str_replace(
10155  'font-family="Helvetica, unifont"',
10156  'font-family="'.$GLOBALS['ilSetting']->get('rpc_pdf_font','Helvetica, unifont').'"',
10157  $xsl
10158  );
10159 
10160  $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
10161  $xh = xslt_create();
10162  $params = array();
10163  $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", NULL, $args, $params);
10164  xslt_error($xh);
10165  xslt_free($xh);
10166  return $output;
10167  }
10168 
10175  public function deliverPDFfromHTML($content, $title = NULL)
10176  {
10177  $content = preg_replace("/href=\".*?\"/", "", $content);
10178  $printbody = new ilTemplate("tpl.il_as_tst_print_body.html", TRUE, TRUE, "Modules/Test");
10179  $printbody->setVariable("TITLE", ilUtil::prepareFormOutput($this->getTitle()));
10180  $printbody->setVariable("ADM_CONTENT", $content);
10181  $printbody->setCurrentBlock("css_file");
10182  $printbody->setVariable("CSS_FILE", $this->getTestStyleLocation("filesystem"));
10183  $printbody->parseCurrentBlock();
10184  $printbody->setCurrentBlock("css_file");
10185  $printbody->setVariable("CSS_FILE", ilUtil::getStyleSheetLocation("filesystem", "delos.css"));
10186  $printbody->parseCurrentBlock();
10187  $printoutput = $printbody->get();
10188  $html = str_replace("href=\"./", "href=\"" . ILIAS_HTTP_PATH . "/", $printoutput);
10189  $html = preg_replace("/<div id=\"dontprint\">.*?<\\/div>/ims", "", $html);
10190  if (extension_loaded("tidy"))
10191  {
10192  $config = array(
10193  "indent" => false,
10194  "output-xml" => true,
10195  "numeric-entities" => true
10196  );
10197  $tidy = new tidy();
10198  $tidy->parseString($html, $config, 'utf8');
10199  $tidy->cleanRepair();
10200  $html = tidy_get_output($tidy);
10201  $html = preg_replace("/^.*?(<html)/", "\\1", $html);
10202  }
10203  else
10204  {
10205  $html = str_replace("&nbsp;", "&#160;", $html);
10206  $html = str_replace("&otimes;", "X", $html);
10207  }
10208  $html = preg_replace("/src=\".\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
10210  }
10211 
10218  public function deliverPDFfromFO($fo, $title = null)
10219  {
10220  global $ilLog;
10221 
10222  include_once "./Services/Utilities/classes/class.ilUtil.php";
10223  $fo_file = ilUtil::ilTempnam() . ".fo";
10224  $fp = fopen($fo_file, "w"); fwrite($fp, $fo); fclose($fp);
10225 
10226  include_once './Services/WebServices/RPC/classes/class.ilRpcClientFactory.php';
10227  try
10228  {
10229  $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo);
10230  $filename = (strlen($title)) ? $title : $this->getTitle();
10231  ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
10232  return true;
10233  }
10234  catch(Exception $e)
10235  {
10236  $ilLog->write(__METHOD__.': '.$e->getMessage());
10237  return false;
10238  }
10239  }
10240 
10250  static function getManualFeedback($active_id, $question_id, $pass)
10251  {
10252  global $ilDB;
10253  $feedback = "";
10254  $result = $ilDB->queryF("SELECT feedback FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10255  array('integer', 'integer', 'integer'),
10256  array($active_id, $question_id, $pass)
10257  );
10258  if ($result->numRows())
10259  {
10260  $row = $ilDB->fetchAssoc($result);
10261  include_once("./Services/RTE/classes/class.ilRTE.php");
10262  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
10263  }
10264  return $feedback;
10265  }
10266 
10277  function saveManualFeedback($active_id, $question_id, $pass, $feedback)
10278  {
10279  global $ilDB;
10280 
10281  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10282  array('integer', 'integer', 'integer'),
10283  array($active_id, $question_id, $pass)
10284  );
10285 
10286  if (strlen($feedback))
10287  {
10288  $next_id = $ilDB->nextId('tst_manual_fb');
10290  $result = $ilDB->insert('tst_manual_fb', array(
10291  'manual_feedback_id' => array( 'integer', $next_id ),
10292  'active_fi' => array( 'integer', $active_id ),
10293  'question_fi' => array( 'integer', $question_id ),
10294  'pass' => array( 'integer', $pass),
10295  'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( $feedback, 0) ),
10296  'tstamp' => array( 'integer', time() ),
10297  )
10298  );
10299  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
10301  {
10302  global $lng, $ilUser;
10303  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
10304  $username = ilObjTestAccess::_getParticipantData($active_id);
10305  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10306  $this->logAction(sprintf($lng->txtlng("assessment", "log_manual_feedback", ilObjAssessmentFolder::_getLogLanguage()), $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")", $username, assQuestion::_getQuestionTitle($question_id), $feedback));
10307  }
10308  }
10309  return TRUE;
10310  }
10311 
10320  {
10321  return TRUE;
10322 
10323 // global $ilUser;
10324 // if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
10325 // if ($this->getForceJS()) return TRUE;
10326 // $assessmentSetting = new ilSetting("assessment");
10327 // return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
10328  }
10329 
10330  function &createTestSequence($active_id, $pass, $shuffle)
10331  {
10332  include_once "./Modules/Test/classes/class.ilTestSequence.php";
10333  $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10334  }
10335 
10341  public function setTestId($a_id)
10342  {
10343  $this->test_id = $a_id;
10344  }
10345 
10354  function getDetailedTestResults($participants)
10355  {
10356  $results = array();
10357  if (count($participants))
10358  {
10359  foreach ($participants as $active_id => $user_rec)
10360  {
10361  $row = array();
10362  $reached_points = 0;
10363  $max_points = 0;
10364  foreach ($this->questions as $value)
10365  {
10366  $question =& ilObjTest::_instanciateQuestion($value);
10367  if (is_object($question))
10368  {
10369  $max_points += $question->getMaximumPoints();
10370  $reached_points += $question->getReachedPoints($active_id);
10371  if ($max_points > 0)
10372  {
10373  $percentvalue = $reached_points / $max_points;
10374  if ($percentvalue < 0) $percentvalue = 0.0;
10375  }
10376  else
10377  {
10378  $percentvalue = 0;
10379  }
10380  if ($this->getAnonymity())
10381  {
10382  $user_rec['firstname'] = "";
10383  $user_rec['lastname'] = $this->lng->txt("anonymous");
10384  }
10385  $row = array(
10386  "user_id"=>$user_rec['usr_id'],
10387  "matriculation" => $user_rec['matriculation'],
10388  "lastname" => $user_rec['lastname'],
10389  "firstname" => $user_rec['firstname'],
10390  "login"=>$user_rec['login'],
10391  "question_id" => $question->getId(),
10392  "question_title" => $question->getTitle(),
10393  "reached_points" => $reached_points,
10394  "max_points" => $max_points
10395  );
10396  $results[] = $row;
10397  }
10398  }
10399  }
10400  }
10401  return $results;
10402  }
10403 
10407  public static function _lookupTestObjIdForQuestionId($a_q_id)
10408  {
10409  global $ilDB;
10410 
10411  $result = $ilDB->queryF("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",
10412  array('integer'),
10413  array($a_q_id)
10414  );
10415  $rec = $ilDB->fetchAssoc($result);
10416  return $rec["obj_id"];
10417  }
10418 
10425  function isPluginActive($a_pname)
10426  {
10427  global $ilPluginAdmin;
10428  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
10429  {
10430  return TRUE;
10431  }
10432  else
10433  {
10434  return FALSE;
10435  }
10436  }
10437 
10438  public function getPassed($active_id)
10439  {
10440  global $ilDB;
10441 
10442  $result = $ilDB->queryF("SELECT passed FROM tst_result_cache WHERE active_fi = %s",
10443  array('integer'),
10444  array($active_id)
10445  );
10446  if ($result->numRows())
10447  {
10448  $row = $ilDB->fetchAssoc($result);
10449  return $row['passed'];
10450  }
10451  else
10452  {
10453  $counted_pass = ilObjTest::_getResultPass($active_id);
10454  $result_array =& $this->getTestResult($active_id, $counted_pass);
10455  return $result_array["test"]["passed"];
10456  }
10457  }
10458 
10464  function canShowCertificate($testSession, $user_id, $active_id)
10465  {
10466  if ($this->canShowTestResults($testSession))
10467  {
10468  include_once "./Services/Certificate/classes/class.ilCertificate.php";
10469  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
10470  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
10471  if ($cert->isComplete())
10472  {
10473  $vis = $this->getCertificateVisibility();
10474  $showcert = FALSE;
10475  switch ($vis)
10476  {
10477  case 0:
10478  $showcert = TRUE;
10479  break;
10480  case 1:
10481  if ($this->getPassed($active_id))
10482  {
10483  $showcert = TRUE;
10484  }
10485  break;
10486  case 2:
10487  $showcert = FALSE;
10488  break;
10489  }
10490  if ($showcert)
10491  {
10492  return TRUE;
10493  }
10494  else
10495  {
10496  return FALSE;
10497  }
10498  }
10499  else
10500  {
10501  return FALSE;
10502  }
10503  }
10504  else
10505  {
10506  return FALSE;
10507  }
10508  }
10509 
10513  public function getParticipantsForTestAndQuestion($test_id, $question_id)
10514  {
10516  global $ilDB;
10517 
10518  $query = "
10519  SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
10520  FROM tst_test_result
10521  INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s
10522  INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi
10523  LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi
10524  WHERE tst_test_result.question_fi = %s
10525  ORDER BY usr_data.lastname ASC, usr_data.firstname ASC
10526  ";
10527 
10528  $result = $ilDB->queryF($query,
10529  array('integer', 'integer'),
10530  array($test_id, $question_id)
10531  );
10532  $foundusers = array();
10534  while ($row = $ilDB->fetchAssoc($result))
10535  {
10536  if (!array_key_exists($row["active_fi"], $foundusers))
10537  {
10538  $foundusers[$row["active_fi"]] = array();
10539  }
10540  array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10541  }
10542  return $foundusers;
10543  }
10544 
10550  public function getAggregatedResultsData()
10551  {
10552  $data =& $this->getCompleteEvaluationData();
10553  $foundParticipants =& $data->getParticipants();
10554  $results = array("overview" => array(), "questions" => array());
10555  if (count($foundParticipants))
10556  {
10557  $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10558  $total_finished = $this->evalTotalFinished();
10559  $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10560  $average_time = $this->evalTotalStartedAverageTime();
10561  $diff_seconds = $average_time;
10562  $diff_hours = floor($diff_seconds/3600);
10563  $diff_seconds -= $diff_hours * 3600;
10564  $diff_minutes = floor($diff_seconds/60);
10565  $diff_seconds -= $diff_minutes * 60;
10566  $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10567  $total_passed = 0;
10568  $total_passed_reached = 0;
10569  $total_passed_max = 0;
10570  $total_passed_time = 0;
10571  foreach ($foundParticipants as $userdata)
10572  {
10573  if ($userdata->getPassed())
10574  {
10575  $total_passed++;
10576  $total_passed_reached += $userdata->getReached();
10577  $total_passed_max += $userdata->getMaxpoints();
10578  $total_passed_time += $userdata->getTimeOfWork();
10579  }
10580  }
10581  $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10582  $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10583  $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10584  $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10585  $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);
10586  $average_time = $average_passed_time;
10587  $diff_seconds = $average_time;
10588  $diff_hours = floor($diff_seconds/3600);
10589  $diff_seconds -= $diff_hours * 3600;
10590  $diff_minutes = floor($diff_seconds/60);
10591  $diff_seconds -= $diff_minutes * 60;
10592  $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10593  }
10594 
10595  foreach ($data->getQuestionTitles() as $question_id => $question_title)
10596  {
10597  $answered = 0;
10598  $reached = 0;
10599  $max = 0;
10600  foreach ($foundParticipants as $userdata)
10601  {
10602  for ($i = 0; $i <= $userdata->getLastPass(); $i++)
10603  {
10604  if (is_object($userdata->getPass($i)))
10605  {
10606  $question =& $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10607  if (is_array($question))
10608  {
10609  $answered++;
10610  $reached += $question["reached"];
10611  $max += $question["points"];
10612  }
10613  }
10614  }
10615  }
10616  $percent = $max ? $reached/$max * 100.0 : 0;
10617  $counter++;
10618  $results["questions"][$question_id] = array(
10619  $question_title,
10620  sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10621  sprintf("%.2f", $percent) . "%",
10622  $answered,
10623  sprintf("%.2f", $answered ? $reached / $answered : 0),
10624  sprintf("%.2f", $answered ? $max / $answered : 0),
10625  $percent / 100.0
10626  );
10627  }
10628  return $results;
10629  }
10630 
10634  function getXMLZip()
10635  {
10636  require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10637  $expFactory = new ilTestExportFactory($this);
10638  $test_exp = $expFactory->getExporter('xml');
10639  return $test_exp->buildExportFile();
10640  }
10641 
10645  public function getMailNotification()
10646  {
10647  return $this->mailnotification;
10648  }
10649 
10655  public function setMailNotification($a_notification)
10656  {
10657  $this->mailnotification = $a_notification;
10658  }
10659 
10660  public function sendSimpleNotification($active_id)
10661  {
10662  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10663 
10664  $mail = new ilTestMailNotification();
10665  $owner_id = $this->getOwner();
10666  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10667  $mail->sendSimpleNotification($owner_id, $this->getTitle(), $usr_data);
10668  }
10669 
10676  {
10677  include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
10678  include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
10679  $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI(''), 'outEvaluation', $this->getAnonymity());
10680  return $table_gui->getSelectedColumns();
10681  }
10682 
10683  public function sendAdvancedNotification($active_id)
10684  {
10685  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10686 
10687  $mail = new ilTestMailNotification();
10688  $owner_id = $this->getOwner();
10689  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10690 
10691  require_once 'Modules/Test/classes/class.ilTestExportFactory.php';
10692  $expFactory = new ilTestExportFactory($this);
10693  $exportObj = $expFactory->getExporter('results');
10694  $file = $exportObj->exportToExcel($deliver = FALSE, 'active_id', $active_id, $passedonly = FALSE);
10695  include_once "./Services/Mail/classes/class.ilFileDataMail.php";
10696  $fd = new ilFileDataMail(ANONYMOUS_USER_ID);
10697  $fd->copyAttachmentFile($file, "result_" . $active_id . ".xls");
10698  $file_names[] = "result_" . $active_id . ".xls";
10699 
10700  $mail->sendAdvancedNotification($owner_id, $this->getTitle(), $usr_data, $file_names);
10701 
10702  if(count($file_names))
10703  {
10704  $fd->unlinkFiles($file_names);
10705  unset($fd);
10706  @unlink($file);
10707  }
10708  }
10709 
10710  function createRandomSolutions($number)
10711  {
10712  global $ilDB;
10713 
10714  // 1. get a user
10715  $query = "SELECT usr_id FROM usr_data";
10716  $result = $ilDB->query($query);
10717  while ($data = $ilDB->fetchAssoc($result))
10718  {
10719  $activequery = sprintf("SELECT user_fi FROM tst_active WHERE test_fi = %s AND user_fi = %s",
10720  $ilDB->quote($this->getTestId()),
10721  $ilDB->quote($data['usr_id'])
10722  );
10723  $activeresult = $ilDB->query($activequery);
10724  if ($activeresult->numRows() == 0)
10725  {
10726  $user_id = $data['usr_id'];
10727  if ($user_id != 13)
10728  {
10729  include_once "./Modules/Test/classes/class.ilTestSession.php";
10730  $testSession = new ilTestSession();
10731  $testSession->setRefId($this->getRefId());
10732  $testSession->setTestId($this->getTestId());
10733  $testSession->setUserId($user_id);
10734  $testSession->saveToDb();
10735  $passes = ($this->getNrOfTries()) ? $this->getNrOfTries() : 10;
10736  $nr_of_passes = rand(1, $passes);
10737  $active_id = $testSession->getActiveId();
10738  for ($pass = 0; $pass < $nr_of_passes; $pass++)
10739  {
10740  include_once "./Modules/Test/classes/class.ilTestSequence.php";
10741  $testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10742  $testSequence->loadFromDb();
10743  $testSequence->loadQuestions();
10744  if (!$testSequence->hasSequence())
10745  {
10746  $testSequence->createNewSequence($this->getQuestionCount(), $shuffle);
10747  $testSequence->saveToDb();
10748  }
10749  for ($seq = 1; $seq <= count($this->questions); $seq++)
10750  {
10751  $question_id = $testSequence->getQuestionForSequence($seq);
10752  $objQuestion = ilObjTest::_instanciateQuestion($question_id);
10753  $assSettings = new ilSetting('assessment');
10754  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
10755  $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
10756  $processLockerFactory->setQuestionId($objQuestion->getId());
10757  $processLockerFactory->setUserId($testSession->getUserId());
10758  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
10759  $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
10760  $objQuestion->setProcessLocker($processLockerFactory->getLocker());
10761  $objQuestion->createRandomSolution($testSession->getActiveId(), $pass);
10762  }
10763  $testSession->increasePass();
10764  $testSession->setLastSequence(0);
10765  $testSession->setLastFinishedPass($pass);
10766  $testSession->setSubmitted(1);
10767  $testSession->setSubmittedTimestamp(date('Y-m-d H:i:s'));
10768  $testSession->saveToDb();
10769  }
10770  $number--;
10771  if ($number == 0) return;
10772  }
10773  }
10774  }
10775  }
10776 
10777  public function getResultsForActiveId($active_id)
10778  {
10779  global $ilDB;
10780 
10781  $query = "
10782  SELECT *
10783  FROM tst_result_cache
10784  WHERE active_fi = %s
10785  ";
10786 
10787  $result = $ilDB->queryF(
10788  $query, array('integer'), array($active_id)
10789  );
10790 
10791  if( !$result->numRows() )
10792  {
10793  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10794 
10796 
10797  $query = "
10798  SELECT *
10799  FROM tst_result_cache
10800  WHERE active_fi = %s
10801  ";
10802 
10803  $result = $ilDB->queryF(
10804  $query, array('integer'), array($active_id)
10805  );
10806  }
10807 
10808  $row = $ilDB->fetchAssoc($result);
10809 
10810  return $row;
10811 
10812  }
10813 
10814  public function getMailNotificationType()
10815  {
10816  if ($this->mailnottype == 1)
10817  {
10818  return $this->mailnottype;
10819  }
10820  else
10821  {
10822  return 0;
10823  }
10824  }
10825 
10827  {
10828  if ($a_type == 1)
10829  {
10830  $this->mailnottype = 1;
10831  }
10832  else
10833  {
10834  $this->mailnottype = 0;
10835  }
10836  }
10837 
10838  public function getExportSettings()
10839  {
10840  if ($this->exportsettings)
10841  {
10842  return $this->exportsettings;
10843  }
10844  else
10845  {
10846  return 0;
10847  }
10848  }
10849 
10850  public function setExportSettings($a_settings)
10851  {
10852  if ($a_settings)
10853  {
10854  $this->exportsettings = $a_settings;
10855  }
10856  else
10857  {
10858  $this->exportsettings = 0;
10859  }
10860  }
10861 
10863  {
10864  if (($this->exportsettings & 1) > 0)
10865  {
10866  return true;
10867  }
10868  else
10869  {
10870  return false;
10871  }
10872  }
10873 
10874  public function setExportSettingsSingleChoiceShort($a_settings)
10875  {
10876  if ($a_settings)
10877  {
10878  $this->exportsettings = $this->exportsettings | 1;
10879  }
10880  else
10881  {
10883  {
10884  $this->exportsettings = $this->exportsettings ^ 1;
10885  }
10886  }
10887  }
10888 
10889  public function getEnabledViewMode() {
10890  return $this->enabled_view_mode;
10891  }
10892 
10893  public function setEnabledViewMode($mode) {
10894  $this->enabled_view_mode = $mode;
10895  }
10896 
10898  $this->template_id = (int)$template_id;
10899  }
10900 
10901  function getTemplate() {
10902  return $this->template_id;
10903  }
10904 
10905  public function moveQuestionAfterOLD($previous_question_id, $new_question_id) {
10906  $new_array = array();
10907  $position = 1;
10908 
10909  $query = 'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
10910  $types = array('integer');
10911  $values = array($this->getTestId());
10912 
10913  $new_question_id += 1;
10914 
10915  global $ilDB;
10916  $inserted = false;
10917  $res = $ilDB->queryF($query, $types, $values);
10918  while($row = $ilDB->fetchAssoc($res)) {
10919 
10920  $qid = $row['question_fi'];
10921 
10922  if ($qid == $new_question_id) {
10923  continue;
10924  }
10925  else if ($qid == $previous_question_id) {
10926  $new_array[$position++] = $qid;
10927  $new_array[$position++] = $new_question_id;
10928  $inserted = true;
10929  }
10930  else {
10931  $new_array[$position++] = $qid;
10932  }
10933  }
10934 
10935  $update_query = 'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
10936  $update_types = array('integer', 'integer', 'integer');
10937 
10938  foreach($new_array as $position => $qid) {
10939  $ilDB->manipulateF(
10940  $update_query,
10941  $update_types,
10942  $vals = array(
10943  $position,
10944  $this->getTestId(),
10945  $qid
10946  )
10947  );
10948  }
10949  }
10950 
10952  {
10953  if (is_array($options))
10954  {
10955  $this->setGenericAnswerFeedback( in_array('instant_feedback_generic', $options) ? 1 : 0);
10956  $this->setSpecificAnswerFeedback( in_array('instant_feedback_specific', $options) ? 1 : 0);
10957  $this->setAnswerFeedbackPoints( in_array('instant_feedback_points', $options) ? 1 : 0);
10958  $this->setInstantFeedbackSolution( in_array('instant_feedback_solution', $options) ? 1 : 0);
10959  }
10960  else
10961  {
10962  $this->setGenericAnswerFeedback(0);
10963  $this->setSpecificAnswerFeedback(0);
10964  $this->setAnswerFeedbackPoints(0);
10965  $this->setInstantFeedbackSolution(0);
10966  }
10967  }
10968 
10970  $setter = array(
10971  'pass_details' => 'setShowPassDetails',
10972  'solution_details' => 'setShowSolutionDetails',
10973  'solution_printview' => 'setShowSolutionPrintview',
10974  'solution_feedback' => 'setShowSolutionFeedback',
10975  'solution_answers_only' => 'setShowSolutionAnswersOnly',
10976  'solution_signature' => 'setShowSolutionSignature',
10977  'solution_suggested' => 'setShowSolutionSuggested',
10978  );
10979  foreach($setter as $key => $setter) {
10980  if (in_array($key, $options)) {
10981  $this->$setter(1);
10982  }
10983  else {
10984  $this->$setter(0);
10985  }
10986  }
10987  }
10988 
10989  public function getPoolUsage() {
10990  return (boolean) $this->poolUsage;
10991  }
10992 
10993  public function setPoolUsage($usage) {
10994  $this->poolUsage = (boolean)$usage;
10995  }
10996 
10998  {
10999  $tree = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['tree'] : $GLOBALS['tree'];
11000  $db = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['ilDB'];
11001  $pluginAdmin = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilPluginAdmin'] : $GLOBALS['ilPluginAdmin'];
11002 
11003  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
11004  $qscFactory = new ilTestQuestionSetConfigFactory($tree, $db, $pluginAdmin, $this);
11005  $questionSetConfig = $qscFactory->getQuestionSetConfig();
11006 
11007  /* @var ilTestFixedQuestionSetConfig $questionSetConfig */
11008  $questionSetConfig->reindexQuestionOrdering();
11009 
11010  $this->loadQuestions();
11011  }
11012 
11013  public function setQuestionOrderAndObligations($orders, $obligations)
11014  {
11015  global $ilDB;
11016 
11017  asort($orders);
11018 
11019  $i = 0;
11020 
11021  foreach($orders as $id => $position)
11022  {
11023  $i++;
11024 
11025  $obligatory = (
11026  isset($obligations[$id]) && $obligations[$id] ? 1 : 0
11027  );
11028 
11029  $query = "
11030  UPDATE tst_test_question
11031  SET sequence = %s,
11032  obligatory = %s
11033  WHERE question_fi = %s
11034  ";
11035 
11036  $ilDB->manipulateF(
11037  $query, array('integer', 'integer', 'integer'), array($i, $obligatory, $id)
11038  );
11039  }
11040 
11041  $this->loadQuestions();
11042  }
11043 
11044  public function moveQuestionAfter($question_to_move, $question_before) {
11045  global $ilDB;
11046  //var_dump(func_get_args());
11047  if ($question_before) {
11048  $query = 'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
11049  $types = array('integer');
11050  $values = array($question_before);
11051  $rset = $ilDB->queryF($query, $types, $values);
11052  }
11053 
11054  if (!$question_before || ($rset && !($row = $ilDB->fetchAssoc($rset)))) {
11055  $row = array(
11056  'sequence' => 0,
11057  'test_fi' => $this->getTestId(),
11058  );
11059  }
11060 
11061  $update = 'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
11062  $types = array('integer', 'integer');
11063  $values = array($row['sequence'], $row['test_fi']);
11064  $ilDB->manipulateF($update, $types, $values);
11065 
11066  $update = 'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
11067  $types = array('integer', 'integer');
11068  $values = array($row['sequence'] + 1, $question_to_move);
11069  $ilDB->manipulateF($update, $types, $values);
11070 
11072  }
11073 
11075  {
11076  global $ilDB;
11077 
11078  $questions = $this->getQuestionTitlesAndIndexes();
11079 
11080  $IN_questions = $ilDB->in('q1.question_id', array_keys($questions), false, 'integer');
11081 
11082  $query = "
11083  SELECT count(q1.question_id) cnt
11084 
11085  FROM qpl_questions q1
11086 
11087  INNER JOIN qpl_questions q2
11088  ON q2.question_id = q1.original_id
11089 
11090  WHERE $IN_questions
11091  AND q1.obj_fi = q2.obj_fi
11092  ";
11093 
11094  $rset = $ilDB->query($query);
11095 
11096  $row = $ilDB->fetchAssoc($rset);
11097 
11098  return $row['cnt'] > 0;
11099  }
11100 
11107  public static function _lookupFinishedUserTests($a_user_id)
11108  {
11109  global $ilDB;
11110 
11111  $result = $ilDB->queryF("SELECT test_fi,MAX(pass) AS pass FROM tst_active".
11112  " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)".
11113  " WHERE user_fi=%s".
11114  " GROUP BY test_fi",
11115  array('integer', 'integer'),
11116  array($a_user_id, 1)
11117  );
11118  $all = array();
11119  while($row = $ilDB->fetchAssoc($result))
11120  {
11121  $obj_id = self::_getObjectIDFromTestID($row["test_fi"]);
11122  $all[$obj_id] = (bool)$row["pass"];
11123  }
11124  return $all;
11125  }
11126  public function getQuestions()
11127  {
11128  return $this->questions;
11129  }
11130 
11131  public function isOnline()
11132  {
11133  return $this->online;
11134  }
11135 
11136  public function setOnline($a_online = true)
11137  {
11138  $this->online = (bool)$a_online;
11139  }
11140 
11144  public function getOldOnlineStatus()
11145  {
11146  return $this->oldOnlineStatus;
11147  }
11148 
11153  {
11154  $this->oldOnlineStatus = $oldOnlineStatus;
11155  }
11156 
11157  public function setPrintBestSolutionWithResult($status)
11158  {
11159  $this->print_best_solution_with_result = (bool) $status;
11160  }
11161 
11163  {
11165  }
11166 
11173  {
11175  }
11176 
11183  {
11184  $this->offeringQuestionHintsEnabled = (bool)$offeringQuestionHintsEnabled;
11185  }
11186 
11187  function setActivationVisibility($a_value)
11188  {
11189  $this->activation_visibility = (bool) $a_value;
11190  }
11191 
11193  {
11195  }
11196 
11198  {
11199  return (bool)$this->activation_limited;
11200  }
11201 
11202  function setActivationLimited($a_value)
11203  {
11204  $this->activation_limited = (bool)$a_value;
11205  }
11206 
11207  /* GET/SET for highscore feature */
11208 
11214  public function setHighscoreEnabled($a_enabled)
11215  {
11216  $this->_highscore_enabled = (bool)$a_enabled;
11217  }
11218 
11224  public function getHighscoreEnabled()
11225  {
11226  return (bool) $this->_highscore_enabled;
11227  }
11228 
11236  public function setHighscoreAnon($a_anon)
11237  {
11238  $this->_highscore_anon = (bool)$a_anon;
11239  }
11240 
11250  public function getHighscoreAnon()
11251  {
11252  return (bool) $this->_highscore_anon;
11253  }
11254 
11263  public function isHighscoreAnon()
11264  {
11265  if ($this->getAnonymity() == 1)
11266  {
11267  return true;
11268  }
11269  else
11270  {
11271  return (bool)$this->getHighscoreAnon();
11272  }
11273  }
11274 
11280  public function setHighscoreAchievedTS($a_achieved_ts)
11281  {
11282  $this->_highscore_achieved_ts = (bool)$a_achieved_ts;
11283  }
11284 
11290  public function getHighscoreAchievedTS()
11291  {
11292  return (bool) $this->_highscore_achieved_ts;
11293  }
11294 
11300  public function setHighscoreScore($a_score)
11301  {
11302  $this->_highscore_score = (bool)$a_score;
11303  }
11304 
11310  public function getHighscoreScore()
11311  {
11312  return (bool) $this->_highscore_score;
11313  }
11314 
11320  public function setHighscorePercentage($a_percentage)
11321  {
11322  $this->_highscore_percentage = (bool)$a_percentage;
11323  }
11324 
11330  public function getHighscorePercentage()
11331  {
11332  return (bool) $this->_highscore_percentage;
11333  }
11334 
11340  public function setHighscoreHints($a_hints)
11341  {
11342  $this->_highscore_hints = (bool)$a_hints;
11343  }
11344 
11350  public function getHighscoreHints()
11351  {
11352  return (bool) $this->_highscore_hints;
11353  }
11354 
11360  public function setHighscoreWTime($a_wtime)
11361  {
11362  $this->_highscore_wtime = (bool)$a_wtime;
11363  }
11364 
11370  public function getHighscoreWTime()
11371  {
11372  return (bool) $this->_highscore_wtime;
11373  }
11374 
11380  public function setHighscoreOwnTable($a_own_table)
11381  {
11382  $this->_highscore_own_table = (bool)$a_own_table;
11383  }
11384 
11390  public function getHighscoreOwnTable()
11391  {
11392  return (bool) $this->_highscore_own_table;
11393  }
11394 
11400  public function setHighscoreTopTable($a_top_table)
11401  {
11402  $this->_highscore_top_table = (bool)$a_top_table;
11403  }
11404 
11410  public function getHighscoreTopTable()
11411  {
11412  return (bool) $this->_highscore_top_table;
11413  }
11414 
11421  public function setHighscoreTopNum($a_top_num)
11422  {
11423  $this->_highscore_top_num = (int)$a_top_num;
11424  }
11425 
11434  public function getHighscoreTopNum($a_retval = 10)
11435  {
11436  $retval = $a_retval;
11437  if ( (int) $this->_highscore_top_num != 0)
11438  {
11439  $retval = $this->_highscore_top_num;
11440  }
11441 
11442  return $retval;
11443  }
11444 
11448  public function getHighscoreMode()
11449  {
11450  switch(true)
11451  {
11452  case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
11453  return self::HIGHSCORE_SHOW_ALL_TABLES;
11454  break;
11455 
11456  case $this->getHighscoreTopTable():
11457  return self::HIGHSCORE_SHOW_TOP_TABLE;
11458  break;
11459 
11460  case $this->getHighscoreOwnTable():
11461  default:
11462  return self::HIGHSCORE_SHOW_OWN_TABLE;
11463  break;
11464  }
11465  }
11466 
11470  public function setHighscoreMode($mode)
11471  {
11472  switch($mode)
11473  {
11474  case self::HIGHSCORE_SHOW_ALL_TABLES:
11475  $this->setHighscoreTopTable(1);
11476  $this->setHighscoreOwnTable(1);
11477  break;
11478 
11479  case self::HIGHSCORE_SHOW_TOP_TABLE:
11480  $this->setHighscoreTopTable(1);
11481  $this->setHighscoreOwnTable(0);
11482  break;
11483 
11484  case self::HIGHSCORE_SHOW_OWN_TABLE:
11485  default:
11486  $this->setHighscoreTopTable(0);
11487  $this->setHighscoreOwnTable(1);
11488  break;
11489  }
11490  }
11491  /* End GET/SET for highscore feature*/
11492 
11493  public function setSpecificAnswerFeedback($specific_answer_feedback)
11494  {
11495  switch ($specific_answer_feedback)
11496  {
11497  case 1:
11498  $this->specific_answer_feedback = 1;
11499  break;
11500  default:
11501  $this->specific_answer_feedback = 0;
11502  break;
11503  }
11504  }
11505 
11506  public function getSpecificAnswerFeedback()
11507  {
11508  switch ($this->specific_answer_feedback)
11509  {
11510  case 1:
11511  return 1;
11512  default:
11513  return 0;
11514  }
11515  }
11516 
11523  {
11524  $this->obligationsEnabled = (bool)$obligationsEnabled;
11525  }
11526 
11532  public function areObligationsEnabled()
11533  {
11534  return (bool)$this->obligationsEnabled;
11535  }
11536 
11543  public static function isQuestionObligationPossible($questionId)
11544  {
11545  require_once('Modules/TestQuestionPool/classes/class.assQuestion.php');
11546 
11547  $classConcreteQuestion = assQuestion::_getQuestionType($questionId);
11548 
11549  assQuestion::_includeClass($classConcreteQuestion, 0);
11550 
11551  // static binder is not at work yet (in PHP < 5.3)
11552  //$obligationPossible = $classConcreteQuestion::isObligationPossible();
11553  $obligationPossible = call_user_func(array($classConcreteQuestion, 'isObligationPossible'), $questionId);
11554 
11555  return $obligationPossible;
11556  }
11557 
11564  public static function isQuestionObligatory($question_id)
11565  {
11566  global $ilDB;
11567 
11568  $rset = $ilDB->queryF('SELECT obligatory FROM tst_test_question WHERE question_fi = %s', array('integer'), array($question_id));
11569 
11570  if( $row = $ilDB->fetchAssoc($rset) )
11571  {
11572  return (bool) $row['obligatory'];
11573  }
11574 
11575  return false;
11576  }
11577 
11590  public static function allObligationsAnswered($test_id, $active_id, $pass)
11591  {
11592  global $ilDB;
11593 
11594  $rset = $ilDB->queryF(
11595  'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
11596  array('integer', 'integer'),
11597  array($active_id, $pass)
11598  );
11599 
11600  if( $row = $ilDB->fetchAssoc($rset) )
11601  {
11602  return (bool)$row['obligations_answered'];
11603  }
11604 
11605  return !self::hasObligations($test_id);
11606  }
11607 
11616  public static function hasObligations($test_id)
11617  {
11618  global $ilDB;
11619 
11620  $rset = $ilDB->queryF(
11621  'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
11622  array('integer'), array($test_id)
11623  );
11624 
11625  $row = $ilDB->fetchAssoc($rset);
11626 
11627  return (bool)$row['cnt'] > 0;
11628  }
11629 
11630  public function setAutosave($autosave)
11631  {
11632  $this->autosave = $autosave;
11633  }
11634 
11635  public function getAutosave()
11636  {
11637  return $this->autosave;
11638  }
11639 
11641  {
11642  $this->autosave_ival = $autosave_ival;
11643  }
11644 
11645  public function getAutosaveIval()
11646  {
11647  return $this->autosave_ival;
11648  }
11649 
11655  public function isPassDeletionAllowed()
11656  {
11658  }
11659 
11666  {
11667  $this->passDeletionAllowed = (bool)$passDeletionAllowed;
11668  }
11669 
11670  #region Examview / PDF Examview
11671 
11675  {
11676  $this->show_examview_html = $show_examview_html;
11677  }
11678 
11682  public function getShowExamviewHtml()
11683  {
11685  }
11686 
11691  {
11692  $this->show_examview_pdf = $show_examview_pdf;
11693  }
11694 
11698  public function getShowExamviewPdf()
11699  {
11700  return $this->show_examview_pdf;
11701  }
11702 
11707  {
11708  $this->enable_examview = $enable_examview;
11709  }
11710 
11714  public function getEnableExamview()
11715  {
11716  return $this->enable_examview;
11717  }
11718 
11719  #endregion
11720 
11722  {
11723  $this->activation_starting_time = $starting_time;
11724  }
11725 
11727  {
11728  $this->activation_ending_time = $ending_time;
11729  }
11730 
11732  {
11733  return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : NULL;
11734  }
11735 
11737  {
11738  return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : NULL;
11739  }
11740 
11742  {
11743  global $ilDB;
11744 
11745  $times = array();
11746  $result = $ilDB->query("SELECT tst_times.active_fi, tst_times.started FROM tst_times, tst_active WHERE tst_times.active_fi = tst_active.active_id ORDER BY tst_times.tstamp DESC");
11747  while ($row = $ilDB->fetchAssoc($result))
11748  {
11749  $times[$row['active_fi']] = $row['started'];
11750  }
11751  return $times;
11752  }
11753 
11755  {
11756  global $ilDB;
11757 
11758  $times = array();
11759  $result = $ilDB->queryF("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",
11760  array('integer'),
11761  array($this->getTestId())
11762  );
11763  while ($row = $ilDB->fetchAssoc($result))
11764  {
11765  $times[$row['active_fi']] = $row['additionaltime'];
11766  }
11767  return $times;
11768  }
11769 
11770  public function getExtraTime($active_id)
11771  {
11772  global $ilDB;
11773 
11774  $result = $ilDB->queryF("SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
11775  array('integer'),
11776  array($active_id)
11777  );
11778  if ($result->numRows() > 0)
11779  {
11780  $row = $ilDB->fetchAssoc($result);
11781  return $row['additionaltime'];
11782  }
11783  return 0;
11784  }
11785 
11786  public function addExtraTime($active_id, $minutes)
11787  {
11788  global $ilDB;
11789 
11790  $participants = array();
11791  if ($active_id == 0)
11792  {
11793  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s",
11794  array('integer'),
11795  array($this->getTestId())
11796  );
11797  while ($row = $ilDB->fetchAssoc($result))
11798  {
11799  array_push($participants, $row['active_id']);
11800  }
11801  }
11802  else
11803  {
11804  array_push($participants, $active_id);
11805  }
11806  foreach ($participants as $active_id)
11807  {
11808  $result = $ilDB->queryF("SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
11809  array('integer'),
11810  array($active_id)
11811  );
11812  if ($result->numRows() > 0)
11813  {
11814  $ilDB->manipulateF("DELETE FROM tst_addtime WHERE active_fi = %s",
11815  array('integer'),
11816  array($active_id)
11817  );
11818  }
11819 
11820  $ilDB->manipulateF("UPDATE tst_active SET tries = %s, submitted = %s, submittimestamp = %s WHERE active_id = %s",
11821  array('integer','integer','timestamp','integer'),
11822  array(0, 0, NULL, $active_id)
11823  );
11824 
11825  $ilDB->manipulateF("INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
11826  array('integer','integer','integer'),
11827  array($active_id, $minutes, time())
11828  );
11829 
11830  require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
11832  {
11833  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_added_extratime", ilObjAssessmentFolder::_getLogLanguage()), $minutes, $active_id));
11834  }
11835  }
11836  }
11837 
11844  {
11845  $this->enable_archiving = $enable_archiving;
11846  return $this;
11847  }
11848 
11852  public function getEnableArchiving()
11853  {
11854  return $this->enable_archiving;
11855  }
11856 
11857  public function getMaxPassOfTest()
11858  {
11862  global $ilDB;
11863 
11864  $query = '
11865  SELECT MAX(tst_pass_result.pass) + 1 max_res
11866  FROM tst_pass_result
11867  INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
11868  WHERE test_fi = '.$ilDB->quote($this->getTestId(), 'integer').'
11869  ';
11870  $res = $ilDB->query($query);
11871  $data = $ilDB->fetchAssoc($res);
11872  return (int)$data['max_res'];
11873  }
11874 
11880  public static function lookupExamId($active_id, $pass)
11881  {
11882  global $ilDB;
11883 
11884  $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
11885  $exam_id_result = $ilDB->queryF( $exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ) );
11886  if ($ilDB->numRows( $exam_id_result ) == 1)
11887  {
11888  $exam_id_row = $ilDB->fetchAssoc( $exam_id_result );
11889 
11890  if ($exam_id_row['exam_id'] != null)
11891  {
11892  return $exam_id_row['exam_id'];
11893  }
11894  }
11895 
11896  return null;
11897  }
11898 
11905  public static function buildExamId($active_id, $pass, $test_obj_id = null)
11906  {
11907  global $ilSetting;
11908 
11909  $inst_id = $ilSetting->get( 'inst_id', null );
11910 
11911  if($test_obj_id === null)
11912  {
11913  $obj_id = self::_getObjectIDFromActiveID($active_id);
11914  }
11915  else
11916  {
11917  $obj_id = $test_obj_id;
11918  }
11919 
11920  $examId = 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
11921 
11922  return $examId;
11923  }
11924 
11926  {
11927  $this->show_exam_id_in_test_pass_enabled = $show_exam_id_in_test_pass_enabled;
11928  }
11929 
11931  {
11933  }
11934 
11939  {
11940  $this->show_exam_id_in_test_results_enabled = $show_exam_id_in_test_results_enabled;
11941  }
11942 
11947  {
11949  }
11950 
11955  {
11956  $this->sign_submission = $sign_submission;
11957  }
11958 
11962  public function getSignSubmission()
11963  {
11964  return $this->sign_submission;
11965  }
11966 
11970  public function setCharSelectorAvailability($availability)
11971  {
11972  $this->char_selector_availability = (int) $availability;
11973  }
11974 
11979  {
11980  return (int) $this->char_selector_availability;
11981  }
11982 
11986  public function setCharSelectorDefinition($definition = '')
11987  {
11988  $this->char_selector_definition = $definition;
11989  }
11990 
11994  public function getCharSelectorDefinition()
11995  {
11997  }
11998 
11999 
12006  {
12007  $this->questionSetType = $questionSetType;
12008  }
12009 
12015  public function getQuestionSetType()
12016  {
12017  return $this->questionSetType;
12018  }
12019 
12027  public static function lookupQuestionSetType($objId)
12028  {
12029  global $ilDB;
12030 
12031  $query = "SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
12032 
12033  $res = $ilDB->queryF($query, array('integer'), array($objId));
12034 
12035  $questionSetType = null;
12036 
12037  while( $row = $ilDB->fetchAssoc($res) )
12038  {
12039  $questionSetType = $row['question_set_type'];
12040  }
12041 
12042  return $questionSetType;
12043  }
12044 
12050  public function isFixedTest()
12051  {
12052  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED;
12053  }
12054 
12060  public function isRandomTest()
12061  {
12062  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_RANDOM;
12063  }
12064 
12070  public function isDynamicTest()
12071  {
12072  return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_DYNAMIC;
12073  }
12074 
12082  public static function _lookupRandomTest($a_obj_id)
12083  {
12084  return self::lookupQuestionSetType($a_obj_id) == self::QUESTION_SET_TYPE_RANDOM;
12085  }
12086 
12088  {
12089  switch( $questionSetType )
12090  {
12092  return $lng->txt('tst_question_set_type_fixed');
12093 
12095  return $lng->txt('tst_question_set_type_random');
12096 
12098  return $lng->txt('tst_question_set_type_dynamic');
12099  }
12100 
12101  throw new ilTestException('invalid question set type value given: '.$questionSetType);
12102  }
12103 
12104  public function participantDataExist()
12105  {
12106  if( $this->participantDataExist === null )
12107  {
12108  $this->participantDataExist = (bool)$this->evalTotalPersons();
12109  }
12110 
12112  }
12113 
12114  public function isScoreReportingAvailable()
12115  {
12116  if ($this->getScoreReporting() == 4)
12117  {
12118  return false;
12119  }
12120 
12121  if ($this->getScoreReporting() == 3 && $this->getReportingDate() > time())
12122  {
12123  return false;
12124  }
12125 
12126  return true;
12127  }
12128 
12129  public function recalculateScores($preserve_manscoring = false)
12130  {
12131  require_once 'class.ilTestScoring.php';
12132  $scoring = new ilTestScoring($this);
12133  $scoring->setPreserveManualScores($preserve_manscoring);
12134  $scoring->recalculateSolutions();
12135  }
12136 
12137  public static function getPoolQuestionChangeListeners(ilDBInterface $db, $poolObjId)
12138  {
12139  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
12140 
12141  $questionChangeListeners = array(
12143  );
12144 
12145  return $questionChangeListeners;
12146  }
12147 
12148  public static function getTestObjIdsWithActiveForUserId($userId)
12149  {
12150  global $ilDB;
12151 
12152  $query = "
12153  SELECT obj_fi
12154  FROM tst_active
12155  INNER JOIN tst_tests
12156  ON test_id = test_fi
12157  WHERE user_fi = %s
12158  ";
12159 
12160  $res = $ilDB->queryF($query, array('integer'), array($userId));
12161 
12162  $objIds = array();
12163 
12164  while( $row = $ilDB->fetchAssoc($res) )
12165  {
12166  $objIds[] = (int)$row['obj_fi'];
12167  }
12168 
12169  return $objIds;
12170  }
12171 
12173  {
12174  $this->skillServiceEnabled = $skillServiceEnabled;
12175  }
12176 
12177  public function isSkillServiceEnabled()
12178  {
12180  }
12181 
12183  {
12184  $this->resultFilterTaxIds = $resultFilterTaxIds;
12185  }
12186 
12187  public function getResultFilterTaxIds()
12188  {
12190  }
12191 
12193  {
12194  if( !$this->isSkillServiceEnabled() )
12195  {
12196  return false;
12197  }
12198 
12199  if( !self::isSkillManagementGloballyActivated() )
12200  {
12201  return false;
12202  }
12203 
12204  return true;
12205  }
12206 
12208 
12209  public static function isSkillManagementGloballyActivated()
12210  {
12211  if( self::$isSkillManagementGloballyActivated === null )
12212  {
12213  include_once 'Services/Skill/classes/class.ilSkillManagementSettings.php';
12214  $skmgSet = new ilSkillManagementSettings();
12215 
12216  self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
12217  }
12218 
12219  return self::$isSkillManagementGloballyActivated;
12220  }
12221 
12223  {
12224  $this->showGradingStatusEnabled = $showGradingStatusEnabled;
12225  }
12226 
12227  public function isShowGradingStatusEnabled()
12228  {
12230  }
12231 
12233  {
12234  $this->showGradingMarkEnabled = $showGradingMarkEnabled;
12235  }
12236 
12237 
12238  public function isShowGradingMarkEnabled()
12239  {
12241  }
12242 
12244  {
12245  $this->instantFeedbackAnswerFixationEnabled = $instantFeedbackAnswerFixationEnabled;
12246  }
12247 
12249  {
12251  }
12252 
12257  {
12259  }
12260 
12265  {
12266  $this->forceInstantFeedbackEnabled = $forceInstantFeedbackEnabled;
12267  }
12268 
12269  public static function ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run = FALSE)
12270  {
12271  global $ilDB, $lng, $ilPluginAdmin;
12272 
12273  /* @var ilObjTest $testOBJ */
12274 
12275  $testOBJ = ilObjectFactory::getInstanceByRefId($testObjId,false);
12276 
12277  $activeId = $testOBJ->getActiveIdOfUser($userId);
12278 
12279  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12280  $testSessionFactory = new ilTestSessionFactory($testOBJ);
12281 
12282  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12283  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12284 
12285  $testSession = $testSessionFactory->getSession($activeId);
12286  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12287  $testSequence->loadFromDb();
12288 
12289  // begin-patch lok changed smeyer
12290  if($a_force_new_run)
12291  {
12292  if( $testSequence->hasSequence() )
12293  {
12294  $testSession->increasePass();
12295  }
12296  $testSession->setLastSequence(0);
12297  $testSession->saveToDb();
12298  }
12299  // end-patch lok
12300  }
12301 
12302  public static function isParticipantsLastPassActive($testRefId, $userId)
12303  {
12304  global $ilDB, $lng, $ilPluginAdmin;
12305 
12306  /* @var ilObjTest $testOBJ */
12307 
12308  $testOBJ = ilObjectFactory::getInstanceByRefId($testRefId,false);
12309 
12310 
12311  $activeId = $testOBJ->getActiveIdOfUser($userId);
12312 
12313  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12314  $testSessionFactory = new ilTestSessionFactory($testOBJ);
12315  // Added temporarily bugfix smeyer
12316  $testSessionFactory->reset();
12317 
12318  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12319  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12320 
12321  $testSession = $testSessionFactory->getSession($activeId);
12322  $testSequence = $testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $testSession->getPass());
12323  $testSequence->loadFromDb();
12324 
12325  return $testSequence->hasSequence();
12326  }
12327 
12331  public function isTestFinalBroken()
12332  {
12333  return $this->testFinalBroken;
12334  }
12335 
12340  {
12341  $this->testFinalBroken = $testFinalBroken;
12342  }
12343 }
setStartingTime($starting_time=NULL)
Sets the starting time in database timestamp format for the test.
$files
Definition: add-vimline.php:18
setAllowedUsers($a_allowed_users)
static _getUserIdFromActiveId($active_id)
setAnswerFeedback($answer_feedback=0)
Sets the generic feedback for the test Use setGenericAnswerFeedback instead.
setECTSFX($a_ects_fx)
{}
saveCertificateVisibility($a_value)
Saves the visibility settings of the certificate.
static _lookupName($a_user_id)
lookup user name
xslt_create()
getExportDirectory()
Get the location of the export directory for the test.
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.
setRedirectionUrl($redirection_url=NULL)
setMailNotification($a_notification)
Set mail notification settings.
saveToDb($properties_only=FALSE)
Saves a ilObjTest object to a database.
ILIAS Setting Class.
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
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...
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()
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...
setQuestionOrderAndObligations($orders, $obligations)
setRedirectionMode($redirection_mode=0)
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
static _addLog($user_id, $object_id, $logtext, $question_id="", $original_id="", $test_only=FALSE, $test_ref_id=NULL)
Add an assessment log entry.
setQuestionSetType($questionSetType)
setter for question set type
Class ilObjTestGUI.
setECTSOutput($a_ects_output)
{}
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.
cloneObject($a_target_id, $a_copy_id=0, $a_omit_tree=false)
Clone object permissions, put in tree ...
saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
Checks if the test is complete and saves the status in the database.
$online
the object&#39;s online status
static _exists($a_id, $a_reference=false, $a_type=NULL)
checks wether a lm content object with specified id exists or not
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
setListOfQuestionsDescription($a_value=TRUE)
Sets the show_summary attribute to TRUE if the list of questions should be presented with the questio...
getListOfQuestionsStart()
Returns if the list of questions should be presented as the first page of the test.
static _lookupRandomTest($a_obj_id)
Returns the fact wether the test with passed obj id is a random questions test or not...
getTestParticipantsForManualScoring($filter=NULL)
& getParticipants()
Returns all persons who started the test.
const SCORE_LAST_PASS
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.
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.
setListOfQuestionsStart($a_value=TRUE)
Sets if the the list of questions as the start page of the test.
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.
setListOfQuestions($a_value=TRUE)
Sets if the the list of questions should be presented to the user or not.
setTmpCopyWizardCopyId($tmpCopyWizardCopyId)
updateMetaData()
update meta data entry
xslt_free(&$proc)
static _getPassScoring($active_id)
Gets the pass scoring type.
setCharSelectorDefinition($definition='')
Class ilObject Basic functions for all objects.
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.
& 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.
setShowSolutionAnswersOnly($a_full=TRUE)
Set to true, if the full solution (including the ILIAS content pages) should be shown in the solution...
setKioskMode($a_kiosk=FALSE)
Sets the kiosk mode for the test.
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.
setShowSolutionSignature($a_signature=FALSE)
Set to TRUE, if the signature field should be shown in the solution.
& 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)
setEndingTime($ending_time=NULL)
Sets the ending time in database timestamp format for the test.
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.
setSpecificAnswerFeedback($specific_answer_feedback)
getShuffleQuestions()
Returns the status of the shuffle_questions variable.
prepareTextareaOutput($txt_output, $prepare_for_latex_output=FALSE, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
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.
questionMoveDown($question_id)
Moves a question down in order.
getOwner()
get object owner
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
isSingleChoiceTest()
Returns TRUE if the test contains single choice results only.
getActiveIdOfUser($user_id="", $anonymous_id="")
Gets the active id of a given user.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
setShowGradingStatusEnabled($showGradingStatusEnabled)
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
& getGroupData($ids)
getPassed($active_id)
static _getBestPass($active_id)
Retrieves the best pass of a given user for a given test.
for($col=0; $col< 50; $col++) $d
$total
Definition: Utf8Test.php:87
static _lookupAnonymity($a_obj_id)
Returns the anonymity status of a test with a given object id.
setShowKioskModeParticipant($a_participant=FALSE)
Set to true, if the participant&#39;s name should be shown in kiosk mode.
& getAllQuestions($pass=NULL)
Returns all questions of a test in test order.
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.
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.
& getCompleteEvaluationData($withStatistics=TRUE, $filterby="", $filtertext="")
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)
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
$counter
updateWorkingTime($times_id)
Update the working time of a test when a question is answered.
Interface ilDBInterface.
$a_type
Definition: workflow.php:93
$instantFeedbackAnswerFixationEnabled
xslt_error(&$proc)
exportFileItems($a_target_dir, &$expLog)
export files of file itmes
setCustomStyle($a_customStyle=NULL)
Set the custom style.
static _getLogLanguage()
retrieve the log language for assessment logging
setSignSubmission($sign_submission)
static completeMissingPluginName($questionTypeData)
getImportMapping()
get array of (two) new created questions for import id
static _getMaxPass($active_id)
Retrieves the maximum pass of a given user for a given test in which the user answered at least one q...
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\+" &#(? foreach( $entity_files as $file) $output
getAnsweredQuestionCount($active_id, $pass=NULL)
Retrieves the number of answered questions for a given user in a given test.
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.
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)
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)
getVisitTimeOfParticipant($active_id)
Returns the first and last visit of a participant.
static _getAvailableTests($use_object_id=FALSE)
Returns the available tests for the active user.
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.
isExecutable($testSession, $user_id, $allowPassIncrease=FALSE)
Checks if the test is executable by the given user.
setProcessingTime($processing_time="00:00:00")
Sets the processing time for the test.
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)
if(!is_array($argv)) $options
getHighscoreAnon()
Gets if the highscores should be anonymized per setting.
$mobs
setExportSettings($a_settings)
static _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
removeQuestion($question_id)
Removes a question from the test object.
getId()
get object id public
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.
deliverPDFfromHTML($content, $title=NULL)
Delivers a PDF file from XHTML.
static _saveTempFileAsMediaObject($name, $tmp_name, $upload=TRUE)
Create new media object and update page in db and return new media object.
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
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.
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.
& processCSVRow($row, $quoteAll=FALSE, $separator=";")
Processes an array as a CSV row and converts the array values to correct CSV values.
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.
isSkillServiceToBeConsidered()
Class ilObjFile.
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.
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
buildIso8601PeriodFromUnixtimeForExportCompatibility($unix_timestamp)
canShowSolutionPrintview($user_id=NULL)
Calculates if a user may see the solution printview of his/her test results.
static formatDate(ilDateTime $date)
Format a date public.
setAllowedUsersTimeGap($a_allowed_users_time_gap)
getTitle()
get object title public
applyDefaults($test_defaults)
Applies given test defaults to this test.
randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id=0, $qpls="", $pass=NULL)
Returns a random selection of questions.
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.
loadQuestions($active_id="", $pass=NULL)
Load the test question id&#39;s from the database.
isBestSolutionPrintedWithResult()
& getExistingQuestions($pass=NULL)
Get the id&#39;s of the questions which are already part of the test.
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.
static ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run=FALSE)
setECTSGrades(array $a_ects_grades)
{}
Class ilObjMediaObject.
Test session handler.
userLookupFullName($user_id, $overwrite_anonymity=FALSE, $sorted_order=FALSE, $suffix="")
Returns the full name of a test user according to the anonymity status.
removeTestResultsFromSoapLpAdministration($userIds)
getMarkSchema()
{ASS_MarkSchema}
getAggregatedResultsData()
Returns the aggregated test results.
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
& 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.
$results
getStartingTime()
Returns the starting time of the test.
getStartingTimeOfParticipants()
setAnonymity($a_value=0)
Sets the anonymity status of the test.
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
setShowSolutionFeedback($a_feedback=TRUE)
Sets if the the feedback should be presented to the user in the solution or not.
isInstantFeedbackAnswerFixationEnabled()
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...
const TEST_FIXED_SEQUENCE
Test constants.
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)
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.
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
getEndingTime()
Returns the ending time of the test.
setListOfQuestionsEnd($a_value=TRUE)
Sets if the the list of questions as the end page 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)
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test...
setShowSolutionSuggested($a_solution=FALSE)
Set to TRUE, if the suggested solution should be shown in the solution.
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
setShowSolutionListComparison($a_comparison=FALSE)
Set to TRUE, if the list of answers should be shown prior to finish the test.
setOfferingQuestionHintsEnabled($offeringQuestionHintsEnabled)
sets offering question hints enabled/disabled
getExtraTime($active_id)
moveQuestions($move_questions, $target_index, $insert_mode)
Move questions to another position.
getSequenceByActiveIdAndPass($activeId, $pass)
creates and returns an instance of a test sequence that corresponds to the current test mode and give...
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd)
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...
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.
setShowKioskModeTitle($a_title=FALSE)
Set to true, if the full test title should be shown in kiosk mode.
saveAuthorToMetadata($a_author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
setActivationStartingTime($starting_time=NULL)
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.
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.
global $DIC
setClientIP($user_id, $client_ip)
getTextAnswer($active_id, $question_id, $pass=NULL)
Returns the text answer of a given user for a given question.
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
getHighscoreScore()
Gets if the score column should be shown.
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.
& getWorkedQuestions($active_id, $pass=NULL)
Gets the id&#39;s of all questions a user already worked through.
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)
getPassFinishDate($active_id, $pass)
Retrieves the number of answered questions for a given user in a given test.
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)
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 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. ...
getForceJS()
Gets whether JavaScript should be forced for tests.
Class ilObjectActivation.
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.
isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
Returns true, if a test is complete for use and can be set online.
setActivationEndingTime($ending_time=NULL)
static getFeedbackClassNameByQuestionType($questionType)
static _getQuestionTitle($question_id)
Returns the question title of a question with a given id.
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.
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.
$params
Definition: example_049.php:96
setSequenceSettings($sequence_settings=0)
SEQUENCE SETTING = POSTPONING ENABLED !!
reindexFixedQuestionOrdering()
setPassword($a_password=NULL)
Sets the password for test access.
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
static _setImportDirectory($a_import_dir=null)
set import directory
static _getTestDefaults($test_defaults_id)
read()
read object data from db into object
& 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...
static _getActiveIdOfUser($user_id="", $test_id="")
Gets the active id of the tst_active table for the active user.
setStartingTimeEnabled($starting_time_enabled)
getHighscoreTopNum($a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
static _getImportDirectory()
Get the import directory location of the test.
$test
Definition: Utf8Test.php:84
$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.