ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
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 
20 {
22 
23  #region Properties
24 
28  const QUESTION_SET_TYPE_FIXED = 'FIXED_QUEST_SET';
29 
33  const QUESTION_SET_TYPE_RANDOM = 'RANDOM_QUEST_SET';
34 
38  const QUESTION_SET_TYPE_DYNAMIC = 'DYNAMIC_QUEST_SET';
39 
44 
49 
54 
61 
65  private $skillServiceEnabled = false;
66 
70  private $resultFilterTaxIds = array();
71 
79  protected $_kiosk;
80 
86  var $test_id;
87 
94 
101  var $author;
102 
109 
116 
121 
128  protected $introduction;
129 
136 
145 
156 
165 
172 
182 
189 
197 
205 
215 
222 
229 
236 
241 
247  protected $starting_time;
248 
253 
259  protected $ending_time;
260 
265  protected $ects_output = FALSE;
266 
271  protected $ects_fx = NULL;
272 
277  protected $ects_grades = array();
278 
279 
287 
294 
301 
309 
316 
323 
330 
334  protected $passwordEnabled;
335 
341  protected $password;
342 
347 
353  protected $allowedUsers;
354 
361 
368 
375 
382 
389 
396 
403 
410 
417 
424 
431 
437  private $_showinfo;
438 
444  private $_forcejs = TRUE;
445 
451  private $_customStyle;
452 
453  protected $mailnotification;
454 
455  protected $mailnottype;
456 
457  protected $exportsettings;
458 
459  protected $poolUsage;
460 
461  private $template_id;
462 
468  private $online = null;
469 
474 
481 
487  private $obligationsEnabled = null;
488 
490 
492 
494 
495  protected $autosave;
496 
497  protected $autosave_ival;
498 
505  private $passDeletionAllowed = null;
506 
512  private $participantDataExist = null;
513 
515  protected $enable_examview;
516 
519 
522 
524  protected $enable_archiving;
525 
529  private $redirection_mode = 0;
530 
534  private $redirection_url = NULL;
535 
538 
541 
543  protected $sign_submission;
544 
547 
550 
555 
560 
565 
569  protected $testFinalBroken;
570 
571  #endregion
572 
581  public function __construct($a_id = 0,$a_call_by_reference = true)
582  {
583  global $ilUser, $lng;
584  $this->type = "tst";
585 
586  $lng->loadLanguageModule("assessment");
587  // Defaults:
588  include_once "./Modules/Test/classes/class.assMarkSchema.php";
589  $this->mark_schema = new ASS_MarkSchema();
590  $this->mark_schema->createSimpleSchema(
591  $lng->txt("failed_short"),
592  $lng->txt("failed_official"),
593  0,
594  0,
595  $lng->txt("passed_short"),
596  $lng->txt("passed_official"),
597  50,
598  1
599  );
600 
601  $this->test_id = -1;
602  $this->author = $ilUser->fullname;
603  $this->introductionEnabled = false;
604  $this->introduction = "";
605  $this->questions = array();
606  $this->sequence_settings = TEST_FIXED_SEQUENCE;
607  $this->score_reporting = REPORT_AFTER_TEST;
608  $this->instant_verification = 0;
609  $this->answer_feedback_points = 0;
610  $this->reporting_date = "";
611  $this->nr_of_tries = 0;
612  $this->_kiosk = 0;
613  $this->use_previous_answers = 1;
614  $this->title_output = 0;
615  $this->starting_time = "";
616  $this->ending_time = "";
617  $this->processing_time = "";
618  $this->enable_processing_time = "0";
619  $this->reset_processing_time = 0;
620  $this->ects_output = FALSE;
621  $this->ects_fx = NULL;
622  $this->shuffle_questions = FALSE;
623  $this->mailnottype = 0;
624  $this->exportsettings = 0;
625  $this->show_summary = 8;
626  $this->count_system = COUNT_PARTIAL_SOLUTIONS;
627  $this->mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED;
628  $this->score_cutting = SCORE_CUT_QUESTION;
629  $this->pass_scoring = SCORE_LAST_PASS;
630  $this->answer_feedback = 0;
631  $this->password = "";
632  $this->certificate_visibility = 0;
633  $this->allowedUsers = "";
634  $this->_showfinalstatement = FALSE;
635  $this->_finalstatement = "";
636  $this->_showinfo = TRUE;
637  $this->_forcejs = TRUE;
638  $this->_customStyle = "";
639  $this->allowedUsersTimeGap = "";
640  $this->anonymity = 0;
641  $this->show_cancel = 0;
642  $this->show_marker = 0;
643  $this->fixed_participants = 0;
644  $this->setShowPassDetails(TRUE);
645  $this->setShowSolutionDetails(TRUE);
646  $this->setShowSolutionAnswersOnly(FALSE);
647  $this->setShowSolutionSignature(FALSE);
648  $this->testSession = FALSE;
649  $this->testSequence = FALSE;
650  $this->mailnotification = 0;
651  $this->poolUsage = 1;
652 
653  $this->ects_grades = array(
654  'A' => 90,
655  'B' => 65,
656  'C' => 35,
657  'D' => 10,
658  'E' => 0
659  );
660 
661  $this->autosave = FALSE;
662  $this->autosave_ival = 30000;
663 
664  $this->enable_examview = false;
665  $this->show_examview_html = false;
666  $this->show_examview_pdf = false;
667  $this->enable_archiving = false;
668 
669  $this->express_mode = false;
670  $this->template_id = '';
671  $this->redirection_mode = 0;
672  $this->redirection_url = NULL;
673  $this->show_exam_id_in_test_pass_enabled = false;
674  $this->show_exam_id_in_test_results_enabled = false;
675  $this->sign_submission = false;
676  $this->char_selector_availability = 0;
677  $this->char_selector_definition = null;
678 
679  $this->showGradingStatusEnabled = true;
680  $this->showGradingMarkEnabled = true;
681 
682  $this->instantFeedbackAnswerFixationEnabled = false;
683 
684  $this->testFinalBroken = false;
685 
686  $this->ilObject($a_id, $a_call_by_reference);
687  }
688 
692  function create($a_upload = false)
693  {
694  parent::create();
695 
696  // meta data will be created by
697  // import parser
698  if (!$a_upload)
699  {
700  $this->createMetaData();
701  }
702  }
703 
710  function update()
711  {
712  if (!parent::update())
713  {
714  return false;
715  }
716 
717  // put here object specific stuff
718 
719  return true;
720  }
721 
727  function read($a_force_db = false)
728  {
729  parent::read($a_force_db);
730  $this->loadFromDb();
731  }
732 
733 
740  function delete()
741  {
742  // always call parent delete function first!!
743  if (!parent::delete())
744  {
745  return false;
746  }
747 
748  // delet meta data
749  $this->deleteMetaData();
750 
751  //put here your module specific stuff
752  $this->deleteTest();
753 
754  return true;
755  }
756 
762  function deleteTest()
763  {
764  global $tree, $ilDB, $ilPluginAdmin;
765 
766  // first of all remove all test editings, because the delete statements used for this
767  // contain a subquery for active ids, that are deleted in the next steps
768  $this->removeAllTestEditings();
769 
770  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s",
771  array('integer'),
772  array($this->getTestId())
773  );
774  $active_array = array();
775  while ($row = $ilDB->fetchAssoc($result))
776  {
777  array_push($active_array, $row["active_id"]);
778  }
779 
780  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE test_fi = %s",
781  array('integer'),
782  array($this->getTestId())
783  );
784 
785  if (count($active_array))
786  {
787  foreach ($active_array as $active_id)
788  {
789  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_times WHERE active_fi = %s",
790  array('integer'),
791  array($active_id)
792  );
793 
794  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_sequence WHERE active_fi = %s",
795  array('integer'),
796  array($active_id)
797  );
798  }
799  }
800 
801  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_mark WHERE test_fi = %s",
802  array('integer'),
803  array($this->getTestId())
804  );
805 
806  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_tests WHERE test_id = %s",
807  array('integer'),
808  array($this->getTestId())
809  );
810 
811  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
812  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
813  $testQuestionSetConfigFactory->getQuestionSetConfig()->removeQuestionSetRelatedData();
814 
815  // delete export files
816  include_once "./Services/Utilities/classes/class.ilUtil.php";
817  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
818  $directory = $tst_data_dir."/tst_".$this->getId();
819  if (is_dir($directory))
820  {
821  include_once "./Services/Utilities/classes/class.ilUtil.php";
822  ilUtil::delDir($directory);
823  }
824  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
825  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
826  // remaining usages are not in text anymore -> delete them
827  // and media objects (note: delete method of ilObjMediaObject
828  // checks whether object is used in another context; if yes,
829  // the object is not deleted!)
830  foreach($mobs as $mob)
831  {
832  ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
833  if (ilObjMediaObject::_exists($mob))
834  {
835  $mob_obj =& new ilObjMediaObject($mob);
836  $mob_obj->delete();
837  }
838  }
839  }
840 
841 
855  function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
856  {
857  global $tree;
858 
859  switch ($a_event)
860  {
861  case "link":
862 
863  //var_dump("<pre>",$a_params,"</pre>");
864  //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
865  //exit;
866  break;
867 
868  case "cut":
869 
870  //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
871  //exit;
872  break;
873 
874  case "copy":
875 
876  //var_dump("<pre>",$a_params,"</pre>");
877  //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
878  //exit;
879  break;
880 
881  case "paste":
882 
883  //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
884  //exit;
885  break;
886 
887  case "new":
888 
889  //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
890  //exit;
891  break;
892  }
893 
894  // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
895  if ($a_node_id==$_GET["ref_id"])
896  {
897  $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
898  $parent_type = $parent_obj->getType();
899  if ($parent_type == $this->getType())
900  {
901  $a_node_id = (int) $tree->getParentId($a_node_id);
902  }
903  }
904 
905  parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
906  }
907 
914  {
915  include_once "./Services/Utilities/classes/class.ilUtil.php";
916  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
917  ilUtil::makeDir($tst_data_dir);
918  if (!is_writable($tst_data_dir))
919  {
920  $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
921  .") not writeable.",$this->ilias->error_obj->MESSAGE);
922  }
923 
924  // create learning module directory (data_dir/lm_data/lm_<id>)
925  $tst_dir = $tst_data_dir."/tst_".$this->getId();
926  ilUtil::makeDir($tst_dir);
927  if (!@is_dir($tst_dir))
928  {
929  $this->ilias->raiseError("Creation of Test Directory failed.",$this->ilias->error_obj->MESSAGE);
930  }
931  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
932  $export_dir = $tst_dir."/export";
933  ilUtil::makeDir($export_dir);
934  if (!@is_dir($export_dir))
935  {
936  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->MESSAGE);
937  }
938  }
939 
946  {
947  include_once "./Services/Utilities/classes/class.ilUtil.php";
948  $export_dir = ilUtil::getDataDir()."/tst_data"."/tst_".$this->getId()."/export";
949  return $export_dir;
950  }
951 
958  function getExportFiles($dir)
959  {
960  // quit if import dir not available
961  if(!@is_dir($dir) || !is_writeable($dir))
962  {
963  return array();
964  }
965 
966  $files = array();
967  foreach(new DirectoryIterator($dir) as $file)
968  {
972  if($file->isDir())
973  {
974  continue;
975  }
976 
977  $files[] = $file->getBasename();
978  }
979 
980  sort($files);
981 
982  return $files;
983  }
984 
988  function _setImportDirectory($a_import_dir = null)
989  {
990  if (strlen($a_import_dir))
991  {
992  $_SESSION["tst_import_dir"] = $a_import_dir;
993  }
994  else
995  {
996  unset($_SESSION["tst_import_dir"]);
997  }
998  }
999 
1007  {
1008  if (strlen($_SESSION["tst_import_dir"]))
1009  {
1010  return $_SESSION["tst_import_dir"];
1011  }
1012  return null;
1013  }
1014 
1016  {
1018  }
1019 
1026  {
1027  global $ilias;
1028  include_once "./Services/Utilities/classes/class.ilUtil.php";
1029  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
1030  ilUtil::makeDir($tst_data_dir);
1031 
1032  if (!is_writable($tst_data_dir))
1033  {
1034  $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
1035  .") not writeable.",$this->ilias->error_obj->FATAL);
1036  }
1037 
1038  // create test directory (data_dir/tst_data/tst_import)
1039  $tst_dir = $tst_data_dir."/tst_import";
1040  ilUtil::makeDir($tst_dir);
1041  if (!@is_dir($tst_dir))
1042  {
1043  $ilias->raiseError("Creation of test import directory failed.",$ilias->error_obj->FATAL);
1044  }
1045  return $tst_dir;
1046  }
1047 
1055  {
1056  global $ilDB;
1057 
1058  $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",
1059  array('integer'),
1060  array($this->getTestId())
1061  );
1062  $hasSC = false;
1063  while ($row = $ilDB->fetchAssoc($result))
1064  {
1065  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0)
1066  {
1067  $hasSC = true;
1068  }
1069  }
1070  return $hasSC;
1071  }
1072 
1080  {
1081  global $ilDB;
1082 
1083  $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",
1084  array('integer'),
1085  array($this->getTestId())
1086  );
1087  if ($result->numRows() == 1)
1088  {
1089  $row = $ilDB->fetchAssoc($result);
1090  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0)
1091  {
1092  return TRUE;
1093  }
1094  else
1095  {
1096  return false;
1097  }
1098  }
1099  return FALSE;
1100  }
1101 
1109  {
1110  global $ilDB;
1111 
1112  if (!$this->hasSingleChoiceQuestions()) return false;
1113 
1114  $result = $ilDB->queryF("
1115  SELECT DISTINCT(qpl_qst_sc.shuffle) foundshuffles
1116  FROM qpl_questions,
1117  qpl_qst_sc,
1118  tst_test_result,
1119  qpl_qst_type,
1120  tst_active
1121  WHERE tst_test_result.question_fi = qpl_questions.question_id
1122  AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
1123  AND tst_test_result.active_fi = tst_active.active_id
1124  AND qpl_questions.question_id = qpl_qst_sc.question_fi
1125  AND tst_active.test_fi = %s
1126  AND qpl_qst_type.type_tag = %s
1127  ",
1128  array('integer', 'text'),
1129  array($this->getTestId(), 'assSingleChoice')
1130  );
1131  if ($result->numRows() == 1)
1132  {
1133  $row = $ilDB->fetchAssoc($result);
1134  return ($row['foundshuffles'] == 0);
1135  }
1136  return FALSE;
1137  }
1138 
1145  final public function isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
1146  {
1147  if( !count($this->mark_schema->mark_steps) )
1148  {
1149  return false;
1150  }
1151 
1152  if( !$testQuestionSetConfig->isQuestionSetConfigured() )
1153  {
1154  return false;
1155  }
1156 
1157  return true;
1158  }
1159 
1166  function _isComplete($obj_id)
1167  {
1168  global $tree, $ilDB, $ilPluginAdmin;
1169 
1170  $test = new ilObjTest($obj_id, false);
1171  $test->loadFromDb();
1172 
1173  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1174  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
1175 
1176  return $test->isComplete( $testQuestionSetConfigFactory->getQuestionSetConfig() );
1177  }
1178 
1182  public function saveECTSStatus()
1183  {
1187  global $ilDB;
1188 
1189  if($this->getTestId() > 0)
1190  {
1191  $this->setECTSFX(preg_replace('/,/', '.', $this->getECTSFX()));
1192  if(!preg_match('/\d+/', $this->getECTSFX()))
1193  {
1194  $this->setECTSFX(NULL);
1195  }
1196 
1197  $grades = $this->getECTSGrades();
1198  $ilDB->manipulateF(
1199  "UPDATE tst_tests
1200  SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s
1201  WHERE test_id = %s",
1202  array('text', 'float', 'float', 'float', 'float', 'float', 'float', 'integer'),
1203  array(
1204  (int)$this->getECTSOutput(),
1205  $grades['A'], $grades['B'], $grades['C'], $grades['D'], $grades['E'],
1206  $this->getECTSFX(),
1207  $this->getTestId()
1208  )
1209  );
1210  }
1211  }
1212 
1217  public function saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
1218  {
1219  global $ilDB;
1220 
1221  $complete = 0;
1222  if($this->isComplete($testQuestionSetConfig))
1223  {
1224  $complete = 1;
1225  }
1226  if($this->getTestId() > 0)
1227  {
1228  $ilDB->manipulateF(
1229  "UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1230  array('text', 'integer'),
1231  array($complete, $this->test_id)
1232  );
1233  }
1234  }
1235 
1241  function getAllRTEContent()
1242  {
1243  $result = array();
1244  array_push($result, $this->getIntroduction());
1245  array_push($result, $this->getFinalStatement());
1246  return $result;
1247  }
1248 
1255  {
1256  include_once("./Services/RTE/classes/class.ilRTE.php");
1257  $completecontent = "";
1258  foreach ($this->getAllRTEContent() as $content)
1259  {
1260  $completecontent .= $content;
1261  }
1262  ilRTE::_cleanupMediaObjectUsage($completecontent, $this->getType() . ":html",
1263  $this->getId());
1264  }
1265 
1271  public function saveToDb($properties_only = FALSE)
1272  {
1273  global $tree, $ilDB, $ilPluginAdmin;
1274 
1275  // moved online_status to ilObjectActivation (see below)
1276 
1277  // cleanup RTE images
1278  $this->cleanupMediaobjectUsage();
1279 
1280  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1281  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
1282  $testQuestionSetConfig = $testQuestionSetConfigFactory->getQuestionSetConfig();
1283 
1284  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1285  if ($this->test_id == -1)
1286  {
1287  // Create new dataset
1288  $next_id = $ilDB->nextId('tst_tests');
1289 
1290  $ilDB->insert('tst_tests', array(
1291  'test_id' => array('integer', $next_id),
1292  'obj_fi' => array('integer', $this->getId()),
1293  'author' => array('text', $this->getAuthor()),
1294  'intro_enabled' => array('integer', (int)$this->isIntroductionEnabled()),
1295  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1296  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1297  'showinfo' => array('integer', $this->getShowInfo()),
1298  'forcejs' => array('integer', $this->getForceJS()),
1299  'customstyle' => array('text', $this->getCustomStyle()),
1300  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1301  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1302  'score_reporting' => array('integer', $this->getScoreReporting()),
1303  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1304  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1305  'answer_feedback' => array('text', $this->getAnswerFeedback()),
1306  'anonymity' => array('text', $this->getAnonymity()),
1307  'show_cancel' => array('text', $this->getShowCancel()),
1308  'show_marker' => array('integer', $this->getShowMarker()),
1309  'fixed_participants' => array('text', $this->getFixedParticipants()),
1310  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1311  'kiosk' => array('integer', $this->getKiosk()),
1312  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1313  'title_output' => array('text', $this->getTitleOutput()),
1314  'processing_time' => array('text', $this->getProcessingTime()),
1315  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1316  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1317  'reporting_date' => array('text', $this->getReportingDate()),
1318  'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1319  'starting_time' => array('text', $this->getStartingTime()),
1320  'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1321  'ending_time' => array('text', $this->getEndingTime()),
1322  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1323  'ects_output' => array('text', $this->getECTSOutput()),
1324  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : NULL),
1325  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : NULL),
1326  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : NULL),
1327  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : NULL),
1328  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : NULL),
1329  'ects_fx' => array('float', $this->getECTSFX()),
1330  'count_system' => array('text', $this->getCountSystem()),
1331  'mc_scoring' => array('text', $this->getMCScoring()),
1332  'score_cutting' => array('text', $this->getScoreCutting()),
1333  'pass_scoring' => array('text', $this->getPassScoring()),
1334  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1335  'results_presentation' => array('integer', $this->getResultsPresentation()),
1336  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1337  'password_enabled' => array('integer', (int)$this->isPasswordEnabled()),
1338  'password' => array('text', $this->getPassword()),
1339  'limit_users_enabled' => array('integer', (int)$this->isLimitUsersEnabled()),
1340  'allowedusers' => array('integer', $this->getAllowedUsers()),
1341  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1342  'mailnottype' => array('integer', $this->getMailNotificationType()),
1343  'exportsettings' => array('integer', $this->getExportSettings()),
1344  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1345  'mailnotification' => array('integer', $this->getMailNotification()),
1346  'created' => array('integer', time()),
1347  'tstamp' => array('integer', time()),
1348  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1349  'template_id' => array('integer', $this->getTemplate()),
1350  'pool_usage' => array('integer', $this->getPoolUsage()),
1351  'print_bs_with_res' => array('integer', (int)$this->isBestSolutionPrintedWithResult()),
1352  'obligations_enabled' => array('integer', (int)$this->areObligationsEnabled()),
1353  'offer_question_hints' => array('integer', (int)$this->isOfferingQuestionHintsEnabled()),
1354  'highscore_enabled' => array('integer', (int)$this->getHighscoreEnabled()),
1355  'highscore_anon' => array('integer', (int)$this->getHighscoreAnon()),
1356  'highscore_achieved_ts' => array('integer', (int)$this->getHighscoreAchievedTS()),
1357  'highscore_score' => array('integer', (int)$this->getHighscoreScore()),
1358  'highscore_percentage' => array('integer', (int)$this->getHighscorePercentage()),
1359  'highscore_hints' => array('integer', (int)$this->getHighscoreHints()),
1360  'highscore_wtime' => array('integer', (int)$this->getHighscoreWTime()),
1361  'highscore_own_table' => array('integer', (int)$this->getHighscoreOwnTable()),
1362  'highscore_top_table' => array('integer', (int)$this->getHighscoreTopTable()),
1363  'highscore_top_num' => array('integer', (int)$this->getHighscoreTopNum()),
1364  'online_status' => array('integer', (int)$this->isOnline()),
1365  'specific_feedback' => array('integer', (int)$this->getSpecificAnswerFeedback()),
1366  'autosave' => array('integer', (int)$this->getAutosave()),
1367  'autosave_ival' => array('integer', (int)$this->getAutosaveIval()),
1368  'pass_deletion_allowed' => array('integer', (int)$this->isPassDeletionAllowed()),
1369  'enable_examview' => array('integer', (int)$this->getEnableExamview()),
1370  'show_examview_html' => array('integer', (int)$this->getShowExamviewHtml()),
1371  'show_examview_pdf' => array('integer', (int)$this->getShowExamviewPdf()),
1372  'redirection_mode' => array('integer', (int)$this->getRedirectionMode()),
1373  'redirection_url' => array('text', (string)$this->getRedirectionUrl()),
1374  'enable_archiving' => array('integer', (int)$this->getEnableArchiving()),
1375  'examid_in_test_pass' => array('integer', (int)$this->isShowExamIdInTestPassEnabled()),
1376  'examid_in_test_res' => array('integer', (int)$this->isShowExamIdInTestResultsEnabled()),
1377  'sign_submission' => array('integer', (int)$this->getSignSubmission()),
1378  'question_set_type' => array('text', $this->getQuestionSetType()),
1379  'char_selector_availability' => array('integer', (int)$this->getCharSelectorAvailability()),
1380  'char_selector_definition' => array('text', (string)$this->getCharSelectorDefinition()),
1381  'skill_service' => array('integer', (int)$this->isSkillServiceEnabled()),
1382  'result_tax_filters' => array('text', serialize((array)$this->getResultFilterTaxIds())),
1383  'show_grading_status' => array('integer', (int)$this->isShowGradingStatusEnabled()),
1384  'show_grading_mark' => array('integer', (int)$this->isShowGradingMarkEnabled()),
1385  'inst_fb_answer_fixation' => array('integer', (int)$this->isInstantFeedbackAnswerFixationEnabled()),
1386  'broken' => array('integer', (int)$this->isTestFinalBroken())
1387  ));
1388 
1389  $this->test_id = $next_id;
1390 
1392  {
1393  $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1394  }
1395  }
1396  else
1397  {
1398  // Modify existing dataset
1399  $oldrow = array();
1401  {
1402  $result = $ilDB->queryF("SELECT * FROM tst_tests WHERE test_id = %s",
1403  array('integer'),
1404  array($this->test_id)
1405  );
1406  if ($result->numRows() == 1)
1407  {
1408  $oldrow = $ilDB->fetchAssoc($result);
1409  }
1410  }
1411 
1412  $ilDB->update('tst_tests',
1413  array(
1414  'author' => array('text', $this->getAuthor()),
1415  'intro_enabled' => array('integer', (int)$this->isIntroductionEnabled()),
1416  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1417  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1418  'showinfo' => array('integer', $this->getShowInfo()),
1419  'forcejs' => array('integer', $this->getForceJS()),
1420  'customstyle' => array('text', $this->getCustomStyle()),
1421  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1422  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1423  'score_reporting' => array('integer', $this->getScoreReporting()),
1424  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1425  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1426  'answer_feedback' => array('text', $this->getGenericAnswerFeedback()),
1427  'anonymity' => array('text', $this->getAnonymity()),
1428  'show_cancel' => array('text', $this->getShowCancel()),
1429  'show_marker' => array('integer', $this->getShowMarker()),
1430  'fixed_participants' => array('text', $this->getFixedParticipants()),
1431  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1432  'kiosk' => array('integer', $this->getKiosk()),
1433  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1434  'title_output' => array('text', $this->getTitleOutput()),
1435  'processing_time' => array('text', $this->getProcessingTime()),
1436  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1437  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1438  'reporting_date' => array('text', $this->getReportingDate()),
1439  'starting_time_enabled' => array('integer', $this->isStartingTimeEnabled()),
1440  'starting_time' => array('text', $this->getStartingTime()),
1441  'ending_time_enabled' => array('integer', $this->isEndingTimeEnabled()),
1442  'ending_time' => array('text', $this->getEndingTime()),
1443  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1444  'ects_output' => array('text', $this->getECTSOutput()),
1445  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : NULL),
1446  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : NULL),
1447  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : NULL),
1448  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : NULL),
1449  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : NULL),
1450  'ects_fx' => array('float', $this->getECTSFX()),
1451  'count_system' => array('text', $this->getCountSystem()),
1452  'mc_scoring' => array('text', $this->getMCScoring()),
1453  'score_cutting' => array('text', $this->getScoreCutting()),
1454  'pass_scoring' => array('text', $this->getPassScoring()),
1455  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1456  'results_presentation' => array('integer', $this->getResultsPresentation()),
1457  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1458  'password_enabled' => array('integer', (int)$this->isPasswordEnabled()),
1459  'password' => array('text', $this->getPassword()),
1460  'limit_users_enabled' => array('integer', (int)$this->isLimitUsersEnabled()),
1461  'allowedusers' => array('integer', $this->getAllowedUsers()),
1462  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1463  'mailnottype' => array('integer', $this->getMailNotificationType()),
1464  'exportsettings' => array('integer', $this->getExportSettings()),
1465  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1466  'mailnotification' => array('integer', $this->getMailNotification()),
1467  'tstamp' => array('integer', time()),
1468  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1469  'template_id' => array('integer', $this->getTemplate()),
1470  'pool_usage' => array('integer', $this->getPoolUsage()),
1471  'print_bs_with_res' => array('integer', (int)$this->isBestSolutionPrintedWithResult()),
1472  'obligations_enabled' => array('integer', (int)$this->areObligationsEnabled()),
1473  'offer_question_hints' => array('integer', (int)$this->isOfferingQuestionHintsEnabled()),
1474  'highscore_enabled' => array('integer', (int)$this->getHighscoreEnabled()),
1475  'highscore_anon' => array('integer', (int)$this->getHighscoreAnon()),
1476  'highscore_achieved_ts' => array('integer', (int)$this->getHighscoreAchievedTS()),
1477  'highscore_score' => array('integer', (int)$this->getHighscoreScore()),
1478  'highscore_percentage' => array('integer', (int)$this->getHighscorePercentage()),
1479  'highscore_hints' => array('integer', (int)$this->getHighscoreHints()),
1480  'highscore_wtime' => array('integer', (int)$this->getHighscoreWTime()),
1481  'highscore_own_table' => array('integer', (int)$this->getHighscoreOwnTable()),
1482  'highscore_top_table' => array('integer', (int)$this->getHighscoreTopTable()),
1483  'highscore_top_num' => array('integer', (int)$this->getHighscoreTopNum()),
1484  'online_status' => array('integer', (int)$this->isOnline()),
1485  'specific_feedback' => array('integer', (int)$this->getSpecificAnswerFeedback()),
1486  'autosave' => array('integer', (int)$this->getAutosave()),
1487  'autosave_ival' => array('integer', (int)$this->getAutosaveIval()),
1488  'pass_deletion_allowed' => array('integer', (int)$this->isPassDeletionAllowed()),
1489  'enable_examview' => array('integer', (int)$this->getEnableExamview()),
1490  'show_examview_html' => array('integer', (int)$this->getShowExamviewHtml()),
1491  'show_examview_pdf' => array('integer', (int)$this->getShowExamviewPdf()),
1492  'redirection_mode' => array('integer', (int)$this->getRedirectionMode()),
1493  'redirection_url' => array('text', (string)$this->getRedirectionUrl()),
1494  'enable_archiving' => array('integer', (int)$this->getEnableArchiving()),
1495  'examid_in_test_pass' => array('integer', (int)$this->isShowExamIdInTestPassEnabled()),
1496  'examid_in_test_res' => array('integer', (int)$this->isShowExamIdInTestResultsEnabled()),
1497  'sign_submission' => array('integer', (int)$this->getSignSubmission()),
1498  'question_set_type' => array('text', $this->getQuestionSetType()),
1499  'char_selector_availability' => array('integer', (int)$this->getCharSelectorAvailability()),
1500  'char_selector_definition' => array('text', (string)$this->getCharSelectorDefinition()),
1501  'skill_service' => array('integer', (int)$this->isSkillServiceEnabled()),
1502  'result_tax_filters' => array('text', serialize((array)$this->getResultFilterTaxIds())),
1503  'show_grading_status' => array('integer', (int)$this->isShowGradingStatusEnabled()),
1504  'show_grading_mark' => array('integer', (int)$this->isShowGradingMarkEnabled()),
1505  'inst_fb_answer_fixation' => array('integer', (int)$this->isInstantFeedbackAnswerFixationEnabled()),
1506  'broken' => array('integer', (int)$this->isTestFinalBroken())
1507  ),
1508  array(
1509  'test_id' => array('integer', (int)$this->getTestId())
1510  )
1511  );
1512 
1513  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1515  {
1516  $logresult = $ilDB->queryF("SELECT * FROM tst_tests WHERE test_id = %s",
1517  array('integer'),
1518  array($this->getTestId())
1519  );
1520  $newrow = array();
1521  if ($logresult->numRows() == 1)
1522  {
1523  $newrow = $ilDB->fetchAssoc($logresult);
1524  }
1525  $changed_fields = array();
1526  foreach ($oldrow as $key => $value)
1527  {
1528  if (strcmp($oldrow[$key], $newrow[$key]) != 0)
1529  {
1530  array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1531  }
1532  }
1533  $changes = join($changed_fields, ", ");
1534  if (count($changed_fields) > 0)
1535  {
1536  $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [".$changes."]");
1537  }
1538  }
1539  if ($this->evalTotalPersons() > 0)
1540  {
1541  // reset the finished status of participants if the nr of test passes did change
1542  if ($this->getNrOfTries() > 0)
1543  {
1544  // set all unfinished tests with nr of passes >= allowed passes finished
1545  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
1546  array('integer', 'integer', 'integer'),
1547  array($this->getTestId(), $this->getNrOfTries(), 0)
1548  );
1549  while ($row = $ilDB->fetchAssoc($aresult))
1550  {
1551  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1552  array('integer', 'timestamp', 'integer'),
1553  array(1, date('Y-m-d H:i:s'), $row["active_id"])
1554  );
1555  }
1556 
1557  // set all finished tests with nr of passes < allowed passes not finished
1558  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
1559  array('integer', 'integer', 'integer'),
1560  array($this->getTestId(), $this->getNrOfTries()-1, 1)
1561  );
1562  while ($row = $ilDB->fetchAssoc($aresult))
1563  {
1564  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1565  array('integer', 'timestamp', 'integer'),
1566  array(0, NULL, $row["active_id"])
1567  );
1568  }
1569  }
1570  else
1571  {
1572  // set all finished tests with nr of passes >= allowed passes not finished
1573  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
1574  array('integer', 'integer'),
1575  array($this->getTestId(), 1)
1576  );
1577  while ($row = $ilDB->fetchAssoc($aresult))
1578  {
1579  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1580  array('integer', 'timestamp', 'integer'),
1581  array(0, NULL, $row["active_id"])
1582  );
1583  }
1584  }
1585  }
1586  }
1587 
1588  // moved activation to ilObjectActivation
1589  if($this->ref_id)
1590  {
1591  include_once "./Services/Object/classes/class.ilObjectActivation.php";
1592  ilObjectActivation::getItem($this->ref_id);
1593 
1594  $item = new ilObjectActivation;
1595  if(!$this->isActivationLimited())
1596  {
1598  }
1599  else
1600  {
1601  $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
1602  $item->setTimingStart($this->getActivationStartingTime());
1603  $item->setTimingEnd($this->getActivationEndingTime());
1604  $item->toggleVisible($this->getActivationVisibility());
1605  }
1606 
1607  $item->update($this->ref_id);
1608  }
1609 
1610  if (!$properties_only)
1611  {
1612  if (PEAR::isError($result))
1613  {
1614  global $ilias;
1615  $ilias->raiseError($result->getMessage());
1616  }
1617  else
1618  {
1620  {
1621  $this->saveQuestionsToDb();
1622  }
1623  $this->mark_schema->saveToDb($this->test_id);
1624  }
1625  }
1626  }
1627 
1635  {
1636  global $ilDB;
1637 
1638  $oldquestions = array();
1639  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1641  {
1642  $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1643  array('integer'),
1644  array($this->getTestId())
1645  );
1646  if ($result->numRows() > 0)
1647  {
1648  while ($row = $ilDB->fetchAssoc($result))
1649  {
1650  array_push($oldquestions, $row["question_fi"]);
1651  }
1652  }
1653  }
1654  // workaround for lost obligations
1655  // this method is called if a question is removed
1656  $currentQuestionsObligationsQuery = 'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
1657  $rset = $ilDB->queryF($currentQuestionsObligationsQuery, array('integer'), array($this->getTestId()));
1658  while ($row = $ilDB->fetchAssoc($rset)) {
1659  $obligatoryQuestionState[$row['question_fi']] = $row['obligatory'];
1660  }
1661  // delete existing category relations
1662  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_question WHERE test_fi = %s",
1663  array('integer'),
1664  array($this->getTestId())
1665  );
1666  // create new category relations
1667  foreach ($this->questions as $key => $value)
1668  {
1669  // workaround for import witout obligations information
1670  if( !isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value]) )
1671  {
1672  $obligatoryQuestionState[$value] = 0;
1673  }
1674 
1675  // insert question
1676  $next_id = $ilDB->nextId('tst_test_question');
1677  $ilDB->insert('tst_test_question', array(
1678  'test_question_id' => array('integer', $next_id),
1679  'test_fi' => array('integer', $this->getTestId()),
1680  'question_fi' => array('integer', $value),
1681  'sequence' => array('integer', $key),
1682  'obligatory' => array('integer', $obligatoryQuestionState[$value]),
1683  'tstamp' => array('integer', time())
1684  ));
1685  }
1686  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1688  {
1689  $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1690  array('integer'),
1691  array($this->getTestId())
1692  );
1693  $newquestions = array();
1694  if ($result->numRows() > 0)
1695  {
1696  while ($row = $ilDB->fetchAssoc($result))
1697  {
1698  array_push($newquestions, $row["question_fi"]);
1699  }
1700  }
1701  foreach ($oldquestions as $index => $question_id)
1702  {
1703  if (strcmp($newquestions[$index], $question_id) != 0)
1704  {
1705  $pos = array_search($question_id, $newquestions);
1706  if ($pos === FALSE)
1707  {
1708  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1709  }
1710  else
1711  {
1712  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1) . " => " . ($pos+1), $question_id);
1713  }
1714  }
1715  }
1716  foreach ($newquestions as $index => $question_id)
1717  {
1718  if (array_search($question_id, $oldquestions) === FALSE)
1719  {
1720  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1), $question_id);
1721  }
1722  }
1723  }
1724  }
1725 
1731  protected function isNewRandomTest()
1732  {
1733  global $ilDB;
1734  $result = $ilDB->queryF('SELECT copy_id FROM tst_rnd_cpy WHERE tst_fi = %s',
1735  array('integer'),
1736  array($this->getTestId())
1737  );
1738  return $result->numRows() > 0;
1739  }
1740 
1753  function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = NULL)
1754  {
1755  global $rbacsystem;
1756  global $ilDB;
1757 
1758  // retrieve object id instead of ref id if necessary
1759  if (($questionpool != 0) && (!$use_obj_id)) $questionpool = ilObject::_lookupObjId($questionpool);
1760 
1761  // get original ids of all existing questions in the test
1762  $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",
1763  array("integer"),
1764  array($this->getTestId())
1765  );
1766  $original_ids = array();
1767  $paramtypes = array();
1768  $paramvalues = array();
1769  while ($row = $ilDB->fetchAssoc($result))
1770  {
1771  array_push($original_ids, $row['original_id']);
1772  }
1773 
1774  $available = "";
1775  // get a list of all available questionpools
1776  if (($questionpool == 0) && (!is_array($qpls)))
1777  {
1778  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1779  $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())));
1780  if (count($available_pools))
1781  {
1782  $available = " AND " . $ilDB->in('obj_fi', $available_pools, false, 'integer');
1783  }
1784  else
1785  {
1786  return array();
1787  }
1788  }
1789 
1790  $constraint_qpls = "";
1791  $result_array = array();
1792  if ($questionpool == 0)
1793  {
1794  if (is_array($qpls))
1795  {
1796  if (count($qpls) > 0)
1797  {
1798  $constraint_qpls = " AND " . $ilDB->in('obj_fi', $qpls, false, 'integer');
1799  }
1800  }
1801  }
1802 
1803  $original_clause = "";
1804  if (count($original_ids))
1805  {
1806  $original_clause = " AND " . $ilDB->in('question_id', $original_ids, true, 'integer');
1807  }
1808 
1809  if ($questionpool == 0)
1810  {
1811  $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",
1812  array('integer', 'text'),
1813  array(0, "1")
1814  );
1815  }
1816  else
1817  {
1818  $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",
1819  array('integer','integer', 'text'),
1820  array($questionpool, 0, "1")
1821  );
1822  }
1823  $found_ids = array();
1824  while ($row = $ilDB->fetchAssoc($result))
1825  {
1826  array_push($found_ids, $row['question_id']);
1827  }
1828  $nr_of_questions = ($nr_of_questions > count($found_ids)) ? count($found_ids) : $nr_of_questions;
1829  if ($nr_of_questions == 0) return array();
1830  $rand_keys = array_rand($found_ids, $nr_of_questions);
1831  $result = array();
1832  if (is_array($rand_keys))
1833  {
1834  foreach ($rand_keys as $key)
1835  {
1836  $result[$found_ids[$key]] = $found_ids[$key];
1837  }
1838  }
1839  else
1840  {
1841  $result[$found_ids[$rand_keys]] = $found_ids[$rand_keys];
1842  }
1843  return $result;
1844  }
1845 
1853  function getNrOfResultsForPass($active_id, $pass)
1854  {
1855  global $ilDB;
1856 
1857  $result = $ilDB->queryF("SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1858  array('integer','integer'),
1859  array($active_id, $pass)
1860  );
1861  return $result->numRows();
1862  }
1863 
1874  function hasRandomQuestionsForPass($active_id, $pass)
1875  {
1876  global $ilDB;
1877  $result = $ilDB->queryF("SELECT test_random_question_id FROM tst_test_rnd_qst WHERE active_fi = %s AND pass = %s",
1878  array('integer','integer'),
1879  array($active_id, $pass)
1880  );
1881  return ($result->numRows() > 0) ? true : false;
1882  }
1883 
1887  public function loadFromDb()
1888  {
1889  global $ilDB;
1890 
1891  $result = $ilDB->queryF("SELECT * FROM tst_tests WHERE obj_fi = %s",
1892  array('integer'),
1893  array($this->getId())
1894  );
1895  if ($result->numRows() == 1)
1896  {
1897  $data = $ilDB->fetchObject($result);
1898  $this->setTestId($data->test_id);
1899  if (strlen($this->getAuthor()) == 0)
1900  {
1901  $this->saveAuthorToMetadata($data->author);
1902  }
1903  $this->setAuthor($data->author);
1904  include_once("./Services/RTE/classes/class.ilRTE.php");
1905  $this->setIntroductionEnabled($data->intro_enabled);
1906  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc($data->introduction, 1));
1907  $this->setShowInfo($data->showinfo);
1908  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc($data->finalstatement, 1));
1909  $this->setForceJS($data->forcejs);
1910  $this->setCustomStyle($data->customstyle);
1911  $this->setShowFinalStatement($data->showfinalstatement);
1912  $this->setSequenceSettings($data->sequence_settings);
1913  $this->setScoreReporting($data->score_reporting);
1914  $this->setInstantFeedbackSolution($data->instant_verification);
1915  $this->setAnswerFeedbackPoints($data->answer_feedback_points);
1916  $this->setAnswerFeedback($data->answer_feedback);
1917  $this->setAnonymity($data->anonymity);
1918  $this->setShowCancel($data->show_cancel);
1919  $this->setShowMarker($data->show_marker);
1920  $this->setFixedParticipants($data->fixed_participants);
1921  $this->setNrOfTries($data->nr_of_tries);
1922  $this->setKiosk($data->kiosk);
1923  $this->setUsePreviousAnswers($data->use_previous_answers);
1924  $this->setRedirectionMode($data->redirection_mode);
1925  $this->setRedirectionUrl($data->redirection_url);
1926  $this->setTitleOutput($data->title_output);
1927  $this->setProcessingTime($data->processing_time);
1928  $this->setEnableProcessingTime($data->enable_processing_time);
1929  $this->setResetProcessingTime($data->reset_processing_time);
1930  $this->setReportingDate($data->reporting_date);
1931  $this->setShuffleQuestions($data->shuffle_questions);
1932  $this->setResultsPresentation($data->results_presentation);
1933  $this->setStartingTimeEnabled($data->starting_time_enabled);
1934  $this->setStartingTime($data->starting_time);
1935  $this->setEndingTimeEnabled($data->ending_time_enabled);
1936  $this->setEndingTime($data->ending_time);
1937  $this->setListOfQuestionsSettings($data->show_summary);
1938  $this->setECTSOutput($data->ects_output);
1939  $this->setECTSGrades(
1940  array(
1941  "A" => $data->ects_a,
1942  "B" => $data->ects_b,
1943  "C" => $data->ects_c,
1944  "D" => $data->ects_d,
1945  "E" => $data->ects_e
1946  )
1947  );
1948  $this->setECTSFX($data->ects_fx);
1949  $this->mark_schema->flush();
1950  $this->mark_schema->loadFromDb($this->getTestId());
1951  $this->setCountSystem($data->count_system);
1952  $this->setMCScoring($data->mc_scoring);
1953  $this->setMailNotification($data->mailnotification);
1954  $this->setMailNotificationType($data->mailnottype);
1955  $this->setExportSettings($data->exportsettings);
1956  $this->setScoreCutting($data->score_cutting);
1957  $this->setPasswordEnabled($data->password_enabled);
1958  $this->setPassword($data->password);
1959  $this->setLimitUsersEnabled($data->limit_users_enabled);
1960  $this->setAllowedUsers($data->allowedusers);
1961  $this->setAllowedUsersTimeGap($data->alloweduserstimegap);
1962  $this->setPassScoring($data->pass_scoring);
1963  $this->setObligationsEnabled($data->obligations_enabled);
1964  $this->setOfferingQuestionHintsEnabled($data->offer_question_hints);
1965  $this->setCertificateVisibility($data->certificate_visibility);
1966  $this->setEnabledViewMode($data->enabled_view_mode);
1967  $this->setTemplate($data->template_id);
1968  $this->setPoolUsage($data->pool_usage);
1969  $this->setPrintBestSolutionWithResult((bool) $data->print_bs_with_res);
1970  $this->setHighscoreEnabled((bool) $data->highscore_enabled);
1971  $this->setHighscoreAnon((bool) $data->highscore_anon);
1972  $this->setHighscoreAchievedTS((bool) $data->highscore_achieved_ts);
1973  $this->setHighscoreScore((bool) $data->highscore_score);
1974  $this->setHighscorePercentage((bool) $data->highscore_percentage);
1975  $this->setHighscoreHints((bool) $data->highscore_hints);
1976  $this->setHighscoreWTime((bool) $data->highscore_wtime);
1977  $this->setHighscoreOwnTable((bool) $data->highscore_own_table);
1978  $this->setHighscoreTopTable((bool) $data->highscore_top_table);
1979  $this->setHighscoreTopNum((int) $data->highscore_top_num);
1980  $this->setOnline((bool) $data->online_status);
1981  $this->setSpecificAnswerFeedback((int) $data->specific_feedback);
1982  $this->setAutosave((bool)$data->autosave);
1983  $this->setAutosaveIval((int)$data->autosave_ival);
1984  $this->setPassDeletionAllowed($data->pass_deletion_allowed);
1985  $this->setEnableExamview((bool)$data->enable_examview);
1986  $this->setShowExamviewHtml((bool)$data->show_examview_html);
1987  $this->setShowExamviewPdf((bool)$data->show_examview_pdf);
1988  $this->setEnableArchiving((bool)$data->enable_archiving);
1989  $this->setShowExamIdInTestPassEnabled( (bool)$data->examid_in_test_pass);
1990  $this->setShowExamIdInTestResultsEnabled( (bool)$data->examid_in_test_res);
1991  $this->setSignSubmission( (bool)$data->sign_submission );
1992  $this->setQuestionSetType($data->question_set_type);
1993  $this->setCharSelectorAvailability((int)$data->char_selector_availability);
1994  $this->setCharSelectorDefinition($data->char_selector_definition);
1995  $this->setSkillServiceEnabled((bool)$data->skill_service);
1996  $this->setResultFilterTaxIds(strlen($data->result_tax_filters) ? unserialize($data->result_tax_filters) : array());
1997  $this->setShowGradingStatusEnabled((bool)$data->show_grading_status);
1998  $this->setShowGradingMarkEnabled((bool)$data->show_grading_mark);
1999  $this->setInstantFeedbackAnswerFixationEnabled((bool)$data->inst_fb_answer_fixation);
2000  $this->setTestFinalBroken((bool)$data->broken);
2001  $this->loadQuestions();
2002  }
2003 
2004  // moved activation to ilObjectActivation
2005  if($this->ref_id)
2006  {
2007  include_once "./Services/Object/classes/class.ilObjectActivation.php";
2008  $activation = ilObjectActivation::getItem($this->ref_id);
2009  switch($activation["timing_type"])
2010  {
2012  $this->setActivationLimited(true);
2013  $this->setActivationStartingTime($activation["timing_start"]);
2014  $this->setActivationEndingTime($activation["timing_end"]);
2015  $this->setActivationVisibility($activation["visible"]);
2016  break;
2017 
2018  default:
2019  $this->setActivationLimited(false);
2020  break;
2021  }
2022  }
2023  }
2024 
2031 function loadQuestions($active_id = "", $pass = NULL)
2032 {
2033  global $ilUser;
2034  global $ilDB;
2035 
2036  $this->questions = array();
2037  if (strcmp($active_id, "") == 0)
2038  {
2039  $active_id = $this->getActiveIdOfUser($ilUser->getId());
2040  }
2041  if ($this->isRandomTest())
2042  {
2043  if (is_null($pass))
2044  {
2045  $pass = $this->_getPass($active_id);
2046  }
2047  $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",
2048  array('integer', 'integer'),
2049  array($active_id, $pass)
2050  );
2051  // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
2052  // is only one test pass (pass = 0) in tst_test_rnd_qst while with ILIAS 3.8 there are questions for every test pass.
2053  // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
2054  // no questions are present for a newer pass.
2055  if ($result->numRows() == 0)
2056  {
2057  $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",
2058  array('integer'),
2059  array($active_id)
2060  );
2061  }
2062  }
2063  else
2064  {
2065  $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",
2066  array('integer'),
2067  array($this->test_id)
2068  );
2069  }
2070  $index = 1;
2071  while ($data = $ilDB->fetchAssoc($result))
2072  {
2073  $this->questions[$index++] = $data["question_fi"];
2074  }
2075 }
2076 
2080  public function isIntroductionEnabled()
2081  {
2083  }
2084 
2089  {
2090  $this->introductionEnabled = $introductionEnabled;
2091  }
2092 
2099  public function getIntroduction()
2100  {
2101  return (strlen($this->introduction)) ? $this->introduction : NULL;
2102  }
2103 
2111  public function setIntroduction($introduction = "")
2112  {
2113  $this->introduction = $introduction;
2114  }
2115 
2116 
2124  public function setFinalStatement($a_statement = "")
2125  {
2126  $this->_finalstatement = $a_statement;
2127  }
2128 
2136  public function setShowInfo($a_info = 1)
2137  {
2138  $this->_showinfo = ($a_info) ? 1 : 0;
2139  }
2140 
2148  public function setForceJS($a_js = 1)
2149  {
2150  $this->_forcejs = ($a_js) ? 1 : 0;
2151  }
2152 
2160  public function setCustomStyle($a_customStyle = NULL)
2161  {
2162  $this->_customStyle = $a_customStyle;
2163  }
2164 
2172  public function getCustomStyle()
2173  {
2174  return (strlen($this->_customStyle)) ? $this->_customStyle : NULL;
2175  }
2176 
2184  public function getCustomStyles()
2185  {
2186  $css_path = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2187  $css_path = str_replace("ta.css", "customstyles", $css_path) . "/";
2188  $customstyles = array();
2189  if (is_dir($css_path))
2190  {
2191  $results = array();
2192  include_once "./Services/Utilities/classes/class.ilFileUtils.php";
2194  if (is_array($results["file"]))
2195  {
2196  foreach ($results["file"] as $filename)
2197  {
2198  if (strpos($filename, ".css"))
2199  {
2200  array_push($customstyles, $filename);
2201  }
2202  }
2203  }
2204  }
2205  return $customstyles;
2206  }
2207 
2215  public function getTestStyleLocation($mode = "output")
2216  {
2217  if (strlen($this->getCustomStyle()))
2218  {
2219  $default = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2220  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $default);
2221  if (file_exists($custom))
2222  {
2223  $custom = ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2224  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $custom);
2225  return $custom;
2226  }
2227  else
2228  {
2229  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2230  }
2231  }
2232  else
2233  {
2234  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2235  }
2236  }
2237 
2245  public function setShowFinalStatement($show = 0)
2246  {
2247  $this->_showfinalstatement = ($show) ? 1 : 0;
2248  }
2249 
2256  public function getFinalStatement()
2257  {
2258  return (strlen($this->_finalstatement)) ? $this->_finalstatement : NULL;
2259  }
2260 
2268  public function getShowInfo()
2269  {
2270  return ($this->_showinfo) ? 1 : 0;
2271  }
2272 
2280  public function getForceJS()
2281  {
2282  return ($this->_forcejs) ? 1 : 0;
2283  }
2284 
2292  public function getShowFinalStatement()
2293  {
2294  return ($this->_showfinalstatement) ? 1 : 0;
2295  }
2296 
2304  function getTestId()
2305  {
2306  return $this->test_id;
2307  }
2308 
2312  public function getECTSOutput()
2313  {
2314  return ($this->ects_output) ? 1 : 0;
2315  }
2316 
2320  public function setECTSOutput($a_ects_output)
2321  {
2322  $this->ects_output = $a_ects_output ? 1 : 0;
2323  }
2324 
2328  public function getECTSFX()
2329  {
2330  return (strlen($this->ects_fx)) ? $this->ects_fx : NULL;
2331  }
2332 
2336  public function setECTSFX($a_ects_fx)
2337  {
2338  $this->ects_fx = $a_ects_fx;
2339  }
2340 
2344  public function getECTSGrades()
2345  {
2346  return $this->ects_grades;
2347  }
2348 
2352  public function setECTSGrades(array $a_ects_grades)
2353  {
2354  $this->ects_grades = $a_ects_grades;
2355  }
2356 
2362  public function getSequenceSettings()
2363  {
2364  return ($this->sequence_settings) ? $this->sequence_settings : 0;
2365  }
2366 
2373  {
2374  $this->sequence_settings = $sequence_settings;
2375  }
2376 
2380  public function isPostponingEnabled()
2381  {
2382  return (bool)$this->getSequenceSettings();
2383  }
2384 
2388  public function setPostponingEnabled($postponingEnabled)
2389  {
2390  $this->setSequenceSettings((int)$postponingEnabled);
2391  }
2392 
2401  {
2402  $this->score_reporting = $score_reporting;
2403  }
2404 
2412  function setInstantFeedbackSolution($instant_feedback = 0)
2413  {
2414  switch ($instant_feedback)
2415  {
2416  case 1:
2417  $this->instant_verification = 1;
2418  break;
2419  default:
2420  $this->instant_verification = 0;
2421  break;
2422  }
2423  }
2424 
2433 {
2434  switch ($answer_feedback)
2435  {
2436  case 1:
2437  $this->answer_feedback = 1;
2438  break;
2439  default:
2440  $this->answer_feedback = 0;
2441  break;
2442  }
2443 }
2444 
2451 function setGenericAnswerFeedback($generic_answer_feedback = 0)
2452 {
2453  switch ($generic_answer_feedback)
2454  {
2455  case 1:
2456  $this->answer_feedback = 1;
2457  break;
2458  default:
2459  $this->answer_feedback = 0;
2460  break;
2461  }
2462 }
2463 
2472  {
2473  switch ($answer_feedback_points)
2474  {
2475  case 1:
2476  $this->answer_feedback_points = 1;
2477  break;
2478  default:
2479  $this->answer_feedback_points = 0;
2480  break;
2481  }
2482  }
2483 
2489  {
2490  if(!$reporting_date)
2491  {
2492  $this->reporting_date = '';
2493  $this->setECTSOutput(false);
2494  }
2495  else
2496  {
2497  $this->reporting_date = $reporting_date;
2498  }
2499  }
2500 
2505 
2514  {
2515  return ($this->score_reporting) ? $this->score_reporting : 0;
2516  }
2517 
2518  public function isScoreReportingEnabled()
2519  {
2520  return $this->getScoreReporting() > 0 && $this->getScoreReporting() < 4;
2521  }
2522 
2531  {
2532  return ($this->instant_verification) ? $this->instant_verification : 0;
2533  }
2534 
2543  public function getAnswerFeedback()
2544  {
2545  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2546  }
2547 
2556  public function getGenericAnswerFeedback()
2557  {
2558  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2559  }
2560 
2569 {
2570  return ($this->answer_feedback_points) ? $this->answer_feedback_points : 0;
2571 }
2572 
2580  function getCountSystem()
2581  {
2582  return ($this->count_system) ? $this->count_system : 0;
2583  }
2584 
2592  function _getCountSystem($active_id)
2593  {
2594  global $ilDB;
2595  $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",
2596  array('integer'),
2597  array($active_id)
2598  );
2599  if ($result->numRows())
2600  {
2601  $row = $ilDB->fetchAssoc($result);
2602  return $row["count_system"];
2603  }
2604  return FALSE;
2605  }
2606 
2614  function getMCScoring()
2615  {
2616  return ($this->mc_scoring) ? $this->mc_scoring : 0;
2617  }
2618 
2626  function getScoreCutting()
2627  {
2628  return ($this->score_cutting) ? $this->score_cutting : 0;
2629  }
2630 
2638  function getPassScoring()
2639  {
2640  return ($this->pass_scoring) ? $this->pass_scoring : 0;
2641  }
2642 
2650  function _getPassScoring($active_id)
2651  {
2652  global $ilDB;
2653  $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",
2654  array('integer'),
2655  array($active_id)
2656  );
2657  if ($result->numRows())
2658  {
2659  $row = $ilDB->fetchAssoc($result);
2660  return $row["pass_scoring"];
2661  }
2662  return 0;
2663  }
2664 
2672  function _getMCScoring($active_id)
2673  {
2674  global $ilDB;
2675  $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",
2676  array('integer'),
2677  array($active_id)
2678  );
2679  if ($result->numRows())
2680  {
2681  $row = $ilDB->fetchAssoc($result);
2682  return $row["mc_scoring"];
2683  }
2684  return FALSE;
2685  }
2686 
2694  function _getScoreCutting($active_id)
2695  {
2696  global $ilDB;
2697  $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",
2698  array('integer'),
2699  array($active_id)
2700  );
2701  if ($result->numRows())
2702  {
2703  $row = $ilDB->fetchAssoc($result);
2704  return $row["score_cutting"];
2705  }
2706  return FALSE;
2707  }
2708 
2716  function getReportingDate()
2717  {
2718  return (strlen($this->reporting_date)) ? $this->reporting_date : NULL;
2719  }
2720 
2728  function getNrOfTries()
2729  {
2730  return ($this->nr_of_tries) ? $this->nr_of_tries : 0;
2731  }
2732 
2740  function getKiosk()
2741  {
2742  return ($this->_kiosk) ? $this->_kiosk : 0;
2743  }
2744 
2745 
2753  function setKiosk($kiosk = 0)
2754  {
2755  $this->_kiosk = $kiosk;
2756  }
2757 
2765  function getKioskMode()
2766  {
2767  if (($this->_kiosk & 1) > 0)
2768  {
2769  return TRUE;
2770  }
2771  else
2772  {
2773  return FALSE;
2774  }
2775  }
2776 
2784  public function setKioskMode($a_kiosk = FALSE)
2785  {
2786  if ($a_kiosk)
2787  {
2788  $this->_kiosk = $this->_kiosk | 1;
2789  }
2790  else
2791  {
2792  if ($this->getKioskMode())
2793  {
2794  $this->_kiosk = $this->_kiosk ^ 1;
2795  }
2796  }
2797  }
2798 
2806  public function getShowKioskModeTitle()
2807  {
2808  if (($this->_kiosk & 2) > 0)
2809  {
2810  return TRUE;
2811  }
2812  else
2813  {
2814  return FALSE;
2815  }
2816  }
2817 
2824  public function setShowKioskModeTitle($a_title = FALSE)
2825  {
2826  if ($a_title)
2827  {
2828  $this->_kiosk = $this->_kiosk | 2;
2829  }
2830  else
2831  {
2832  if ($this->getShowKioskModeTitle())
2833  {
2834  $this->_kiosk = $this->_kiosk ^ 2;
2835  }
2836  }
2837  }
2838 
2847  {
2848  if (($this->_kiosk & 4) > 0)
2849  {
2850  return TRUE;
2851  }
2852  else
2853  {
2854  return FALSE;
2855  }
2856  }
2857 
2864  public function setShowKioskModeParticipant($a_participant = FALSE)
2865  {
2866  if ($a_participant)
2867  {
2868  $this->_kiosk = $this->_kiosk | 4;
2869  }
2870  else
2871  {
2872  if ($this->getShowKioskModeParticipant())
2873  {
2874  $this->_kiosk = $this->_kiosk ^ 4;
2875  }
2876  }
2877  }
2878 
2887  {
2888  return ($this->use_previous_answers) ? $this->use_previous_answers : 0;
2889  }
2890 
2898  function getTitleOutput()
2899  {
2900  return ($this->title_output) ? $this->title_output : 0;
2901  }
2902 
2911  function _getTitleOutput($active_id)
2912  {
2913  global $ilDB;
2914 
2915  $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",
2916  array('integer'),
2917  array($active_id)
2918  );
2919  if ($result->numRows())
2920  {
2921  $row = $ilDB->fetchAssoc($result);
2922  return $row["title_output"];
2923  }
2924  return 0;
2925  }
2926 
2936  function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
2937  {
2938  global $ilDB;
2939  global $ilUser;
2940 
2942 
2943  $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",
2944  array("integer"),
2945  array($active_id)
2946  );
2947  if ($result->numRows())
2948  {
2949  $row = $ilDB->fetchAssoc($result);
2950  $use_previous_answers = $row["use_previous_answers"];
2951  }
2952 
2953  if ($use_previous_answers == 1)
2954  {
2955  if ($user_active_user_setting)
2956  {
2957  $res = $ilUser->getPref("tst_use_previous_answers");
2958  if ($res !== FALSE)
2959  {
2961  }
2962  }
2963  }
2964  return $use_previous_answers;
2965  }
2966 
2975  {
2976  return (strlen($this->processing_time)) ? $this->processing_time : NULL;
2977  }
2978 
2985  public function getProcessingTimeAsArray()
2986  {
2987  if (strlen($this->processing_time))
2988  {
2989  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches))
2990  {
2991  if ((int)$matches[1]+(int)$matches[2]+(int)$matches[3] == 0)
2992  {
2993  return $this->getEstimatedWorkingTime();
2994  }
2995  else
2996  {
2997  return array(
2998  'hh' => $matches[1],
2999  'mm' => $matches[2],
3000  'ss' => $matches[3],
3001  );
3002  }
3003  }
3004  }
3005  return $this->getEstimatedWorkingTime();
3006  }
3007 
3008  public function getProcessingTimeAsMinutes()
3009  {
3010  if (strlen($this->processing_time))
3011  {
3012  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches))
3013  {
3014  return ($matches[1] * 60) + $matches[2];
3015  }
3016  }
3017 
3019  }
3020 
3028  function getProcessingTimeInSeconds($active_id = "")
3029  {
3030  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches))
3031  {
3032  $extratime = $this->getExtraTime($active_id) * 60;
3033  return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
3034  }
3035  else
3036  {
3037  return 0;
3038  }
3039  }
3040 
3049  {
3050  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndingTime(), $matches))
3051  {
3052  $ending = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
3053  $now = time();
3054  return $ending - $now;
3055  }
3056  else
3057  {
3058  return 0;
3059  }
3060  }
3061 
3070  {
3071  return ($this->enable_processing_time) ? $this->enable_processing_time : 0;
3072  }
3073 
3082  {
3083  return ($this->reset_processing_time) ? $this->reset_processing_time : 0;
3084  }
3085 
3089  public function isStartingTimeEnabled()
3090  {
3092  }
3093 
3098  {
3099  $this->starting_time_enabled = $starting_time_enabled;
3100  }
3101 
3109  public function getStartingTime()
3110  {
3111  return (strlen($this->starting_time)) ? $this->starting_time : NULL;
3112  }
3113 
3121  public function setStartingTime($starting_time = NULL)
3122  {
3123  $this->starting_time = $starting_time;
3124  }
3125 
3129  public function isEndingTimeEnabled()
3130  {
3132  }
3133 
3138  {
3139  $this->ending_time_enabled = $ending_time_enabled;
3140  }
3141 
3149  public function getEndingTime()
3150  {
3151  return (strlen($this->ending_time)) ? $this->ending_time : NULL;
3152  }
3153 
3161  public function setEndingTime($ending_time = NULL)
3162  {
3163  $this->ending_time = $ending_time;
3164  }
3165 
3174  {
3175  $this->nr_of_tries = $nr_of_tries;
3176  }
3177 
3186  {
3188  {
3189  $this->use_previous_answers = 1;
3190  }
3191  else
3192  {
3193  $this->use_previous_answers = 0;
3194  }
3195  }
3196 
3198  {
3199  $this->redirection_mode = $redirection_mode;
3200  }
3202  {
3203  return $this->redirection_mode;
3204  }
3206  {
3207  $this->redirection_url = $redirection_url;
3208  }
3210  {
3211  return $this->redirection_url;
3212  }
3213 
3222  {
3223  switch ($title_output)
3224  {
3225  case 1:
3226  $this->title_output = 1;
3227  break;
3228  case 2:
3229  $this->title_output = 2;
3230  break;
3231  default:
3232  $this->title_output = 0;
3233  break;
3234  }
3235  }
3236 
3244  function setProcessingTime($processing_time = "00:00:00")
3245  {
3246  $this->processing_time = $processing_time;
3247  }
3248 
3249  public function setProcessingTimeByMinutes($minutes)
3250  {
3251  $this->processing_time = sprintf("%02d:%02d:00", floor($minutes/60), $minutes%60);
3252  }
3253 
3261  function setEnableProcessingTime($enable = 0)
3262  {
3263  if ($enable) {
3264  $this->enable_processing_time = "1";
3265  } else {
3266  $this->enable_processing_time = "0";
3267  }
3268  }
3269 
3277  function setResetProcessingTime($reset = 0)
3278  {
3279  if ($reset)
3280  {
3281  $this->reset_processing_time = 1;
3282  }
3283  else
3284  {
3285  $this->reset_processing_time = 0;
3286  }
3287  }
3288 
3296  function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3297  {
3298  $this->count_system = $a_count_system;
3299  }
3300 
3304  public function isPasswordEnabled()
3305  {
3306  return $this->passwordEnabled;
3307  }
3308 
3313  {
3314  $this->passwordEnabled = $passwordEnabled;
3315  }
3316 
3324  public function getPassword()
3325  {
3326  return (strlen($this->password)) ? $this->password : NULL;
3327  }
3328 
3336  public function setPassword($a_password = NULL)
3337  {
3338  $this->password = $a_password;
3339  }
3340 
3348  function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3349  {
3350  $this->score_cutting = $a_score_cutting;
3351  }
3352 
3361  {
3362  $this->mc_scoring = $a_mc_scoring;
3363  }
3364 
3372  function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3373  {
3374  switch ($a_pass_scoring)
3375  {
3376  case SCORE_BEST_PASS:
3377  $this->pass_scoring = SCORE_BEST_PASS;
3378  break;
3379  default:
3380  $this->pass_scoring = SCORE_LAST_PASS;
3381  break;
3382  }
3383  }
3384 
3392  function removeQuestion($question_id)
3393  {
3394  $question =& ilObjTest::_instanciateQuestion($question_id);
3395  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3397  {
3398  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3399  }
3400  $question->delete($question_id);
3401  $this->removeAllTestEditings($question_id);
3402  $this->loadQuestions();
3403  $this->saveQuestionsToDb();
3404  }
3405 
3413  public function removeAllTestEditings($question_id = "")
3414  {
3415  global $ilDB;
3416 
3417  // remove the question from tst_solutions
3418  if ($question_id)
3419  {
3420  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE tst_solutions.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s) AND tst_solutions.question_fi = %s",
3421  array('integer','integer'),
3422  array($this->getTestId(), $question_id)
3423  );
3424  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_qst_solved WHERE tst_qst_solved.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s) AND tst_qst_solved.question_fi = %s",
3425  array('integer','integer'),
3426  array($this->getTestId(), $question_id)
3427  );
3428  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_result WHERE tst_test_result.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s) AND tst_test_result.question_fi = %s",
3429  array('integer','integer'),
3430  array($this->getTestId(), $question_id)
3431  );
3432  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_pass_result WHERE tst_pass_result.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3433  array('integer'),
3434  array($this->getTestId())
3435  );
3436 
3437  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3439  }
3440  else
3441  {
3442  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE tst_solutions.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3443  array('integer'),
3444  array($this->getTestId())
3445  );
3446  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_qst_solved WHERE tst_qst_solved.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3447  array('integer'),
3448  array($this->getTestId())
3449  );
3450  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_result WHERE tst_test_result.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3451  array('integer'),
3452  array($this->getTestId())
3453  );
3454  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_pass_result WHERE tst_pass_result.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3455  array('integer'),
3456  array($this->getTestId())
3457  );
3458 
3459  $query = "SELECT active_id FROM tst_active WHERE test_fi = %s";
3460  $res = $ilDB->queryF($query, array('integer'), array($this->getTestId()));
3461  $activeIds = array();
3462  while( $row = $ilDB->fetchAssoc($res) )
3463  {
3464  $activeIds[] = $row['active_id'];
3465  }
3466 
3467  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3469 
3470  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3472  {
3473  $this->logAction($this->lng->txtlng("assessment", "log_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()));
3474  }
3475  }
3476 
3477  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_sequence WHERE tst_sequence.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3478  array('integer'),
3479  array($this->getTestId())
3480  );
3481 
3482  if ($this->isRandomTest())
3483  {
3484  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_rnd_qst WHERE tst_test_rnd_qst.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3485  array('integer'),
3486  array($this->getTestId())
3487  );
3488  }
3489 
3490  // remove test_active entries, because test has changed
3491  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE test_fi = %s",
3492  array('integer'),
3493  array($this->getTestId())
3494  );
3495 
3496  // remove saved user passwords
3497  $affectedRows = $ilDB->manipulateF("DELETE FROM usr_pref WHERE keyword = %s",
3498  array('text'),
3499  array("tst_password_".$this->getTestId())
3500  );
3501 
3502  // TODO: this shouldn't be here since it is question stuff and should be modular but there's no other solution yet
3503  // remove file uploads
3504  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId()))
3505  {
3506  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId());
3507  }
3508  }
3509 
3510  public function removeTestResults(ilTestParticipantData $participantData)
3511  {
3512  if( count($participantData->getAnonymousActiveIds()) )
3513  {
3514  $this->removeTestResultsByActiveIds($participantData->getAnonymousActiveIds());
3515  }
3516 
3517  if( count($participantData->getUserIds()) )
3518  {
3519  /* @var ilTestLP $testLP */
3520  require_once 'Services/Object/classes/class.ilObjectLP.php';
3521  $testLP = ilObjectLP::getInstance($this->getId());
3522  $testLP->resetLPDataForUserIds($participantData->getUserIds(), false);
3523  }
3524 
3525  if( count($participantData->getActiveIds()) )
3526  {
3527  $this->removeTestActives($participantData->getActiveIds());
3528  }
3529  }
3530 
3531  public function removeTestResultsByUserIds($userIds)
3532  {
3533  global $ilDB, $lng;
3534 
3535  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3536  $participantData = new ilTestParticipantData($ilDB, $lng);
3537  $participantData->setUserIds($userIds);
3538  $participantData->load($this->getTestId());
3539 
3540  $IN_userIds = $ilDB->in('usr_id', $participantData->getUserIds(), false, 'integer');
3541  $ilDB->manipulateF("DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
3542  array('text'), array("tst_password_".$this->getTestId())
3543  );
3544 
3545  if( count($participantData->getActiveIds()) )
3546  {
3547  $this->removeTestResultsByActiveIds($participantData->getActiveIds());
3548  }
3549  }
3550 
3551  public function removeTestResultsByActiveIds($activeIds)
3552  {
3553  global $ilDB;
3554 
3555  $IN_activeIds = $ilDB->in('active_fi', $activeIds, false, 'integer');
3556 
3557  $ilDB->manipulate("DELETE FROM tst_solutions WHERE $IN_activeIds");
3558  $ilDB->manipulate("DELETE FROM tst_qst_solved WHERE $IN_activeIds");
3559  $ilDB->manipulate("DELETE FROM tst_test_result WHERE $IN_activeIds");
3560  $ilDB->manipulate("DELETE FROM tst_pass_result WHERE $IN_activeIds");
3561  $ilDB->manipulate("DELETE FROM tst_result_cache WHERE $IN_activeIds");
3562  $ilDB->manipulate("DELETE FROM tst_sequence WHERE $IN_activeIds");
3563 
3564  if( $this->isRandomTest() )
3565  {
3566  $ilDB->manipulate("DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
3567  }
3568  elseif( $this->isDynamicTest() )
3569  {
3570  $ilDB->manipulate("DELETE FROM tst_seq_qst_tracking WHERE $IN_activeIds");
3571  $ilDB->manipulate("DELETE FROM tst_seq_qst_answstatus WHERE $IN_activeIds");
3572  $ilDB->manipulate("DELETE FROM tst_seq_qst_postponed WHERE $IN_activeIds");
3573  $ilDB->manipulate("DELETE FROM tst_seq_qst_checked WHERE $IN_activeIds");
3574  }
3575 
3576  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3577 
3578  foreach ($activeIds as $active_id)
3579  {
3580  // TODO: this shouldn't be here since it is question stuff and should be modular but there's no other solution yet
3581  // remove file uploads
3582  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id"))
3583  {
3584  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3585  }
3586 
3588  {
3589  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3590  }
3591  }
3592 
3593  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3595  }
3596 
3597  public function removeTestActives($activeIds)
3598  {
3599  global $ilDB;
3600 
3601  $IN_activeIds = $ilDB->in('active_id', $activeIds, false, 'integer');
3602  $ilDB->manipulate("DELETE FROM tst_active WHERE $IN_activeIds");
3603  }
3604 
3605  function removeTestResultsForUser($user_id)
3606  {
3607  global $ilDB;
3608 
3609  $active_id = $this->getActiveIdOfUser($user_id);
3610 
3611  // remove the question from tst_solutions
3612  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s",
3613  array('integer'),
3614  array($active_id)
3615  );
3616  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_qst_solved WHERE active_fi = %s",
3617  array('integer'),
3618  array($active_id)
3619  );
3620  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_result WHERE active_fi = %s",
3621  array('integer'),
3622  array($active_id)
3623  );
3624  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_pass_result WHERE active_fi = %s",
3625  array('integer'),
3626  array($active_id)
3627  );
3628 
3629  if ($this->isRandomTest())
3630  {
3631  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_rnd_qst WHERE active_fi = %s",
3632  array('integer'),
3633  array($active_id)
3634  );
3635  }
3636 
3637  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3639  {
3640  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3641  }
3642 
3643  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_sequence WHERE active_fi = %s",
3644  array('integer'),
3645  array($active_id)
3646  );
3647 
3648  // remove test_active entry
3649  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE active_id = %s",
3650  array('integer'),
3651  array($active_id)
3652  );
3653 
3654  // remove saved user password
3655  if ($user_id > 0)
3656  {
3657  $affectedRows = $ilDB->manipulateF("DELETE FROM usr_pref WHERE usr_id = %s AND keyword = %s",
3658  array('integer', 'text'),
3659  array($user_id, "tst_password_".$this->getTestId())
3660  );
3661  }
3662 
3663  // TODO: this shouldn't be here since it is question stuff and should be modular but there's no other solution yet
3664  // remove file uploads
3665  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id"))
3666  {
3667  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3668  }
3669 
3670  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3672  }
3673 
3681  function questionMoveUp($question_id)
3682  {
3683  global $ilDB;
3684 
3685  // Move a question up in sequence
3686  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3687  array('integer', 'integer'),
3688  array($this->getTestId(), $question_id)
3689  );
3690  $data = $ilDB->fetchObject($result);
3691  if ($data->sequence > 1)
3692  {
3693  // OK, it's not the top question, so move it up
3694  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3695  array('integer','integer'),
3696  array($this->getTestId(), $data->sequence - 1)
3697  );
3698  $data_previous = $ilDB->fetchObject($result);
3699  // change previous dataset
3700  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3701  array('integer','integer'),
3702  array($data->sequence, $data_previous->test_question_id)
3703  );
3704  // move actual dataset up
3705  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3706  array('integer','integer'),
3707  array($data->sequence - 1, $data->test_question_id)
3708  );
3709  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3711  {
3712  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence-1), $question_id);
3713  }
3714  }
3715  $this->loadQuestions();
3716  }
3717 
3725  function questionMoveDown($question_id)
3726  {
3727  global $ilDB;
3728 
3729  // Move a question down in sequence
3730  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3731  array('integer','integer'),
3732  array($this->getTestId(), $question_id)
3733  );
3734  $data = $ilDB->fetchObject($result);
3735  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3736  array('integer','integer'),
3737  array($this->getTestId(), $data->sequence + 1)
3738  );
3739  if ($result->numRows() == 1)
3740  {
3741  // OK, it's not the last question, so move it down
3742  $data_next = $ilDB->fetchObject($result);
3743  // change next dataset
3744  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3745  array('integer','integer'),
3746  array($data->sequence, $data_next->test_question_id)
3747  );
3748  // move actual dataset down
3749  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3750  array('integer','integer'),
3751  array($data->sequence + 1, $data->test_question_id)
3752  );
3753  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3755  {
3756  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence+1), $question_id);
3757  }
3758  }
3759  $this->loadQuestions();
3760  }
3761 
3769  function duplicateQuestionForTest($question_id)
3770  {
3771  global $ilUser;
3772  $question =& ilObjTest::_instanciateQuestion($question_id);
3773  $duplicate_id = $question->duplicate(true, null, null, null, $this->getId());
3774 
3775  return $duplicate_id;
3776  }
3777 
3786  public function insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly = false)
3787  {
3788  global $ilDB;
3789 #var_dump($question_id);
3790  if ($linkOnly)
3791  {
3792  $duplicate_id = $question_id;
3793  }
3794  else
3795  {
3796  $duplicate_id = $this->duplicateQuestionForTest($question_id);
3797  }
3798 
3799  // get maximum sequence index in test
3800  $result = $ilDB->queryF("SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
3801  array('integer'),
3802  array($this->getTestId())
3803  );
3804  $sequence = 1;
3805 
3806  if ($result->numRows() == 1)
3807  {
3808  $data = $ilDB->fetchObject($result);
3809  $sequence = $data->seq + 1;
3810  }
3811 
3812  $next_id = $ilDB->nextId('tst_test_question');
3813  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
3814  array('integer', 'integer','integer','integer','integer'),
3815  array($next_id, $this->getTestId(), $duplicate_id, $sequence, time())
3816  );
3817  if ($affectedRows == 1)
3818  {
3819  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3821  {
3822  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3823  }
3824  }
3825  // remove test_active entries, because test has changed
3826  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE test_fi = %s",
3827  array('integer'),
3828  array($this->getTestId())
3829  );
3830  $this->loadQuestions();
3831  $this->saveCompleteStatus($testQuestionSetConfig);
3832  return $duplicate_id;
3833  }
3834 
3842  function &getQuestionTitles()
3843  {
3844  $titles = array();
3845  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED)
3846  {
3847  global $ilDB;
3848  $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",
3849  array('integer'),
3850  array($this->getTestId())
3851  );
3852  while ($row = $ilDB->fetchAssoc($result))
3853  {
3854  array_push($titles, $row["title"]);
3855  }
3856  }
3857  return $titles;
3858  }
3859 
3868  {
3869  $titles = array();
3870  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED)
3871  {
3872  global $ilDB;
3873  $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",
3874  array('integer'),
3875  array($this->getTestId())
3876  );
3877  while ($row = $ilDB->fetchAssoc($result))
3878  {
3879  $titles[$row['question_id']] = $row["title"];
3880  }
3881  }
3882  return $titles;
3883  }
3884 
3894  {
3895  if ($this->getTitleOutput() == 2)
3896  {
3897  return $this->lng->txt("ass_question");
3898  }
3899  else
3900  {
3901  return $title;
3902  }
3903  }
3904 
3913  function getQuestionDataset($question_id)
3914  {
3915  global $ilDB;
3916 
3917  $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",
3918  array('integer'),
3919  array($question_id)
3920  );
3921  $row = $ilDB->fetchObject($result);
3922  return $row;
3923  }
3924 
3931  function &getExistingQuestions($pass = NULL)
3932  {
3933  global $ilUser;
3934  global $ilDB;
3935 
3936  $existing_questions = array();
3937  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3938  if ($this->isRandomTest())
3939  {
3940  if (is_null($pass)) $pass = 0;
3941  $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",
3942  array('integer','integer'),
3943  array($active_id, $pass)
3944  );
3945  }
3946  else
3947  {
3948  $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",
3949  array('integer'),
3950  array($this->getTestId())
3951  );
3952  }
3953  while ($data = $ilDB->fetchObject($result))
3954  {
3955  if( $data->original_id === null )
3956  {
3957  continue;
3958  }
3959 
3960  array_push($existing_questions, $data->original_id);
3961  }
3962  return $existing_questions;
3963  }
3964 
3972  function getQuestionType($question_id)
3973  {
3974  global $ilDB;
3975 
3976  if ($question_id < 1) return -1;
3977  $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",
3978  array('integer'),
3979  array($question_id)
3980  );
3981  if ($result->numRows() == 1)
3982  {
3983  $data = $ilDB->fetchObject($result);
3984  return $data->type_tag;
3985  }
3986  else
3987  {
3988  return "";
3989  }
3990  }
3991 
3998  function startWorkingTime($active_id, $pass)
3999  {
4000  global $ilDB;
4001 
4002  $next_id = $ilDB->nextId('tst_times');
4003  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
4004  array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'),
4005  array($next_id, $active_id, strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"), $pass, time())
4006  );
4007  return $next_id;
4008  }
4009 
4016  function updateWorkingTime($times_id)
4017  {
4018  global $ilDB;
4019 
4020  $affectedRows = $ilDB->manipulateF("UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
4021  array('timestamp', 'integer', 'integer'),
4022  array(strftime("%Y-%m-%d %H:%M:%S"), time(), $times_id)
4023  );
4024  }
4025 
4032  function &getWorkedQuestions($active_id, $pass = NULL)
4033  {
4034  global $ilUser;
4035  global $ilDB;
4036 
4037  if (is_null($pass))
4038  {
4039  $result = $ilDB->queryF("SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
4040  array('integer','integer'),
4041  array($active_id, 0)
4042  );
4043  }
4044  else
4045  {
4046  $result = $ilDB->queryF("SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
4047  array('integer','integer'),
4048  array($active_id, $pass)
4049  );
4050  }
4051  $result_array = array();
4052  while ($row = $ilDB->fetchAssoc($result))
4053  {
4054  array_push($result_array, $row["question_fi"]);
4055  }
4056  return $result_array;
4057  }
4058 
4067  function isTestFinishedToViewResults($active_id, $currentpass)
4068  {
4069  $num = $this->getPassFinishDate($active_id, $currentpass);
4070  return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ? true : false;
4071  }
4072 
4079  function &getAllQuestions($pass = NULL)
4080  {
4081  global $ilUser;
4082  global $ilDB;
4083 
4084  $result_array = array();
4085  if ($this->isRandomTest())
4086  {
4087  $active_id = $this->getActiveIdOfUser($ilUser->getId());
4088  $this->loadQuestions($active_id, $pass);
4089  if (count($this->questions) == 0) return $result_array;
4090  if (is_null($pass))
4091  {
4092  $pass = $this->_getPass($active_id);
4093  }
4094  $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'),
4095  array('integer','integer'),
4096  array($active_id, $pass)
4097  );
4098  }
4099  else
4100  {
4101  if (count($this->questions) == 0) return $result_array;
4102  $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'));
4103  }
4104  while ($row = $ilDB->fetchAssoc($result))
4105  {
4106  $result_array[$row["question_id"]] = $row;
4107  }
4108  return $result_array;
4109  }
4110 
4119  function getActiveIdOfUser($user_id = "", $anonymous_id = "")
4120  {
4121  global $ilDB;
4122  global $ilUser;
4123 
4124  if (!$user_id) $user_id = $ilUser->getId();
4125  if (($_SESSION["AccountId"] == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()])))
4126  {
4127  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4128  array('integer','integer','text'),
4129  array($user_id, $this->test_id, $_SESSION["tst_access_code"][$this->getTestId()])
4130  );
4131  }
4132  else if (strlen($anonymous_id))
4133  {
4134  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4135  array('integer','integer','text'),
4136  array($user_id, $this->test_id, $anonymous_id)
4137  );
4138  }
4139  else
4140  {
4141  if ($_SESSION["AccountId"] == ANONYMOUS_USER_ID)
4142  {
4143  return NULL;
4144  }
4145  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4146  array('integer','integer'),
4147  array($user_id, $this->test_id)
4148  );
4149  }
4150  if ($result->numRows())
4151  {
4152  $row = $ilDB->fetchAssoc($result);
4153  return $row["active_id"];
4154  }
4155  else
4156  {
4157  return 0;
4158  }
4159  }
4160 
4169  function _getActiveIdOfUser($user_id = "", $test_id = "")
4170  {
4171  global $ilDB;
4172  global $ilUser;
4173 
4174  if (!$user_id) {
4175  $user_id = $ilUser->id;
4176  }
4177  if (!$test_id)
4178  {
4179  return "";
4180  }
4181  $result = $ilDB->queryF("SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4182  array('integer', 'integer'),
4183  array($user_id, $test_id)
4184  );
4185  if ($result->numRows())
4186  {
4187  $row = $ilDB->fetchAssoc($result);
4188  return $row["active_id"];
4189  }
4190  else
4191  {
4192  return "";
4193  }
4194  }
4195 
4202  function pcArrayShuffle($array)
4203  {
4204  $keys = array_keys($array);
4205  shuffle($keys);
4206  $result = array();
4207  foreach ($keys as $key)
4208  {
4209  $result[$key] = $array[$key];
4210  }
4211  return $result;
4212  }
4213 
4221  function &getTestResult($active_id, $pass = NULL, $ordered_sequence = FALSE)
4222  {
4223  global $tree, $ilDB, $lng, $ilPluginAdmin;
4224 
4225  $results = $this->getResultsForActiveId($active_id);
4226 
4227  if( is_null($pass) )
4228  {
4229  $pass = $results['pass'];
4230  }
4231 
4232  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
4233  $testSessionFactory = new ilTestSessionFactory($this);
4234  $testSession = $testSessionFactory->getSession($active_id);
4235 
4236  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4237  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
4238  $testSequence = $testSequenceFactory->getSequenceByPass($testSession, $pass);
4239 
4240  if( $this->isDynamicTest() )
4241  {
4242  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4243  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
4244  $dynamicQuestionSetConfig->loadFromDb();
4245 
4246  $testSequence->loadFromDb($dynamicQuestionSetConfig);
4247  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4248 
4249  $sequence = $testSequence->getUserSequenceQuestions();
4250  }
4251  else
4252  {
4253  $testSequence->loadFromDb();
4254  $testSequence->loadQuestions();
4255 
4256  if( $ordered_sequence )
4257  {
4258  $sequence = $testSequence->getOrderedSequenceQuestions();
4259  }
4260  else
4261  {
4262  $sequence = $testSequence->getUserSequenceQuestions();
4263  }
4264  }
4265 
4266  $arrResults = array();
4267 
4268  $query = "
4269  SELECT tst_test_result.question_fi,
4270  tst_test_result.points reached,
4271  tst_test_result.hint_count requested_hints,
4272  tst_test_result.hint_points hint_points,
4273  tst_test_result.answered answered
4274 
4275  FROM tst_test_result
4276 
4277  LEFT JOIN tst_solutions
4278  ON tst_solutions.active_fi = tst_test_result.active_fi
4279  AND tst_solutions.question_fi = tst_test_result.question_fi
4280 
4281  WHERE tst_test_result.active_fi = %s
4282  AND tst_test_result.pass = %s
4283  ";
4284 
4285  $solutionresult = $ilDB->queryF(
4286  $query, array('integer', 'integer'), array($active_id, $pass)
4287  );
4288 
4289  while( $row = $ilDB->fetchAssoc($solutionresult) )
4290  {
4291  $arrResults[ $row['question_fi'] ] = $row;
4292  }
4293 
4294  $numWorkedThrough = count($arrResults);
4295 
4296  require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4297 
4298  $IN_question_ids = $ilDB->in('qpl_questions.question_id', $sequence, false, 'integer');
4299 
4300  $query = "
4301  SELECT qpl_questions.*,
4302  qpl_qst_type.type_tag,
4303  qpl_sol_sug.question_fi has_sug_sol
4304 
4305  FROM qpl_qst_type,
4306  qpl_questions
4307 
4308  LEFT JOIN qpl_sol_sug
4309  ON qpl_sol_sug.question_fi = qpl_questions.question_id
4310 
4311  WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi
4312  AND $IN_question_ids
4313  ";
4314 
4315  $result = $ilDB->query($query);
4316 
4317  $unordered = array();
4318 
4319  $key = 1;
4320 
4321  $obligationsAnswered = true;
4322 
4323  while( $row = $ilDB->fetchAssoc($result) )
4324  {
4325  $percentvalue = (
4326  $row['points'] ? $arrResults[ $row['question_id'] ]['reached'] / $row['points'] : 0
4327  );
4328 
4329  if( $percentvalue < 0 ) $percentvalue = 0.0;
4330 
4331  $data = array(
4332  "nr" => "$key",
4333  "title" => ilUtil::prepareFormOutput($row['title']),
4334  "max" => round($row['points'], 2),
4335  "reached" => round($arrResults[$row['question_id']]['reached'],2),
4336  'requested_hints' => $arrResults[$row['question_id']]['requested_hints'],
4337  'hint_points' => $arrResults[$row['question_id']]['hint_points'],
4338  "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4339  "solution" => ($row['has_sug_sol']) ? assQuestion::_getSuggestedSolutionOutput($row['question_id']) : '',
4340  "type" => $row["type_tag"],
4341  "qid" => $row['question_id'],
4342  "original_id" => $row["original_id"],
4343  "workedthrough" => isset($arrResults[$row['question_id']]) ? 1 : 0,
4344  'answered' => $arrResults[$row['question_id']]['answered']
4345  );
4346 
4347  if( !$arrResults[ $row['question_id'] ]['answered'] )
4348  {
4349  $obligationsAnswered = false;
4350  }
4351 
4352  $unordered[ $row['question_id'] ] = $data;
4353 
4354  $key++;
4355  }
4356 
4357  $pass_max = 0;
4358  $pass_reached = 0;
4359  $pass_requested_hints = 0;
4360  $pass_hint_points = 0;
4361  $key = 1;
4362 
4363  $found = array();
4364 
4365  foreach( $sequence as $qid )
4366  {
4367  // building pass point sums based on prepared data
4368  // for question that exists in users qst sequence
4369  $pass_max += round($unordered[$qid]['max'], 2);
4370  $pass_reached += round($unordered[$qid]['reached'], 2);
4371  $pass_requested_hints += $unordered[$qid]['requested_hints'];
4372  $pass_hint_points += $unordered[$qid]['hint_points'];
4373 
4374  // pickup prepared data for question
4375  // that exists in users qst sequence
4376  $unordered[$qid]['nr'] = $key;
4377  array_push($found, $unordered[$qid]);
4378 
4379  // increment key counter
4380  $key++;
4381  }
4382 
4383  $unordered = null;
4384 
4385  if( $this->getScoreCutting() == 1 )
4386  {
4387  if( $results['reached_points'] < 0 )
4388  {
4389  $results['reached_points'] = 0;
4390  }
4391 
4392  if( $pass_reached < 0 ) $pass_reached = 0;
4393  }
4394 
4395  $found['pass']['total_max_points'] = $pass_max;
4396  $found['pass']['total_reached_points'] = $pass_reached;
4397  $found['pass']['total_requested_hints'] = $pass_requested_hints;
4398  $found['pass']['total_hint_points'] = $pass_hint_points;
4399  $found['pass']['percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
4400  $found['pass']['obligationsAnswered'] = $obligationsAnswered;
4401  $found['pass']['num_workedthrough'] = $numWorkedThrough;
4402 
4403  $found["test"]["total_max_points"] = $results['max_points'];
4404  $found["test"]["total_reached_points"] = $results['reached_points'];
4405  $found["test"]["total_requested_hints"] = $results['hint_count'];
4406  $found["test"]["total_hint_points"] = $results['hint_points'];
4407  $found["test"]["result_pass"] = $results['pass'];
4408  $found['test']['obligations_answered'] = $results['obligations_answered'];
4409 
4410  if( (!$total_reached_points) or (!$total_max_points) )
4411  {
4412  $percentage = 0.0;
4413  }
4414  else
4415  {
4416  $percentage = ($total_reached_points / $total_max_points) * 100.0;
4417 
4418  if( $percentage < 0 ) $percentage = 0.0;
4419  }
4420 
4421  $found["test"]["passed"] = $results['passed'];
4422 
4423  return $found;
4424  }
4425 
4432  function evalTotalPersons()
4433  {
4434  global $ilDB;
4435 
4436  $result = $ilDB->queryF("SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
4437  array('integer'),
4438  array($this->getTestId())
4439  );
4440  $row = $ilDB->fetchAssoc($result);
4441  return $row["total"];
4442  }
4443 
4450  function getCompleteWorkingTime($user_id)
4451  {
4452  global $ilDB;
4453 
4454  $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",
4455  array('integer','integer'),
4456  array($this->getTestId(), $user_id)
4457  );
4458  $time = 0;
4459  while ($row = $ilDB->fetchAssoc($result))
4460  {
4461  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4462  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4463  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4464  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4465  $time += ($epoch_2 - $epoch_1);
4466  }
4467  return $time;
4468  }
4469 
4477  {
4478  return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4479  }
4480 
4489  {
4490  global $ilDB;
4491 
4492  $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",
4493  array('integer'),
4494  array($test_id)
4495  );
4496  $time = 0;
4497  $times = array();
4498  while ($row = $ilDB->fetchAssoc($result))
4499  {
4500  if (!array_key_exists($row["active_fi"], $times))
4501  {
4502  $times[$row["active_fi"]] = 0;
4503  }
4504  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4505  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4506  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4507  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4508  $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4509  }
4510  return $times;
4511  }
4512 
4520  {
4521  global $ilDB;
4522 
4523  $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",
4524  array('integer','integer'),
4525  array($this->getTestId(), $active_id)
4526  );
4527  $time = 0;
4528  while ($row = $ilDB->fetchAssoc($result))
4529  {
4530  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4531  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4532  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4533  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4534  $time += ($epoch_2 - $epoch_1);
4535  }
4536  return $time;
4537  }
4538 
4546  {
4547  global $ilDB;
4548 
4549  $result = $ilDB->queryF("SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4550  array('integer','integer'),
4551  array($active_id, $pass)
4552  );
4553  $time = 0;
4554  while ($row = $ilDB->fetchAssoc($result))
4555  {
4556  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4557  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4558  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4559  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4560  $time += ($epoch_2 - $epoch_1);
4561  }
4562  return $time;
4563  }
4564 
4572  function getVisitTimeOfParticipant($active_id)
4573  {
4574  return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4575  }
4576 
4585  function _getVisitTimeOfParticipant($test_id, $active_id)
4586  {
4587  global $ilDB;
4588 
4589  $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",
4590  array('integer','integer'),
4591  array($test_id, $active_id)
4592  );
4593  $firstvisit = 0;
4594  $lastvisit = 0;
4595  while ($row = $ilDB->fetchAssoc($result))
4596  {
4597  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4598  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4599  if ($firstvisit == 0 || $epoch_1 < $firstvisit) $firstvisit = $epoch_1;
4600  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4601  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4602  if ($epoch_2 > $lastvisit) $lastvisit = $epoch_2;
4603  }
4604  return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4605  }
4606 
4613  function &evalStatistical($active_id)
4614  {
4615  global $ilDB;
4616 // global $ilBench;
4617  $pass = ilObjTest::_getResultPass($active_id);
4618  $test_result =& $this->getTestResult($active_id, $pass);
4619  $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",
4620  array('integer'),
4621  array($active_id)
4622  );
4623  $times = array();
4624  $first_visit = 0;
4625  $last_visit = 0;
4626  while ($row = $ilDB->fetchObject($result))
4627  {
4628  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4629  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4630  if (!$first_visit) {
4631  $first_visit = $epoch_1;
4632  }
4633  if ($epoch_1 < $first_visit) {
4634  $first_visit = $epoch_1;
4635  }
4636  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4637  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4638  if (!$last_visit) {
4639  $last_visit = $epoch_2;
4640  }
4641  if ($epoch_2 > $last_visit) {
4642  $last_visit = $epoch_2;
4643  }
4644  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4645  }
4646  $max_time = 0;
4647  foreach ($times as $key => $value) {
4648  $max_time += $value;
4649  }
4650  if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"]))
4651  {
4652  $percentage = 0.0;
4653  }
4654  else
4655  {
4656  $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4657  if ($percentage < 0) $percentage = 0.0;
4658  }
4659  $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4660  $first_date = getdate($first_visit);
4661  $last_date = getdate($last_visit);
4662  $qworkedthrough = 0;
4663  foreach ($test_result as $key => $value)
4664  {
4665  if (preg_match("/\d+/", $key))
4666  {
4667  $qworkedthrough += $value["workedthrough"];
4668  }
4669  }
4670  if (!$qworkedthrough)
4671  {
4672  $atimeofwork = 0;
4673  }
4674  else
4675  {
4676  $atimeofwork = $max_time / $qworkedthrough;
4677  }
4678 
4679  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4680 
4681  $result_mark = "";
4682  $passed = "";
4683 
4684  if ($mark_obj)
4685  {
4686  $result_mark = $mark_obj->getShortName();
4687 
4688  if( $mark_obj->getPassed() && $obligationsAnswered )
4689  {
4690  $passed = 1;
4691  }
4692  else
4693  {
4694  $passed = 0;
4695  }
4696  }
4697  $percent_worked_through = 0;
4698  if (count($this->questions))
4699  {
4700  $percent_worked_through = $qworkedthrough / count($this->questions);
4701  }
4702  $result_array = array(
4703  "qworkedthrough" => $qworkedthrough,
4704  "qmax" => count($this->questions),
4705  "pworkedthrough" => $percent_worked_through,
4706  "timeofwork" => $max_time,
4707  "atimeofwork" => $atimeofwork,
4708  "firstvisit" => $first_date,
4709  "lastvisit" => $last_date,
4710  "resultspoints" => $test_result["test"]["total_reached_points"],
4711  "maxpoints" => $test_result["test"]["total_max_points"],
4712  "resultsmarks" => $result_mark,
4713  "passed" => $passed,
4714  "distancemedian" => "0"
4715  );
4716  foreach ($test_result as $key => $value)
4717  {
4718  if (preg_match("/\d+/", $key))
4719  {
4720  $result_array[$key] = $value;
4721  }
4722  }
4723  return $result_array;
4724  }
4725 
4734  {
4735  $totalpoints_array = array();
4736  $all_users =& $this->evalTotalParticipantsArray();
4737  foreach ($all_users as $active_id => $user_name)
4738  {
4739  $test_result =& $this->getTestResult($active_id);
4740  $reached = $test_result["test"]["total_reached_points"];
4741  $total = $test_result["test"]["total_max_points"];
4742  $percentage = $total != 0 ? $reached/$total : 0;
4743  $mark = $this->mark_schema->getMatchingMark($percentage*100.0);
4744 
4745  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4746 
4747  if ($mark)
4748  {
4749  if( $mark->getPassed() && $obligationsAnswered )
4750  {
4751  array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4752  }
4753  }
4754  }
4755  return $totalpoints_array;
4756  }
4757 
4763  public function &getParticipants()
4764  {
4765  global $ilDB;
4766  $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",
4767  array('integer'),
4768  array($this->getTestId())
4769  );
4770  $persons_array = array();
4771  while ($row = $ilDB->fetchAssoc($result))
4772  {
4773  $name = $this->lng->txt("anonymous");
4774  $fullname = $this->lng->txt("anonymous");
4775  $login = "";
4776  if (!$this->getAnonymity())
4777  {
4778  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4779  {
4780  $name = $this->lng->txt("deleted_user");
4781  $fullname = $this->lng->txt("deleted_user");
4782  $login = $this->lng->txt("unknown");
4783  }
4784  else
4785  {
4786  $login = $row["login"];
4787  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4788  {
4789  $name = $this->lng->txt("anonymous");
4790  $fullname = $this->lng->txt("anonymous");
4791  }
4792  else
4793  {
4794  $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4795  $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4796  }
4797  }
4798  }
4799  $persons_array[$row["active_id"]] = array(
4800  "name" => $name,
4801  "fullname" => $fullname,
4802  "login" => $login
4803  );
4804  }
4805  return $persons_array;
4806  }
4807 
4814  function &evalTotalPersonsArray($name_sort_order = "asc")
4815  {
4816  global $ilDB;
4817  $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),
4818  array('integer'),
4819  array($this->getTestId())
4820  );
4821  $persons_array = array();
4822  while ($row = $ilDB->fetchAssoc($result))
4823  {
4824  if ($this->getAnonymity())
4825  {
4826  $persons_array[$row["active_id"]] = $this->lng->txt("anonymous");
4827  }
4828  else
4829  {
4830  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4831  {
4832  $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4833  }
4834  else
4835  {
4836  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4837  {
4838  $persons_array[$row["active_id"]] = $row["lastname"];
4839  }
4840  else
4841  {
4842  $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4843  }
4844  }
4845  }
4846  }
4847  return $persons_array;
4848  }
4849 
4856  function &evalTotalParticipantsArray($name_sort_order = "asc")
4857  {
4858  global $ilDB;
4859  $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),
4860  array('integer'),
4861  array($this->getTestId())
4862  );
4863  $persons_array = array();
4864  while ($row = $ilDB->fetchAssoc($result))
4865  {
4866  if ($this->getAnonymity())
4867  {
4868  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("anonymous"));
4869  }
4870  else
4871  {
4872  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4873  {
4874  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4875  }
4876  else
4877  {
4878  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4879  {
4880  $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4881  }
4882  else
4883  {
4884  $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4885  }
4886  }
4887  }
4888  }
4889  return $persons_array;
4890  }
4891 
4899  {
4900  global $ilDB;
4901 
4902  $result = $ilDB->queryF("SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s AND submitted = %s",
4903  array('integer', 'integer'),
4904  array($this->getTestId(), 1)
4905  );
4906  $row = $ilDB->fetchAssoc($result);
4907  return $row["total"];
4908  }
4909 
4916  function &getQuestionsOfTest($active_id)
4917  {
4918  global $ilDB;
4919  if ($this->isRandomTest())
4920  {
4921  $ilDB->setLimit($this->getQuestionCount(), 0);
4922  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4923  "tst_test_rnd_qst.pass, qpl_questions.points " .
4924  "FROM tst_test_rnd_qst, qpl_questions " .
4925  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4926  "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4927  array('integer'),
4928  array($active_id)
4929  );
4930  }
4931  else
4932  {
4933  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4934  "qpl_questions.points " .
4935  "FROM tst_test_question, tst_active, qpl_questions " .
4936  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4937  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4938  array('integer'),
4939  array($active_id)
4940  );
4941  }
4942  $qtest = array();
4943  if ($result->numRows())
4944  {
4945  while ($row = $ilDB->fetchAssoc($result))
4946  {
4947  array_push($qtest, $row);
4948  }
4949  }
4950  return $qtest;
4951  }
4952 
4959  function &getQuestionsOfPass($active_id, $pass)
4960  {
4961  global $ilDB;
4962  if ($this->isRandomTest())
4963  {
4964  $ilDB->setLimit($this->getQuestionCount(), 0);
4965  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4966  "qpl_questions.points " .
4967  "FROM tst_test_rnd_qst, qpl_questions " .
4968  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4969  "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
4970  "ORDER BY tst_test_rnd_qst.sequence",
4971  array('integer', 'integer'),
4972  array($active_id, $pass)
4973  );
4974  }
4975  else
4976  {
4977  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4978  "qpl_questions.points " .
4979  "FROM tst_test_question, tst_active, qpl_questions " .
4980  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4981  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4982  array('integer'),
4983  array($active_id)
4984  );
4985  }
4986  $qpass = array();
4987  if ($result->numRows())
4988  {
4989  while ($row = $ilDB->fetchAssoc($result))
4990  {
4991  array_push($qpass, $row);
4992  }
4993  }
4994  return $qpass;
4995  }
4996 
4998  {
4999  global $ilDB;
5000 
5001  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5002  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5003  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5004 
5005  $data = new ilTestEvaluationData($this);
5006 
5007  $query = "
5008  SELECT tst_test_result.*,
5009  qpl_questions.original_id,
5010  qpl_questions.title questiontitle,
5011  qpl_questions.points maxpoints
5012 
5013  FROM tst_test_result, qpl_questions, tst_active
5014 
5015  WHERE tst_active.active_id = tst_test_result.active_fi
5016  AND qpl_questions.question_id = tst_test_result.question_fi
5017  AND tst_active.test_fi = %s
5018 
5019  ORDER BY tst_active.active_id ASC, tst_test_result.pass ASC, tst_test_result.tstamp DESC
5020  ";
5021 
5022  $result = $ilDB->queryF(
5023  $query, array('integer'), array($this->getTestId())
5024  );
5025 
5026  $pass = NULL;
5027  $checked = array();
5028  $datasets = 0;
5029 
5030  while( $row = $ilDB->fetchAssoc($result) )
5031  {
5032  $participantObject = $data->getParticipant($row["active_fi"]);
5033 
5034  if( !($participantObject instanceof ilTestEvaluationUserData) )
5035  {
5036  continue;
5037  }
5038 
5039  $passObject = $participantObject->getPass($row["pass"]);
5040 
5041  if( !($passObject instanceof ilTestEvaluationPassData) )
5042  {
5043  continue;
5044  }
5045 
5046  $passObject->addAnsweredQuestion(
5047  $row["question_fi"], $row["maxpoints"], $row["points"], $row['answered'], null, $row['manual']
5048  );
5049  }
5050 
5051  foreach( array_keys($data->getParticipants()) as $active_id )
5052  {
5053  if( $this->isRandomTest() )
5054  {
5055  for( $testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++ )
5056  {
5057  $ilDB->setLimit($this->getQuestionCount(), 0);
5058  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, qpl_questions.original_id, " .
5059  "tst_test_rnd_qst.pass, qpl_questions.points, qpl_questions.title " .
5060  "FROM tst_test_rnd_qst, qpl_questions " .
5061  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
5062  "AND tst_test_rnd_qst.pass = %s " .
5063  "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
5064  array('integer','integer'),
5065  array($testpass, $active_id)
5066  );
5067  if ($result->numRows())
5068  {
5069  while ($row = $ilDB->fetchAssoc($result))
5070  {
5071  $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
5072  $data->getParticipant($active_id)->addQuestion($row["original_id"], $row["question_fi"], $row["points"], $row["sequence"], $tpass);
5073  $data->addQuestionTitle($row["question_fi"], $row["title"]);
5074  }
5075  }
5076  }
5077  }
5078  else
5079  {
5080  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
5081  "qpl_questions.points, qpl_questions.title, qpl_questions.original_id " .
5082  "FROM tst_test_question, tst_active, qpl_questions " .
5083  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
5084  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi ORDER BY tst_test_question.sequence",
5085  array('integer'),
5086  array($active_id)
5087  );
5088  if ($result->numRows())
5089  {
5090  $questionsbysequence = array();
5091 
5092  while ($row = $ilDB->fetchAssoc($result))
5093  {
5094  $questionsbysequence[$row["sequence"]] = $row;
5095  }
5096 
5097  $seqresult = $ilDB->queryF("SELECT * FROM tst_sequence WHERE active_fi = %s",
5098  array('integer'),
5099  array($active_id)
5100  );
5101 
5102  while ($seqrow = $ilDB->fetchAssoc($seqresult))
5103  {
5104  $questionsequence = unserialize($seqrow["sequence"]);
5105  foreach ($questionsequence as $sidx => $seq)
5106  {
5107  $data->getParticipant($active_id)->addQuestion($questionsbysequence[$seq]["original_id"], $questionsbysequence[$seq]["question_fi"], $questionsbysequence[$seq]["points"], $sidx + 1, $seqrow["pass"]);
5108  $data->addQuestionTitle($questionsbysequence[$seq]["question_fi"], $questionsbysequence[$seq]["title"]);
5109  }
5110  }
5111  }
5112  }
5113  }
5114 
5115  if($this->getECTSOutput())
5116  {
5117  $passed_array =& $this->getTotalPointsPassedArray();
5118  }
5119 
5120  foreach( array_keys($data->getParticipants()) as $active_id )
5121  {
5122  $tstUserData = $data->getParticipant($active_id);
5123 
5124  $percentage = $tstUserData->getReachedPointsInPercent();
5125 
5126  $obligationsAnswered = $tstUserData->areObligationsAnswered();
5127 
5128  $mark = $this->mark_schema->getMatchingMark($percentage);
5129 
5130  if (is_object($mark))
5131  {
5132  $tstUserData->setMark($mark->getShortName());
5133  $tstUserData->setMarkOfficial($mark->getOfficialName());
5134 
5135  $tstUserData->setPassed(
5136  $mark->getPassed() && $tstUserData->areObligationsAnswered()
5137  );
5138  }
5139 
5140  if($this->getECTSOutput())
5141  {
5142  $ects_mark = $this->getECTSGrade(
5143  $passed_array, $tstUserData->getReached(), $tstUserData->getMaxPoints()
5144  );
5145 
5146  $tstUserData->setECTSMark($ects_mark);
5147  }
5148 
5149  $visitingTime =& $this->getVisitTimeOfParticipant($active_id);
5150 
5151  $tstUserData->setFirstVisit($visitingTime["firstvisit"]);
5152  $tstUserData->setLastVisit($visitingTime["lastvisit"]);
5153  }
5154 
5155  return $data;
5156  }
5157 
5159  {
5160  global $ilDB;
5161 
5163 
5164  switch( $questionSetType )
5165  {
5167 
5168  $res = $ilDB->queryF("
5169  SELECT COUNT(qpl_questions.question_id) qcount,
5170  SUM(qpl_questions.points) qsum
5171  FROM tst_active
5172  INNER JOIN tst_tests
5173  ON tst_tests.test_id = tst_active.test_fi
5174  INNER JOIN tst_dyn_quest_set_cfg
5175  ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
5176  INNER JOIN qpl_questions
5177  ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
5178  AND qpl_questions.original_id IS NULL
5179  AND qpl_questions.complete = %s
5180  WHERE tst_active.active_id = %s
5181  ",
5182  array('integer', 'integer'),
5183  array(1, $active_id)
5184  );
5185 
5186  break;
5187 
5189 
5190  $res = $ilDB->queryF("
5191  SELECT tst_test_rnd_qst.pass,
5192  COUNT(tst_test_rnd_qst.question_fi) qcount,
5193  SUM(qpl_questions.points) qsum
5194 
5195  FROM tst_test_rnd_qst,
5196  qpl_questions
5197 
5198  WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
5199  AND tst_test_rnd_qst.active_fi = %s
5200  AND pass = %s
5201 
5202  GROUP BY tst_test_rnd_qst.active_fi,
5203  tst_test_rnd_qst.pass
5204  ",
5205  array('integer', 'integer'),
5206  array($active_id, $pass)
5207  );
5208 
5209  break;
5210 
5212 
5213  $res = $ilDB->queryF("
5214  SELECT COUNT(tst_test_question.question_fi) qcount,
5215  SUM(qpl_questions.points) qsum
5216 
5217  FROM tst_test_question,
5218  qpl_questions,
5219  tst_active
5220 
5221  WHERE tst_test_question.question_fi = qpl_questions.question_id
5222  AND tst_test_question.test_fi = tst_active.test_fi
5223  AND tst_active.active_id = %s
5224 
5225  GROUP BY tst_test_question.test_fi
5226  ",
5227  array('integer'),
5228  array($active_id)
5229  );
5230 
5231  break;
5232 
5233  default:
5234 
5235  throw new ilTestException("not supported question set type: $questionSetType");
5236  }
5237 
5238  $row = $ilDB->fetchAssoc($res);
5239 
5240  if( is_array($row) )
5241  {
5242  return array("count" => $row["qcount"], "points" => $row["qsum"]);
5243  }
5244 
5245  return array("count" => 0, "points" => 0);
5246  }
5247 
5248  function &getCompleteEvaluationData($withStatistics = TRUE, $filterby = "", $filtertext = "")
5249  {
5250  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5251  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5252  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5253  $data = $this->getUnfilteredEvaluationData();
5254  if ($withStatistics)
5255  {
5256  $data->calculateStatistics();
5257  }
5258  $data->setFilter($filterby, $filtertext);
5259  return $data;
5260  }
5261 
5269  {
5270  return $this->_evalResultsOverview($this->getTestId());
5271  }
5272 
5280  {
5281  global $ilDB;
5282 
5283  $result = $ilDB->queryF("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5284  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5285  "qpl_questions.points maxpoints " .
5286  "FROM tst_test_result, qpl_questions, tst_active " .
5287  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5288  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5289  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5290  "AND tst_active.test_fi = %s " .
5291  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5292  array('integer'),
5293  array($test_id)
5294  );
5295  $overview = array();
5296  while ($row = $ilDB->fetchAssoc($result))
5297  {
5298  if (!array_key_exists($row["active_fi"], $overview))
5299  {
5300  $overview[$row["active_fi"]] = array();
5301  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5302  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5303  $overview[$row["active_fi"]]["title"] = $row["title"];
5304  $overview[$row["active_fi"]]["login"] = $row["login"];
5305  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5306  $overview[$row["active_fi"]]["started"] = $row["started"];
5307  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5308  }
5309  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5310  {
5311  $overview[$row["active_fi"]][$row["pass"]] = array();
5312  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5313  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5314  }
5315  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5316  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5317  }
5318  return $overview;
5319  }
5320 
5328  function &evalResultsOverviewOfParticipant($active_id)
5329  {
5330  global $ilDB;
5331 
5332  $result = $ilDB->queryF("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5333  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5334  "qpl_questions.points maxpoints " .
5335  "FROM tst_test_result, qpl_questions, tst_active " .
5336  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5337  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5338  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5339  "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5340  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5341  array('integer', 'integer'),
5342  array($this->getTestId(), $active_id)
5343  );
5344  $overview = array();
5345  while ($row = $ilDB->fetchAssoc($result))
5346  {
5347  if (!array_key_exists($row["active_fi"], $overview))
5348  {
5349  $overview[$row["active_fi"]] = array();
5350  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5351  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5352  $overview[$row["active_fi"]]["title"] = $row["title"];
5353  $overview[$row["active_fi"]]["login"] = $row["login"];
5354  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5355  $overview[$row["active_fi"]]["started"] = $row["started"];
5356  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5357  }
5358  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5359  {
5360  $overview[$row["active_fi"]][$row["pass"]] = array();
5361  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5362  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5363  }
5364  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5365  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5366  }
5367  return $overview;
5368  }
5369 
5381  function buildName($user_id, $firstname, $lastname, $title)
5382  {
5383  $name = "";
5384  if (strlen($firstname.$lastname.$title) == 0)
5385  {
5386  $name = $this->lng->txt("deleted_user");
5387  }
5388  else
5389  {
5390  if ($user_id == ANONYMOUS_USER_ID)
5391  {
5392  $name = $lastname;
5393  }
5394  else
5395  {
5396  $name = trim($lastname . ", " . $firstname . " " . $title);
5397  }
5398  if ($this->getAnonymity())
5399  {
5400  $name = $this->lng->txt("anonymous");
5401  }
5402  }
5403  return $name;
5404  }
5405 
5418  function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5419  {
5420  global $lng;
5421  $name = "";
5422  if (strlen($firstname.$lastname.$title) == 0)
5423  {
5424  $name = $lng->txt("deleted_user");
5425  }
5426  else
5427  {
5428  if ($user_id == ANONYMOUS_USER_ID)
5429  {
5430  $name = $lastname;
5431  }
5432  else
5433  {
5434  $name = trim($lastname . ", " . $firstname . " " . $title);
5435  }
5436  if ($is_anonymous)
5437  {
5438  $name = $lng->txt("anonymous");
5439  }
5440  }
5441  return $name;
5442  }
5443 
5451  {
5452  global $ilDB;
5453 
5454  $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",
5455  array('integer'),
5456  array($this->getTestId())
5457  );
5458  $times = array();
5459  while ($row = $ilDB->fetchObject($result))
5460  {
5461  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5462  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5463  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5464  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5465  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5466  }
5467  $max_time = 0;
5468  $counter = 0;
5469  foreach ($times as $key => $value)
5470  {
5471  $max_time += $value;
5472  $counter++;
5473  }
5474  if ($counter)
5475  {
5476  $average_time = round($max_time / $counter);
5477  }
5478  else
5479  {
5480  $average_time = 0;
5481  }
5482  return $average_time;
5483  }
5484 
5491  function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = FALSE, $with_questioncount = FALSE, $permission = "read")
5492  {
5493  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5494  return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5495  }
5496 
5504  {
5505  $time_in_seconds = 0;
5506  foreach ($this->questions as $question_id)
5507  {
5508  $question =& ilObjTest::_instanciateQuestion($question_id);
5509  $est_time = $question->getEstimatedWorkingTime();
5510  $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5511  }
5512  $hours = (int)($time_in_seconds / 3600) ;
5513  $time_in_seconds = $time_in_seconds - ($hours * 3600);
5514  $minutes = (int)($time_in_seconds / 60);
5515  $time_in_seconds = $time_in_seconds - ($minutes * 60);
5516  $result = array("hh" => $hours, "mm" => $minutes, "ss" => $time_in_seconds);
5517  return $result;
5518  }
5519 
5526  function getImagePath()
5527  {
5528  return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5529  }
5530 
5537  function getImagePathWeb()
5538  {
5539  include_once "./Services/Utilities/classes/class.ilUtil.php";
5540  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
5542  }
5543 
5552  function &createQuestionGUI($question_type, $question_id = -1)
5553  {
5554  if ((!$question_type) and ($question_id > 0))
5555  {
5556  $question_type = $this->getQuestionType($question_id);
5557  }
5558 
5559  if (!strlen($question_type)) return null;
5560 
5561  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5562  assQuestion::_includeClass($question_type, 1);
5563 
5564  $question_type_gui = assQuestion::getGuiClassNameByQuestionType($question_type);
5565  $question = new $question_type_gui();
5566 
5567  $question->object->setObligationsToBeConsidered( $this->areObligationsEnabled() );
5568 
5569  if ($question_id > 0)
5570  {
5571  $question->object->loadFromDb($question_id);
5572 
5573  global $ilCtrl, $ilDB, $ilUser, $lng;
5574 
5575  $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
5576  $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
5577 
5578  $assSettings = new ilSetting('assessment');
5579  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
5580  $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
5581  $processLockerFactory->setQuestionId($question->object->getId());
5582  $processLockerFactory->setUserId($ilUser->getId());
5583  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
5584  $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
5585  $question->object->setProcessLocker($processLockerFactory->getLocker());
5586  }
5587 
5588  return $question;
5589  }
5590 
5600  function &_instanciateQuestion($question_id)
5601  {
5602  if (strcmp($question_id, "") != 0)
5603  {
5604  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5605  return assQuestion::_instanciateQuestion($question_id);
5606  }
5607  }
5608 
5617  function moveQuestions($move_questions, $target_index, $insert_mode)
5618  {
5619  $this->questions = array_values($this->questions);
5620  $array_pos = array_search($target_index, $this->questions);
5621  if ($insert_mode == 0)
5622  {
5623  $part1 = array_slice($this->questions, 0, $array_pos);
5624  $part2 = array_slice($this->questions, $array_pos);
5625  }
5626  else if ($insert_mode == 1)
5627  {
5628  $part1 = array_slice($this->questions, 0, $array_pos + 1);
5629  $part2 = array_slice($this->questions, $array_pos + 1);
5630  }
5631  foreach ($move_questions as $question_id)
5632  {
5633  if (!(array_search($question_id, $part1) === FALSE))
5634  {
5635  unset($part1[array_search($question_id, $part1)]);
5636  }
5637  if (!(array_search($question_id, $part2) === FALSE))
5638  {
5639  unset($part2[array_search($question_id, $part2)]);
5640  }
5641  }
5642  $part1 = array_values($part1);
5643  $part2 = array_values($part2);
5644  $new_array = array_values(array_merge($part1, $move_questions, $part2));
5645  $this->questions = array();
5646  $counter = 1;
5647  foreach ($new_array as $question_id)
5648  {
5649  $this->questions[$counter] = $question_id;
5650  $counter++;
5651  }
5652  $this->saveQuestionsToDb();
5653  }
5654 
5655 
5664  {
5665  if( $this->isStartingTimeEnabled() && $this->getStartingTime() )
5666  {
5667  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getStartingTime(), $matches))
5668  {
5669  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5670  $now = mktime();
5671  if ($now < $epoch_time)
5672  {
5673  // starting time not reached
5674  return false;
5675  }
5676  }
5677  }
5678  return true;
5679  }
5680 
5689  {
5690  if( $this->isEndingTimeEnabled() && $this->getEndingTime() )
5691  {
5692  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndingTime(), $matches))
5693  {
5694  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5695  $now = mktime();
5696  if ($now > $epoch_time)
5697  {
5698  // ending time reached
5699  return true;
5700  }
5701  }
5702  }
5703  return false;
5704  }
5705 
5711  function getAvailableQuestions($arrFilter, $completeonly = 0)
5712  {
5713  global $ilUser;
5714  global $ilDB;
5715 
5716  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5717  $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = TRUE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE));
5718  $available = "";
5719  if (count($available_pools))
5720  {
5721  $available = " AND " . $ilDB->in('qpl_questions.obj_fi', $available_pools, false, 'integer');
5722  }
5723  else
5724  {
5725  return array();
5726  }
5727  if ($completeonly)
5728  {
5729  $available .= " AND qpl_questions.complete = " . $ilDB->quote("1", 'text');
5730  }
5731 
5732  $where = "";
5733  if (is_array($arrFilter))
5734  {
5735  if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title']))
5736  {
5737  $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
5738  }
5739  if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description']))
5740  {
5741  $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
5742  }
5743  if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author']))
5744  {
5745  $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
5746  }
5747  if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type']))
5748  {
5749  $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
5750  }
5751  if (array_key_exists('qpl', $arrFilter) && strlen($arrFilter['qpl']))
5752  {
5753  $where .= " AND " . $ilDB->like('object_data.title', 'text', "%%" . $arrFilter['qpl'] . "%%");
5754  }
5755  }
5756 
5757  $original_ids =& $this->getExistingQuestions();
5758  $original_clause = " qpl_questions.original_id IS NULL";
5759  if (count($original_ids))
5760  {
5761  $original_clause = " qpl_questions.original_id IS NULL AND " . $ilDB->in('qpl_questions.question_id', $original_ids, true, 'integer');
5762  }
5763 
5764  $query_result = $ilDB->query(
5765  "SELECT qpl_questions.*, qpl_questions.tstamp, qpl_qst_type.type_tag, qpl_qst_type.plugin, object_data.title qpl " .
5766  "FROM qpl_questions, qpl_qst_type, object_data WHERE $original_clause $available AND " .
5767  "object_data.obj_id = qpl_questions.obj_fi AND qpl_questions.tstamp > 0 AND " .
5768  "qpl_questions.question_type_fi = qpl_qst_type.question_type_id$where");
5769  $rows = array();
5770  $types = $this->getQuestionTypeTranslations();
5771  if ($query_result->numRows())
5772  {
5773  while ($row = $ilDB->fetchAssoc($query_result))
5774  {
5775  $row['ttype'] = $types[$row['type_tag']];
5776  if ($row["plugin"])
5777  {
5778  if ($this->isPluginActive($row["type_tag"]))
5779  {
5780  array_push($rows, $row);
5781  }
5782  }
5783  else
5784  {
5785  array_push($rows, $row);
5786  }
5787  }
5788  }
5789  return $rows;
5790  }
5791 
5792  public function &getQuestionTypeTranslations()
5793  {
5794  global $ilDB;
5795  global $lng;
5796  global $ilLog;
5797  global $ilPluginAdmin;
5798 
5799  $lng->loadLanguageModule("assessment");
5800  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
5801  $types = array();
5802  while ($row = $ilDB->fetchAssoc($result))
5803  {
5804  if ($row["plugin"] == 0)
5805  {
5806  $types[$row['type_tag']] = $lng->txt($row["type_tag"]);
5807  }
5808  else
5809  {
5810  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
5811  foreach ($pl_names as $pl_name)
5812  {
5813  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
5814  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
5815  {
5816  $types[$row['type_tag']] = $pl->getQuestionTypeTranslation();
5817  }
5818  }
5819  }
5820  }
5821  ksort($types);
5822  return $types;
5823  }
5824 
5829  public function fromXML(ilQTIAssessment $assessment)
5830  {
5831  unset($_SESSION["import_mob_xhtml"]);
5832 
5833  $this->setDescription($assessment->getComment());
5834  $this->setTitle($assessment->getTitle());
5835 
5836  $this->setIntroductionEnabled(false);
5837  foreach ($assessment->objectives as $objectives)
5838  {
5839  foreach ($objectives->materials as $material)
5840  {
5841  $intro = $this->QTIMaterialToString($material);
5842  $this->setIntroduction($intro);
5843  $this->setIntroductionEnabled(strlen($intro) > 0);
5844  }
5845  }
5846 
5847  if(
5848  $assessment->getPresentationMaterial() &&
5849  $assessment->getPresentationMaterial()->getFlowMat(0) &&
5850  $assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)
5851  )
5852  {
5853  $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)));
5854  }
5855 
5856  foreach ($assessment->assessmentcontrol as $assessmentcontrol)
5857  {
5858  switch ($assessmentcontrol->getSolutionswitch())
5859  {
5860  case "Yes":
5861  $this->setInstantFeedbackSolution(1);
5862  break;
5863  default:
5864  $this->setInstantFeedbackSolution(0);
5865  break;
5866  }
5867  }
5868 
5869  $this->setStartingTimeEnabled(false);
5870  $this->setEndingTimeEnabled(false);
5871  $this->setPasswordEnabled(false);
5872  $this->setLimitUsersEnabled(false);
5873 
5874  foreach ($assessment->qtimetadata as $metadata)
5875  {
5876  switch ($metadata["label"])
5877  {
5878  case "test_type":
5879  // for old tests with a test type
5880  $type = $metadata["entry"];
5881  switch ($type)
5882  {
5883  case 1:
5884  // assessment
5885  $this->setAnonymity(1);
5886  break;
5887  case 2:
5888  // self assessment
5889  break;
5890  case 4:
5891  // online exam
5892  $this->setFixedParticipants(1);
5893  $this->setListOfQuestionsSettings(7);
5894  $this->setShowSolutionPrintview(1);
5895  break;
5896  case 5:
5897  // varying random test
5898  break;
5899  }
5900  break;
5901  case "sequence_settings":
5902  $this->setSequenceSettings($metadata["entry"]);
5903  break;
5904  case "author":
5905  $this->setAuthor($metadata["entry"]);
5906  break;
5907  case "nr_of_tries":
5908  $this->setNrOfTries($metadata["entry"]);
5909  break;
5910  case "kiosk":
5911  $this->setKiosk($metadata["entry"]);
5912  break;
5913  case "showfinalstatement":
5914  $this->setShowFinalStatement($metadata["entry"]);
5915  break;
5916  case "showinfo":
5917  $this->setShowInfo($metadata["entry"]);
5918  break;
5919  case "forcejs":
5920  $this->setForceJS($metadata["entry"]);
5921  break;
5922  case "customstyle":
5923  $this->setCustomStyle($metadata["entry"]);
5924  break;
5925 
5926  case "highscore_enabled":
5927  $this->setHighscoreEnabled($metadata["entry"]);
5928  break;
5929 
5930  case "highscore_anon":
5931  $this->setHighscoreAnon($metadata["entry"]);
5932  break;
5933 
5934  case "highscore_achieved_ts":
5935  $this->setHighscoreAchievedTS($metadata["entry"]);
5936  break;
5937 
5938  case "highscore_score":
5939  $this->setHighscoreScore($metadata["entry"]);
5940  break;
5941 
5942  case "highscore_percentage":
5943  $this->setHighscorePercentage($metadata["entry"]);
5944  break;
5945 
5946  case "highscore_hints":
5947  $this->setHighscoreHints($metadata["entry"]);
5948  break;
5949 
5950  case "highscore_wtime":
5951  $this->setHighscoreWTime($metadata["entry"]);
5952  break;
5953 
5954  case "highscore_own_table":
5955  $this->setHighscoreOwnTable($metadata["entry"]);
5956  break;
5957 
5958  case "highscore_top_table":
5959  $this->setHighscoreTopTable($metadata["entry"]);
5960  break;
5961 
5962  case "highscore_top_num":
5963  $this->setHighscoreTopNum($metadata["entry"]);
5964  break;
5965 
5966  case "hide_previous_results":
5967  if ($metadata["entry"] == 0)
5968  {
5969  $this->setUsePreviousAnswers(1);
5970  }
5971  else
5972  {
5973  $this->setUsePreviousAnswers(0);
5974  }
5975  break;
5976  case "use_previous_answers":
5977  $this->setUsePreviousAnswers($metadata["entry"]);
5978  break;
5979  case "answer_feedback":
5980  $this->setAnswerFeedback($metadata["entry"]);
5981  break;
5982  case "hide_title_points":
5983  $this->setTitleOutput($metadata["entry"]);
5984  break;
5985  case "title_output":
5986  $this->setTitleOutput($metadata["entry"]);
5987  break;
5988  case "question_set_type":
5989  $this->setQuestionSetType($metadata["entry"]);
5990  break;
5991  case "random_test":
5992  if( $metadata["entry"] )
5993  {
5994  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
5995  }
5996  else
5997  {
5998  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
5999  }
6000  break;
6001  case "results_presentation":
6002  $this->setResultsPresentation($metadata["entry"]);
6003  break;
6004  case "reset_processing_time":
6005  $this->setResetProcessingTime($metadata["entry"]);
6006  break;
6007  case "instant_verification":
6008  $this->setInstantFeedbackSolution($metadata["entry"]);
6009  break;
6010  case "answer_feedback_points":
6011  $this->setAnswerFeedbackPoints($metadata["entry"]);
6012  break;
6013  case "anonymity":
6014  $this->setAnonymity($metadata["entry"]);
6015  break;
6016  case "show_cancel":
6017  $this->setShowCancel($metadata["entry"]);
6018  break;
6019  case "show_marker":
6020  $this->setShowMarker($metadata["entry"]);
6021  break;
6022  case "fixed_participants":
6023  $this->setFixedParticipants($metadata["entry"]);
6024  break;
6025  case "score_reporting":
6026  $this->setScoreReporting($metadata["entry"]);
6027  break;
6028  case "shuffle_questions":
6029  $this->setShuffleQuestions($metadata["entry"]);
6030  break;
6031  case "count_system":
6032  $this->setCountSystem($metadata["entry"]);
6033  break;
6034  case "mc_scoring":
6035  $this->setMCScoring($metadata["entry"]);
6036  break;
6037  case "mailnotification":
6038  $this->setMailNotification($metadata["entry"]);
6039  break;
6040  case "mailnottype":
6041  $this->setMailNotificationType($metadata["entry"]);
6042  break;
6043  case "exportsettings":
6044  $this->setExportSettings($metadata['entry']);
6045  break;
6046  case "score_cutting":
6047  $this->setScoreCutting($metadata["entry"]);
6048  break;
6049  case "password":
6050  $this->setPassword($metadata["entry"]);
6051  $this->setPasswordEnabled(strlen($metadata["entry"]) > 0);
6052  break;
6053  case "allowedUsers":
6054  $this->setAllowedUsers($metadata["entry"]);
6055  $this->setLimitUsersEnabled((int)$metadata["entry"] > 0);
6056  break;
6057  case "allowedUsersTimeGap":
6058  $this->setAllowedUsersTimeGap($metadata["entry"]);
6059  break;
6060  case "pass_scoring":
6061  $this->setPassScoring($metadata["entry"]);
6062  break;
6063  case "show_summary":
6064  $this->setListOfQuestionsSettings($metadata["entry"]);
6065  break;
6066  case "reporting_date":
6067  $iso8601period = $metadata["entry"];
6068  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6069  {
6070  $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6071  }
6072  break;
6073  case 'enable_processing_time':
6074  $this->setEnableProcessingTime($metadata['entry']);
6075  break;
6076  case "processing_time":
6077  $this->setProcessingTime($metadata['entry']);
6078  break;
6079  case "starting_time":
6080  $iso8601period = $metadata["entry"];
6081  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6082  {
6083  $this->setStartingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6084  $this->setStartingTimeEnabled(true);
6085  }
6086  break;
6087  case "ending_time":
6088  $iso8601period = $metadata["entry"];
6089  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6090  {
6091  $this->setEndingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6092  $this->setEndingTimeEnabled(true);
6093  }
6094  break;
6095  case "enable_examview":
6096  $this->setEnableExamview($metadata["entry"]);
6097  break;
6098  case 'show_examview_html':
6099  $this->setShowExamviewHtml($metadata['entry']);
6100  break;
6101  case 'show_examview_pdf':
6102  $this->setShowExamviewPdf($metadata['entry']);
6103  break;
6104  case 'redirection_mode':
6105  $this->setRedirectionMode($metadata['entry']);
6106  break;
6107  case 'redirection_url':
6108  $this->setRedirectionUrl($metadata['entry']);
6109  break;
6110  case 'examid_in_kiosk':
6111  case 'examid_in_test_pass':
6112  $this->setShowExamIdInTestPassEnabled($metadata['entry']);
6113  break;
6114  case 'show_exam_id':
6115  case 'examid_in_test_res':
6116  $this->setShowExamIdInTestResultsEnabled($metadata['entry']);
6117  break;
6118  case 'enable_archiving':
6119  $this->setEnableArchiving($metadata['entry']);
6120  break;
6121  case 'sign_submission':
6122  $this->setSignSubmission($metadata['entry']);
6123  break;
6124  case 'char_selector_availability':
6125  $this->setCharSelectorAvailability($metadata['entry']);
6126  break;
6127  case 'char_selector_definition':
6128  $this->setCharSelectorDefinition($metadata['entry']);
6129  break;
6130  case 'skill_service':
6131  $this->setSkillServiceEnabled((bool)$metadata['entry']);
6132  break;
6133  case 'result_tax_filters':
6134  $this->setResultFilterTaxIds(strlen($metadata['entry']) ? unserialize($metadata['entry']) : array());
6135  break;
6136  case 'show_grading_status':
6137  $this->setShowGradingStatusEnabled((bool)$metadata['entry']);
6138  break;
6139  case 'show_grading_mark':
6140  $this->setShowGradingMarkEnabled((bool)$metadata['entry']);
6141  break;
6142  case 'activation_limited':
6143  $this->setActivationLimited($metadata['entry']);
6144  break;
6145  case 'activation_start_time':
6146  $this->setActivationStartingTime($metadata['entry']);
6147  break;
6148  case 'activation_end_time':
6149  $this->setActivationEndingTime($metadata['entry']);
6150  break;
6151  case 'activation_visibility':
6152  $this->setActivationVisibility($metadata['entry']);
6153  break;
6154  case 'autosave':
6155  $this->setAutosave($metadata['entry']);
6156  break;
6157  case 'autosave_ival':
6158  $this->setAutosaveIval($metadata['entry']);
6159  break;
6160  case 'offer_question_hints':
6161  $this->setOfferingQuestionHintsEnabled($metadata['entry']);
6162  break;
6163  case 'instant_feedback_specific':
6164  $this->setSpecificAnswerFeedback($metadata['entry']);
6165  break;
6166  case 'instant_feedback_answer_fixation':
6167  $this->setInstantFeedbackAnswerFixationEnabled($metadata['entry']);
6168  break;
6169  case 'obligations_enabled':
6170  $this->setObligationsEnabled($metadata['entry']);
6171  break;
6172  }
6173  if (preg_match("/mark_step_\d+/", $metadata["label"]))
6174  {
6175  $xmlmark = $metadata["entry"];
6176  preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
6177  $mark_short = $matches[1];
6178  preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
6179  $mark_official = $matches[1];
6180  preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
6181  $mark_percentage = $matches[1];
6182  preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
6183  $mark_passed = $matches[1];
6184  $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
6185  }
6186  }
6187  // handle the import of media objects in XHTML code
6188  if (is_array($_SESSION["import_mob_xhtml"]))
6189  {
6190  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6191  include_once "./Services/RTE/classes/class.ilRTE.php";
6192  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
6193  foreach ($_SESSION["import_mob_xhtml"] as $mob)
6194  {
6195  $importfile = ilObjTest::_getImportDirectory() . '/' . $_SESSION["tst_import_subdir"] . '/' . $mob["uri"];
6196  if (file_exists($importfile))
6197  {
6198  $media_object =& ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, FALSE);
6199  ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
6200  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
6201  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
6202  }
6203  else
6204  {
6205  global $ilLog;
6206  $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
6207  }
6208  }
6209  $this->saveToDb();
6210  }
6211  }
6212 
6218  public function toXML()
6219  {
6220  include_once("./Services/Xml/classes/class.ilXmlWriter.php");
6221  $a_xml_writer = new ilXmlWriter;
6222  // set xml header
6223  $a_xml_writer->xmlHeader();
6224  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
6225  $a_xml_writer->xmlStartTag("questestinterop");
6226 
6227  $attrs = array(
6228  "ident" => "il_".IL_INST_ID."_tst_".$this->getTestId(),
6229  "title" => $this->getTitle()
6230  );
6231  $a_xml_writer->xmlStartTag("assessment", $attrs);
6232  // add qti comment
6233  $a_xml_writer->xmlElement("qticomment", NULL, $this->getDescription());
6234 
6235  // add qti duration
6236  if ($this->enable_processing_time)
6237  {
6238  preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
6239  $a_xml_writer->xmlElement("duration", NULL, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
6240  }
6241 
6242  // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
6243  $a_xml_writer->xmlStartTag("qtimetadata");
6244  $a_xml_writer->xmlStartTag("qtimetadatafield");
6245  $a_xml_writer->xmlElement("fieldlabel", NULL, "ILIAS_VERSION");
6246  $a_xml_writer->xmlElement("fieldentry", NULL, $this->ilias->getSetting("ilias_version"));
6247  $a_xml_writer->xmlEndTag("qtimetadatafield");
6248 
6249  // anonymity
6250  $a_xml_writer->xmlStartTag("qtimetadatafield");
6251  $a_xml_writer->xmlElement("fieldlabel", NULL, "anonymity");
6252  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnonymity()));
6253  $a_xml_writer->xmlEndTag("qtimetadatafield");
6254 
6255  // question set type (fixed, random, dynamic, ...)
6256  $a_xml_writer->xmlStartTag("qtimetadatafield");
6257  $a_xml_writer->xmlElement("fieldlabel", NULL, "question_set_type");
6258  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getQuestionSetType());
6259  $a_xml_writer->xmlEndTag("qtimetadatafield");
6260 
6261  // sequence settings
6262  $a_xml_writer->xmlStartTag("qtimetadatafield");
6263  $a_xml_writer->xmlElement("fieldlabel", NULL, "sequence_settings");
6264  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getSequenceSettings());
6265  $a_xml_writer->xmlEndTag("qtimetadatafield");
6266 
6267  // author
6268  $a_xml_writer->xmlStartTag("qtimetadatafield");
6269  $a_xml_writer->xmlElement("fieldlabel", NULL, "author");
6270  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAuthor());
6271  $a_xml_writer->xmlEndTag("qtimetadatafield");
6272 
6273  // reset processing time
6274  $a_xml_writer->xmlStartTag("qtimetadatafield");
6275  $a_xml_writer->xmlElement("fieldlabel", NULL, "reset_processing_time");
6276  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getResetProcessingTime());
6277  $a_xml_writer->xmlEndTag("qtimetadatafield");
6278 
6279  // count system
6280  $a_xml_writer->xmlStartTag("qtimetadatafield");
6281  $a_xml_writer->xmlElement("fieldlabel", NULL, "count_system");
6282  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCountSystem());
6283  $a_xml_writer->xmlEndTag("qtimetadatafield");
6284 
6285  // multiple choice scoring
6286  $a_xml_writer->xmlStartTag("qtimetadatafield");
6287  $a_xml_writer->xmlElement("fieldlabel", NULL, "mc_scoring");
6288  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMCScoring());
6289  $a_xml_writer->xmlEndTag("qtimetadatafield");
6290 
6291  // multiple choice scoring
6292  $a_xml_writer->xmlStartTag("qtimetadatafield");
6293  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_cutting");
6294  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getScoreCutting());
6295  $a_xml_writer->xmlEndTag("qtimetadatafield");
6296 
6297  // multiple choice scoring
6298  $a_xml_writer->xmlStartTag("qtimetadatafield");
6299  $a_xml_writer->xmlElement("fieldlabel", NULL, "password");
6300  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassword());
6301  $a_xml_writer->xmlEndTag("qtimetadatafield");
6302 
6303  // allowed users
6304  $a_xml_writer->xmlStartTag("qtimetadatafield");
6305  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsers");
6306  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsers());
6307  $a_xml_writer->xmlEndTag("qtimetadatafield");
6308 
6309  // allowed users time gap
6310  $a_xml_writer->xmlStartTag("qtimetadatafield");
6311  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsersTimeGap");
6312  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsersTimeGap());
6313  $a_xml_writer->xmlEndTag("qtimetadatafield");
6314 
6315  // pass scoring
6316  $a_xml_writer->xmlStartTag("qtimetadatafield");
6317  $a_xml_writer->xmlElement("fieldlabel", NULL, "pass_scoring");
6318  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassScoring());
6319  $a_xml_writer->xmlEndTag("qtimetadatafield");
6320 
6321  // score reporting date
6322  if ($this->getReportingDate())
6323  {
6324  $a_xml_writer->xmlStartTag("qtimetadatafield");
6325  $a_xml_writer->xmlElement("fieldlabel", NULL, "reporting_date");
6326  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6327  $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]));
6328  $a_xml_writer->xmlEndTag("qtimetadatafield");
6329  }
6330  // number of tries
6331  $a_xml_writer->xmlStartTag("qtimetadatafield");
6332  $a_xml_writer->xmlElement("fieldlabel", NULL, "nr_of_tries");
6333  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getNrOfTries()));
6334  $a_xml_writer->xmlEndTag("qtimetadatafield");
6335 
6336  // kiosk
6337  $a_xml_writer->xmlStartTag("qtimetadatafield");
6338  $a_xml_writer->xmlElement("fieldlabel", NULL, "kiosk");
6339  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getKiosk()));
6340  $a_xml_writer->xmlEndTag("qtimetadatafield");
6341 
6342 
6343  //redirection_mode
6344  $a_xml_writer->xmlStartTag('qtimetadatafield');
6345  $a_xml_writer->xmlElement("fieldlabel", NULL, "redirection_mode");
6346  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getRedirectionMode());
6347  $a_xml_writer->xmlEndTag("qtimetadatafield");
6348 
6349  //redirection_url
6350  $a_xml_writer->xmlStartTag('qtimetadatafield');
6351  $a_xml_writer->xmlElement("fieldlabel", NULL, "redirection_url");
6352  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getRedirectionUrl());
6353  $a_xml_writer->xmlEndTag("qtimetadatafield");
6354 
6355  // use previous answers
6356  $a_xml_writer->xmlStartTag("qtimetadatafield");
6357  $a_xml_writer->xmlElement("fieldlabel", NULL, "use_previous_answers");
6358  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getUsePreviousAnswers());
6359  $a_xml_writer->xmlEndTag("qtimetadatafield");
6360 
6361  // hide title points
6362  $a_xml_writer->xmlStartTag("qtimetadatafield");
6363  $a_xml_writer->xmlElement("fieldlabel", NULL, "title_output");
6364  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getTitleOutput()));
6365  $a_xml_writer->xmlEndTag("qtimetadatafield");
6366 
6367  // results presentation
6368  $a_xml_writer->xmlStartTag("qtimetadatafield");
6369  $a_xml_writer->xmlElement("fieldlabel", NULL, "results_presentation");
6370  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getResultsPresentation()));
6371  $a_xml_writer->xmlEndTag("qtimetadatafield");
6372 
6373  // examid in test pass
6374  $a_xml_writer->xmlStartTag("qtimetadatafield");
6375  $a_xml_writer->xmlElement("fieldlabel", NULL, "examid_in_test_pass");
6376  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->isShowExamIdInTestPassEnabled()));
6377  $a_xml_writer->xmlEndTag("qtimetadatafield");
6378 
6379  // examid in kiosk
6380  $a_xml_writer->xmlStartTag("qtimetadatafield");
6381  $a_xml_writer->xmlElement("fieldlabel", NULL, "examid_in_test_res");
6382  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->isShowExamIdInTestResultsEnabled()));
6383  $a_xml_writer->xmlEndTag("qtimetadatafield");
6384 
6385  // solution details
6386  $a_xml_writer->xmlStartTag("qtimetadatafield");
6387  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_summary");
6388  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getListOfQuestionsSettings()));
6389  $a_xml_writer->xmlEndTag("qtimetadatafield");
6390 
6391  // solution details
6392  $a_xml_writer->xmlStartTag("qtimetadatafield");
6393  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_reporting");
6394  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getScoreReporting()));
6395  $a_xml_writer->xmlEndTag("qtimetadatafield");
6396 
6397  // solution details
6398  $a_xml_writer->xmlStartTag("qtimetadatafield");
6399  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_verification");
6400  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getInstantFeedbackSolution()));
6401  $a_xml_writer->xmlEndTag("qtimetadatafield");
6402 
6403  // answer specific feedback
6404  $a_xml_writer->xmlStartTag("qtimetadatafield");
6405  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback");
6406  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedback()));
6407  $a_xml_writer->xmlEndTag("qtimetadatafield");
6408 
6409  // answer specific feedback of reached points
6410  $a_xml_writer->xmlStartTag("qtimetadatafield");
6411  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback_points");
6412  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedbackPoints()));
6413  $a_xml_writer->xmlEndTag("qtimetadatafield");
6414 
6415  // highscore
6416  $highscore_metadata = array(
6417  'highscore_enabled' => array('value' => $this->getHighscoreEnabled()),
6418  'highscore_anon' => array('value' => $this->getHighscoreAnon()),
6419  'highscore_achieved_ts' => array('value' => $this->getHighscoreAchievedTS()),
6420  'highscore_score' => array('value' => $this->getHighscoreScore()),
6421  'highscore_percentage' => array('value' => $this->getHighscorePercentage()),
6422  'highscore_hints' => array('value' => $this->getHighscoreHints()),
6423  'highscore_wtime' => array('value' => $this->getHighscoreWTime()),
6424  'highscore_own_table' => array('value' => $this->getHighscoreOwnTable()),
6425  'highscore_top_table' => array('value' => $this->getHighscoreTopTable()),
6426  'highscore_top_num' => array('value' => $this->getHighscoreTopNum()),
6427  );
6428  foreach($highscore_metadata as $label => $data)
6429  {
6430  $a_xml_writer->xmlStartTag("qtimetadatafield");
6431  $a_xml_writer->xmlElement("fieldlabel", NULL, $label);
6432  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $data['value']));
6433  $a_xml_writer->xmlEndTag("qtimetadatafield");
6434  }
6435 
6436  // show cancel
6437  $a_xml_writer->xmlStartTag("qtimetadatafield");
6438  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_cancel");
6439  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowCancel()));
6440  $a_xml_writer->xmlEndTag("qtimetadatafield");
6441 
6442  // show marker
6443  $a_xml_writer->xmlStartTag("qtimetadatafield");
6444  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_marker");
6445  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowMarker()));
6446  $a_xml_writer->xmlEndTag("qtimetadatafield");
6447 
6448  // fixed participants
6449  $a_xml_writer->xmlStartTag("qtimetadatafield");
6450  $a_xml_writer->xmlElement("fieldlabel", NULL, "fixed_participants");
6451  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getFixedParticipants()));
6452  $a_xml_writer->xmlEndTag("qtimetadatafield");
6453 
6454  // show final statement
6455  $a_xml_writer->xmlStartTag("qtimetadatafield");
6456  $a_xml_writer->xmlElement("fieldlabel", NULL, "showfinalstatement");
6457  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6458  $a_xml_writer->xmlEndTag("qtimetadatafield");
6459 
6460  // show introduction only
6461  $a_xml_writer->xmlStartTag("qtimetadatafield");
6462  $a_xml_writer->xmlElement("fieldlabel", NULL, "showinfo");
6463  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6464  $a_xml_writer->xmlEndTag("qtimetadatafield");
6465 
6466  // mail notification
6467  $a_xml_writer->xmlStartTag("qtimetadatafield");
6468  $a_xml_writer->xmlElement("fieldlabel", NULL, "mailnotification");
6469  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMailNotification());
6470  $a_xml_writer->xmlEndTag("qtimetadatafield");
6471 
6472  // mail notification type
6473  $a_xml_writer->xmlStartTag("qtimetadatafield");
6474  $a_xml_writer->xmlElement("fieldlabel", NULL, "mailnottype");
6475  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMailNotificationType());
6476  $a_xml_writer->xmlEndTag("qtimetadatafield");
6477 
6478  // export settings
6479  $a_xml_writer->xmlStartTag("qtimetadatafield");
6480  $a_xml_writer->xmlElement("fieldlabel", NULL, "exportsettings");
6481  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getExportSettings());
6482  $a_xml_writer->xmlEndTag("qtimetadatafield");
6483 
6484  // force JavaScript
6485  $a_xml_writer->xmlStartTag("qtimetadatafield");
6486  $a_xml_writer->xmlElement("fieldlabel", NULL, "forcejs");
6487  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6488  $a_xml_writer->xmlEndTag("qtimetadatafield");
6489 
6490  // custom style
6491  $a_xml_writer->xmlStartTag("qtimetadatafield");
6492  $a_xml_writer->xmlElement("fieldlabel", NULL, "customstyle");
6493  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCustomStyle());
6494  $a_xml_writer->xmlEndTag("qtimetadatafield");
6495 
6496  // shuffle questions
6497  $a_xml_writer->xmlStartTag("qtimetadatafield");
6498  $a_xml_writer->xmlElement("fieldlabel", NULL, "shuffle_questions");
6499  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShuffleQuestions()));
6500  $a_xml_writer->xmlEndTag("qtimetadatafield");
6501 
6502  // processing time
6503  $a_xml_writer->xmlStartTag("qtimetadatafield");
6504  $a_xml_writer->xmlElement("fieldlabel", NULL, "processing_time");
6505  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getProcessingTime());
6506  $a_xml_writer->xmlEndTag("qtimetadatafield");
6507 
6508  // enable_examview
6509  $a_xml_writer->xmlStartTag("qtimetadatafield");
6510  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_examview");
6511  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableExamview());
6512  $a_xml_writer->xmlEndTag("qtimetadatafield");
6513 
6514  // show_examview_html
6515  $a_xml_writer->xmlStartTag("qtimetadatafield");
6516  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_examview_html");
6517  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowExamviewHtml());
6518  $a_xml_writer->xmlEndTag("qtimetadatafield");
6519 
6520  // show_examview_pdf
6521  $a_xml_writer->xmlStartTag("qtimetadatafield");
6522  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_examview_pdf");
6523  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowExamviewPdf());
6524  $a_xml_writer->xmlEndTag("qtimetadatafield");
6525 
6526  // enable_archiving
6527  $a_xml_writer->xmlStartTag("qtimetadatafield");
6528  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_archiving");
6529  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableArchiving());
6530  $a_xml_writer->xmlEndTag("qtimetadatafield");
6531 
6532  // sign_submission
6533  $a_xml_writer->xmlStartTag("qtimetadatafield");
6534  $a_xml_writer->xmlElement("fieldlabel", NULL, "sign_submission");
6535  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getSignSubmission());
6536  $a_xml_writer->xmlEndTag("qtimetadatafield");
6537 
6538  // char_selector_availability
6539  $a_xml_writer->xmlStartTag("qtimetadatafield");
6540  $a_xml_writer->xmlElement("fieldlabel", NULL, "char_selector_availability");
6541  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getCharSelectorAvailability()));
6542  $a_xml_writer->xmlEndTag("qtimetadatafield");
6543 
6544  // char_selector_definition
6545  $a_xml_writer->xmlStartTag("qtimetadatafield");
6546  $a_xml_writer->xmlElement("fieldlabel", NULL, "char_selector_definition");
6547  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCharSelectorDefinition());
6548  $a_xml_writer->xmlEndTag("qtimetadatafield");
6549 
6550  // skill_service
6551  $a_xml_writer->xmlStartTag("qtimetadatafield");
6552  $a_xml_writer->xmlElement("fieldlabel", NULL, "skill_service");
6553  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isSkillServiceEnabled());
6554  $a_xml_writer->xmlEndTag("qtimetadatafield");
6555 
6556  // result_tax_filters
6557  $a_xml_writer->xmlStartTag("qtimetadatafield");
6558  $a_xml_writer->xmlElement("fieldlabel", NULL, "result_tax_filters");
6559  $a_xml_writer->xmlElement("fieldentry", NULL, serialize((array)$this->getResultFilterTaxIds()));
6560  $a_xml_writer->xmlEndTag("qtimetadatafield");
6561 
6562  // show_grading_status
6563  $a_xml_writer->xmlStartTag("qtimetadatafield");
6564  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_grading_status");
6565  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isShowGradingStatusEnabled());
6566  $a_xml_writer->xmlEndTag("qtimetadatafield");
6567 
6568  // show_grading_mark
6569  $a_xml_writer->xmlStartTag("qtimetadatafield");
6570  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_grading_mark");
6571  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isShowGradingMarkEnabled());
6572  $a_xml_writer->xmlEndTag("qtimetadatafield");
6573 
6574 
6575  // starting time
6576  if ($this->getStartingTime())
6577  {
6578  $a_xml_writer->xmlStartTag("qtimetadatafield");
6579  $a_xml_writer->xmlElement("fieldlabel", NULL, "starting_time");
6580  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->starting_time, $matches);
6581  $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]));
6582  $a_xml_writer->xmlEndTag("qtimetadatafield");
6583  }
6584  // ending time
6585  if ($this->getEndingTime())
6586  {
6587  $a_xml_writer->xmlStartTag("qtimetadatafield");
6588  $a_xml_writer->xmlElement("fieldlabel", NULL, "ending_time");
6589  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->ending_time, $matches);
6590  $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]));
6591  $a_xml_writer->xmlEndTag("qtimetadatafield");
6592  }
6593 
6594 
6595  //activation_limited
6596  $a_xml_writer->xmlStartTag("qtimetadatafield");
6597  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_limited");
6598  $a_xml_writer->xmlElement("fieldentry", NULL,(int)$this->isActivationLimited());
6599  $a_xml_writer->xmlEndTag("qtimetadatafield");
6600 
6601  //activation_start_time
6602  $a_xml_writer->xmlStartTag("qtimetadatafield");
6603  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_start_time");
6604  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationStartingTime());
6605  $a_xml_writer->xmlEndTag("qtimetadatafield");
6606 
6607  //activation_end_time
6608  $a_xml_writer->xmlStartTag("qtimetadatafield");
6609  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_end_time");
6610  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationEndingTime());
6611  $a_xml_writer->xmlEndTag("qtimetadatafield");
6612 
6613  //activation_visibility
6614  $a_xml_writer->xmlStartTag("qtimetadatafield");
6615  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_visibility");
6616  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationVisibility());
6617  $a_xml_writer->xmlEndTag("qtimetadatafield");
6618 
6619  // autosave
6620  $a_xml_writer->xmlStartTag("qtimetadatafield");
6621  $a_xml_writer->xmlElement("fieldlabel", NULL, "autosave");
6622  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getAutosave());
6623  $a_xml_writer->xmlEndTag("qtimetadatafield");
6624 
6625  // autosave_ival
6626  $a_xml_writer->xmlStartTag("qtimetadatafield");
6627  $a_xml_writer->xmlElement("fieldlabel", NULL, "autosave_ival");
6628  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getAutosaveIval());
6629  $a_xml_writer->xmlEndTag("qtimetadatafield");
6630 
6631  //offer_question_hints
6632  $a_xml_writer->xmlStartTag("qtimetadatafield");
6633  $a_xml_writer->xmlElement("fieldlabel", NULL, "offer_question_hints");
6634  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isOfferingQuestionHintsEnabled());
6635  $a_xml_writer->xmlEndTag("qtimetadatafield");
6636 
6637  //instant_feedback_specific
6638  $a_xml_writer->xmlStartTag("qtimetadatafield");
6639  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_feedback_specific");
6640  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getSpecificAnswerFeedback());
6641  $a_xml_writer->xmlEndTag("qtimetadatafield");
6642 
6643  //instant_feedback_answer_fixation
6644  $a_xml_writer->xmlStartTag("qtimetadatafield");
6645  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_feedback_answer_fixation");
6646  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isInstantFeedbackAnswerFixationEnabled());
6647  $a_xml_writer->xmlEndTag("qtimetadatafield");
6648 
6649  //obligations_enabled
6650  $a_xml_writer->xmlStartTag("qtimetadatafield");
6651  $a_xml_writer->xmlElement("fieldlabel", NULL, "obligations_enabled");
6652  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->areObligationsEnabled());
6653  $a_xml_writer->xmlEndTag("qtimetadatafield");
6654 
6655  //enable_processing_time
6656  $a_xml_writer->xmlStartTag("qtimetadatafield");
6657  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_processing_time");
6658  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableProcessingTime());
6659  $a_xml_writer->xmlEndTag("qtimetadatafield");
6660 
6661  foreach ($this->mark_schema->mark_steps as $index => $mark)
6662  {
6663  // mark steps
6664  $a_xml_writer->xmlStartTag("qtimetadatafield");
6665  $a_xml_writer->xmlElement("fieldlabel", NULL, "mark_step_$index");
6666  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf(
6667  "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
6668  $mark->getShortName(), $mark->getOfficialName(), $mark->getMinimumLevel(), $mark->getPassed()
6669  ));
6670  $a_xml_writer->xmlEndTag("qtimetadatafield");
6671  }
6672  $a_xml_writer->xmlEndTag("qtimetadata");
6673 
6674  // add qti objectives
6675  $a_xml_writer->xmlStartTag("objectives");
6676  $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6677  $a_xml_writer->xmlEndTag("objectives");
6678 
6679  // add qti assessmentcontrol
6680  if ($this->getInstantFeedbackSolution() == 1)
6681  {
6682  $attrs = array(
6683  "solutionswitch" => "Yes"
6684  );
6685  }
6686  else
6687  {
6688  $attrs = NULL;
6689  }
6690  $a_xml_writer->xmlElement("assessmentcontrol", $attrs, NULL);
6691 
6692  if (strlen($this->getFinalStatement()))
6693  {
6694  // add qti presentation_material
6695  $a_xml_writer->xmlStartTag("presentation_material");
6696  $a_xml_writer->xmlStartTag("flow_mat");
6697  $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6698  $a_xml_writer->xmlEndTag("flow_mat");
6699  $a_xml_writer->xmlEndTag("presentation_material");
6700  }
6701 
6702  $attrs = array(
6703  "ident" => "1"
6704  );
6705  $a_xml_writer->xmlElement("section", $attrs, NULL);
6706  $a_xml_writer->xmlEndTag("assessment");
6707  $a_xml_writer->xmlEndTag("questestinterop");
6708 
6709  $xml = $a_xml_writer->xmlDumpMem(FALSE);
6710 
6711  foreach ($this->questions as $question_id)
6712  {
6713  $question =& ilObjTest::_instanciateQuestion($question_id);
6714  $qti_question = $question->toXML(false);
6715  $qti_question = preg_replace("/<questestinterop>/", "", $qti_question);
6716  $qti_question = preg_replace("/<\/questestinterop>/", "", $qti_question);
6717  if (strpos($xml, "</section>") !== false)
6718  {
6719  $xml = str_replace("</section>", "$qti_question</section>", $xml);
6720  }
6721  else
6722  {
6723  $xml = str_replace("<section ident=\"1\"/>", "<section ident=\"1\">\n$qti_question</section>", $xml);
6724  }
6725  }
6726  return $xml;
6727  }
6728 
6735  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6736  {
6737  global $ilBench;
6738 
6739  $this->mob_ids = array();
6740  $this->file_ids = array();
6741 
6742  $attrs = array();
6743  $attrs["Type"] = "Test";
6744  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
6745 
6746  // MetaData
6747  $this->exportXMLMetaData($a_xml_writer);
6748 
6749  // PageObjects
6750  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
6751  $ilBench->start("ContentObjectExport", "exportPageObjects");
6752  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6753  $ilBench->stop("ContentObjectExport", "exportPageObjects");
6754  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
6755 
6756  // MediaObjects
6757  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
6758  $ilBench->start("ContentObjectExport", "exportMediaObjects");
6759  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6760  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6761  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
6762 
6763  // FileItems
6764  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
6765  $ilBench->start("ContentObjectExport", "exportFileItems");
6766  $this->exportFileItems($a_target_dir, $expLog);
6767  $ilBench->stop("ContentObjectExport", "exportFileItems");
6768  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
6769 
6770  $a_xml_writer->xmlEndTag("ContentObject");
6771  }
6772 
6779  function exportXMLMetaData(&$a_xml_writer)
6780  {
6781  include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6782  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6783  $md2xml->setExportMode(true);
6784  $md2xml->startExport();
6785  $a_xml_writer->appendXML($md2xml->getXML());
6786  }
6787 
6793  function modifyExportIdentifier($a_tag, $a_param, $a_value)
6794  {
6795  if ($a_tag == "Identifier" && $a_param == "Entry")
6796  {
6797  include_once "./Services/Utilities/classes/class.ilUtil.php";
6798  $a_value = ilUtil::insertInstIntoID($a_value);
6799  }
6800 
6801  return $a_value;
6802  }
6803 
6804 
6811  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6812  {
6813  global $ilBench;
6814 
6815  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6816 
6817  foreach ($this->questions as $question_id)
6818  {
6819  $ilBench->start("ContentObjectExport", "exportPageObject");
6820  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
6821 
6822  $attrs = array();
6823  $a_xml_writer->xmlStartTag("PageObject", $attrs);
6824 
6825 
6826  // export xml to writer object
6827  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6828  include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
6829  $page_object = new ilAssQuestionPage($question_id);
6830  $page_object->buildDom();
6831  $page_object->insertInstIntoIDs($a_inst);
6832  $mob_ids = $page_object->collectMediaObjects(false);
6833  require_once 'Services/COPage/classes/class.ilPCFileList.php';
6834  $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
6835  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6836  $xml = str_replace("&","&amp;", $xml);
6837  $a_xml_writer->appendXML($xml);
6838  $page_object->freeDom();
6839  unset ($page_object);
6840 
6841  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6842 
6843  // collect media objects
6844  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6845  //$mob_ids = $page_obj->getMediaObjectIDs();
6846  foreach($mob_ids as $mob_id)
6847  {
6848  $this->mob_ids[$mob_id] = $mob_id;
6849  }
6850  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6851 
6852  // collect all file items
6853  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6854  //$file_ids = $page_obj->getFileItemIds();
6855  foreach($file_ids as $file_id)
6856  {
6857  $this->file_ids[$file_id] = $file_id;
6858  }
6859  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6860 
6861  $a_xml_writer->xmlEndTag("PageObject");
6862  //unset($page_obj);
6863 
6864  $ilBench->stop("ContentObjectExport", "exportPageObject");
6865 
6866 
6867  }
6868  }
6869 
6876  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6877  {
6878  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6879 
6880  foreach ($this->mob_ids as $mob_id)
6881  {
6882  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
6883  if (ilObjMediaObject::_exists($mob_id))
6884  {
6885  $media_obj = new ilObjMediaObject($mob_id);
6886  $media_obj->exportXML($a_xml_writer, $a_inst);
6887  $media_obj->exportFiles($a_target_dir);
6888  unset($media_obj);
6889  }
6890  }
6891  }
6892 
6897  function exportFileItems($a_target_dir, &$expLog)
6898  {
6899  include_once "./Modules/File/classes/class.ilObjFile.php";
6900 
6901  foreach ($this->file_ids as $file_id)
6902  {
6903  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
6904  $file_obj = new ilObjFile($file_id, false);
6905  $file_obj->export($a_target_dir);
6906  unset($file_obj);
6907  }
6908  }
6909 
6914  function getImportMapping()
6915  {
6916  if (!is_array($this->import_mapping))
6917  {
6918  return array();
6919  }
6920  else
6921  {
6922  return $this->import_mapping;
6923  }
6924  }
6925 
6929  public function canEditEctsGrades()
6930  {
6931  return $this->getReportingDate();
6932  }
6933 
6937  public function getECTSGrade($passed_array, $reached_points, $max_points)
6938  {
6939  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);
6940  }
6941 
6945  public static function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6946  {
6947  include_once "./Modules/Test/classes/class.ilStatistics.php";
6948  // calculate the median
6949  $passed_statistics = new ilStatistics();
6950  $passed_statistics->setData($points_passed);
6951  $ects_percentiles = array
6952  (
6953  "A" => $passed_statistics->quantile($a),
6954  "B" => $passed_statistics->quantile($b),
6955  "C" => $passed_statistics->quantile($c),
6956  "D" => $passed_statistics->quantile($d),
6957  "E" => $passed_statistics->quantile($e)
6958  );
6959  if (count($points_passed) && ($reached_points >= $ects_percentiles["A"]))
6960  {
6961  return "A";
6962  }
6963  else if (count($points_passed) && ($reached_points >= $ects_percentiles["B"]))
6964  {
6965  return "B";
6966  }
6967  else if (count($points_passed) && ($reached_points >= $ects_percentiles["C"]))
6968  {
6969  return "C";
6970  }
6971  else if (count($points_passed) && ($reached_points >= $ects_percentiles["D"]))
6972  {
6973  return "D";
6974  }
6975  else if (count($points_passed) && ($reached_points >= $ects_percentiles["E"]))
6976  {
6977  return "E";
6978  }
6979  else if (strcmp($fx, "") != 0)
6980  {
6981  if ($max_points > 0)
6982  {
6983  $percentage = ($reached_points / $max_points) * 100.0;
6984  if ($percentage < 0) $percentage = 0.0;
6985  }
6986  else
6987  {
6988  $percentage = 0.0;
6989  }
6990  if ($percentage >= $fx)
6991  {
6992  return "FX";
6993  }
6994  else
6995  {
6996  return "F";
6997  }
6998  }
6999  else
7000  {
7001  return "F";
7002  }
7003  }
7004 
7008  public function checkMarks()
7009  {
7010  return $this->mark_schema->checkMarks();
7011  }
7012 
7016  public function getMarkSchema()
7017  {
7018  return $this->mark_schema;
7019  }
7020 
7024  public function getMarkSchemaForeignId()
7025  {
7026  return $this->getTestId();
7027  }
7028 
7031  public function onMarkSchemaSaved()
7032  {
7038  global $ilDB, $ilPluginAdmin, $tree;
7039 
7040  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
7041  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7042  $this->saveCompleteStatus($testQuestionSetConfigFactory->getQuestionSetConfig());
7043 
7044  if( $this->participantDataExist() )
7045  {
7046  $this->recalculateScores(true);
7047  }
7048  }
7049 
7053  public function canEditMarks()
7054  {
7055  $total = $this->evalTotalPersons();
7056  if($total > 0)
7057  {
7058  if($this->getReportingDate())
7059  {
7060  if(preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
7061  {
7062  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
7063  $now = mktime();
7064  if($now < $epoch_time)
7065  {
7066  return true;
7067  }
7068  }
7069  }
7070  return false;
7071  }
7072  else
7073  {
7074  return true;
7075  }
7076  }
7077 
7085  function setAuthor($author = "")
7086  {
7087  $this->author = $author;
7088  }
7089 
7099  function saveAuthorToMetadata($a_author = "")
7100  {
7101  $md =& new ilMD($this->getId(), 0, $this->getType());
7102  $md_life =& $md->getLifecycle();
7103  if (!$md_life)
7104  {
7105  if (strlen($a_author) == 0)
7106  {
7107  global $ilUser;
7108  $a_author = $ilUser->getFullname();
7109  }
7110 
7111  $md_life =& $md->addLifecycle();
7112  $md_life->save();
7113  $con =& $md_life->addContribute();
7114  $con->setRole("Author");
7115  $con->save();
7116  $ent =& $con->addEntity();
7117  $ent->setEntity($a_author);
7118  $ent->save();
7119  }
7120  }
7121 
7127  function createMetaData()
7128  {
7130  $this->saveAuthorToMetadata();
7131  }
7132 
7140  function getAuthor()
7141  {
7142  $author = array();
7143  include_once "./Services/MetaData/classes/class.ilMD.php";
7144  $md =& new ilMD($this->getId(), 0, $this->getType());
7145  $md_life =& $md->getLifecycle();
7146  if ($md_life)
7147  {
7148  $ids =& $md_life->getContributeIds();
7149  foreach ($ids as $id)
7150  {
7151  $md_cont =& $md_life->getContribute($id);
7152  if (strcmp($md_cont->getRole(), "Author") == 0)
7153  {
7154  $entids =& $md_cont->getEntityIds();
7155  foreach ($entids as $entid)
7156  {
7157  $md_ent =& $md_cont->getEntity($entid);
7158  array_push($author, $md_ent->getEntity());
7159  }
7160  }
7161  }
7162  }
7163  return join($author, ",");
7164  }
7165 
7173  function _lookupAuthor($obj_id)
7174  {
7175  $author = array();
7176  include_once "./Services/MetaData/classes/class.ilMD.php";
7177  $md =& new ilMD($obj_id, 0, "tst");
7178  $md_life =& $md->getLifecycle();
7179  if ($md_life)
7180  {
7181  $ids =& $md_life->getContributeIds();
7182  foreach ($ids as $id)
7183  {
7184  $md_cont =& $md_life->getContribute($id);
7185  if (strcmp($md_cont->getRole(), "Author") == 0)
7186  {
7187  $entids =& $md_cont->getEntityIds();
7188  foreach ($entids as $entid)
7189  {
7190  $md_ent =& $md_cont->getEntity($entid);
7191  array_push($author, $md_ent->getEntity());
7192  }
7193  }
7194  }
7195  }
7196  return join($author, ",");
7197  }
7198 
7205  function &_getAvailableTests($use_object_id = FALSE)
7206  {
7207  global $ilUser;
7208  global $ilDB;
7209 
7210  $result_array = array();
7211  $tests = ilUtil::_getObjectsByOperations("tst","write", $ilUser->getId(), -1);
7212  if (count($tests))
7213  {
7214  $titles = ilObject::_prepareCloneSelection($tests, "tst");
7215  foreach ($tests as $ref_id)
7216  {
7217  if ($use_object_id)
7218  {
7219  $obj_id = ilObject::_lookupObjId($ref_id);
7220  $result_array[$obj_id] = $titles[$ref_id];
7221  }
7222  else
7223  {
7224  $result_array[$ref_id] = $titles[$ref_id];
7225  }
7226  }
7227  }
7228  return $result_array;
7229  }
7230 
7239  public function cloneObject($a_target_id,$a_copy_id = 0)
7240  {
7241  global $ilLog, $tree, $ilDB, $ilPluginAdmin;
7242 
7243  $this->loadFromDb();
7244 
7245  // Copy settings
7247  $newObj = parent::cloneObject($a_target_id,$a_copy_id);
7248  $this->cloneMetaData($newObj);
7249 
7250  //copy online status if object is not the root copy object
7251  $cp_options = ilCopyWizardOptions::_getInstance($a_copy_id);
7252 
7253  if(!$cp_options->isRootNode($this->getRefId()))
7254  {
7255  $newObj->setOnline($this->isOnline());
7256  }
7257 
7258  $newObj->setAnonymity($this->getAnonymity());
7259  $newObj->setAnswerFeedback($this->getAnswerFeedback());
7260  $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
7261  $newObj->setAuthor($this->getAuthor());
7262  $newObj->setLimitUsersEnabled($this->isLimitUsersEnabled());
7263  $newObj->setAllowedUsers($this->getAllowedUsers());
7264  $newObj->setAllowedUsersTimeGap($this->getAllowedUsersTimeGap());
7265  $newObj->setCountSystem($this->getCountSystem());
7266  $newObj->setECTSFX($this->getECTSFX());
7267  $newObj->setECTSGrades($this->getECTSGrades());
7268  $newObj->setECTSOutput($this->getECTSOutput());
7269  $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
7270  $newObj->setEndingTimeEnabled($this->isEndingTimeEnabled());
7271  $newObj->setEndingTime($this->getEndingTime());
7272  $newObj->setFixedParticipants($this->getFixedParticipants());
7273  $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
7274  $newObj->setIntroductionEnabled($this->isIntroductionEnabled());
7275  $newObj->setIntroduction($this->getIntroduction());
7276  $newObj->setFinalStatement($this->getFinalStatement());
7277  $newObj->setShowInfo($this->getShowInfo());
7278  $newObj->setForceJS($this->getForceJS());
7279  $newObj->setCustomStyle($this->getCustomStyle());
7280  $newObj->setKiosk($this->getKiosk());
7281  $newObj->setShowFinalStatement($this->getShowFinalStatement());
7282  $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
7283  $newObj->setMCScoring($this->getMCScoring());
7284  $newObj->setMailNotification($this->getMailNotification());
7285  $newObj->setMailNotificationType($this->getMailNotificationType());
7286  $newObj->setNrOfTries($this->getNrOfTries());
7287  $newObj->setPassScoring($this->getPassScoring());
7288  $newObj->setPasswordEnabled($this->isPasswordEnabled());
7289  $newObj->setPassword($this->getPassword());
7290  $newObj->setProcessingTime($this->getProcessingTime());
7291  $newObj->setQuestionSetType($this->getQuestionSetType());
7292  $newObj->setReportingDate($this->getReportingDate());
7293  $newObj->setResetProcessingTime($this->getResetProcessingTime());
7294  $newObj->setResultsPresentation($this->getResultsPresentation());
7295  $newObj->setScoreCutting($this->getScoreCutting());
7296  $newObj->setScoreReporting($this->getScoreReporting());
7297  $newObj->setSequenceSettings($this->getSequenceSettings());
7298  $newObj->setShowCancel($this->getShowCancel());
7299  $newObj->setShowMarker($this->getShowMarker());
7300  $newObj->setShuffleQuestions($this->getShuffleQuestions());
7301  $newObj->setStartingTimeEnabled($this->isStartingTimeEnabled());
7302  $newObj->setStartingTime($this->getStartingTime());
7303  $newObj->setTitleOutput($this->getTitleOutput());
7304  $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
7305  $newObj->setRedirectionMode($this->getRedirectionMode());
7306  $newObj->setRedirectionUrl($this->getRedirectionUrl());
7307  $newObj->setCertificateVisibility($this->getCertificateVisibility());
7308  $newObj->mark_schema = clone $this->mark_schema;
7309  $newObj->setEnabledViewMode($this->getEnabledViewMode());
7310  $newObj->setTemplate($this->getTemplate());
7311  $newObj->setPoolUsage($this->getPoolUsage());
7312  $newObj->setPrintBestSolutionWithResult($this->isBestSolutionPrintedWithResult());
7313  $newObj->setShowExamIdInTestPassEnabled($this->isShowExamIdInTestPassEnabled());
7314  $newObj->setShowExamIdInTestResultsEnabled($this->isShowExamIdInTestResultsEnabled());
7315  $newObj->setEnableExamView($this->getEnableExamview());
7316  $newObj->setShowExamViewHtml($this->getShowExamviewHtml());
7317  $newObj->setShowExamViewPdf($this->getShowExamviewPdf());
7318  $newObj->setEnableArchiving($this->getEnableArchiving());
7319  $newObj->setSignSubmission($this->getSignSubmission());
7320  $newObj->setCharSelectorAvailability((int)$this->getCharSelectorAvailability());
7321  $newObj->setCharSelectorDefinition($this->getCharSelectorDefinition());
7322  $newObj->setSkillServiceEnabled($this->isSkillServiceEnabled());
7323  $newObj->setResultFilterTaxIds($this->getResultFilterTaxIds());
7324  $newObj->setInstantFeedbackAnswerFixationEnabled($this->isInstantFeedbackAnswerFixationEnabled());
7325  $newObj->saveToDb();
7326 
7327  // clone certificate
7328  include_once "./Services/Certificate/classes/class.ilCertificate.php";
7329  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
7330  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
7331  $newcert = new ilCertificate(new ilTestCertificateAdapter($newObj));
7332  $cert->cloneCertificate($newcert);
7333 
7334  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
7335  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7336  $testQuestionSetConfigFactory->getQuestionSetConfig()->cloneQuestionSetRelatedData($newObj);
7337 
7338  $newObj->saveToDb();
7339  $newObj->updateMetaData();// #14467
7340 
7341  include_once('./Services/Tracking/classes/class.ilLPObjSettings.php');
7342  $obj_settings = new ilLPObjSettings($this->getId());
7343  $obj_settings->cloneSettings($newObj->getId());
7344 
7345  return $newObj;
7346  }
7347 
7354  function getQuestionCount()
7355  {
7356  $num = 0;
7357 
7358  if( $this->isRandomTest() )
7359  {
7360  global $tree, $ilDB, $ilPluginAdmin;
7361 
7362  $questionSetConfig = new ilTestRandomQuestionSetConfig(
7363  $tree, $ilDB, $ilPluginAdmin, $this
7364  );
7365 
7366  $questionSetConfig->loadFromDb();
7367 
7368  if( $questionSetConfig->isQuestionAmountConfigurationModePerPool() )
7369  {
7370  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php';
7371  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetBuilderWithAmountPerPool.php';
7372  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php';
7373 
7374  $sourcePoolDefinitionList = new ilTestRandomQuestionSetSourcePoolDefinitionList(
7375  $ilDB, $this, new ilTestRandomQuestionSetSourcePoolDefinitionFactory($ilDB, $this)
7376  );
7377 
7378  $sourcePoolDefinitionList->loadDefinitions();
7379 
7380  $num = $sourcePoolDefinitionList->getQuestionAmount();
7381  }
7382  else
7383  {
7384  $num = $questionSetConfig->getQuestionAmountPerTest();
7385  }
7386  }
7387  else
7388  {
7389  $num = count($this->questions);
7390  }
7391 
7392  return $num;
7393  }
7394 
7402  function logAction($logtext = "", $question_id = "")
7403  {
7404  global $ilUser;
7405 
7406  $original_id = "";
7407  if (strcmp($question_id, "") != 0)
7408  {
7409  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7410  $original_id = assQuestion::_getOriginalId($question_id);
7411  }
7412  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7413  ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, TRUE, $this->getRefId());
7414  }
7415 
7424  {
7425  global $ilDB;
7426  $object_id = FALSE;
7427  $result = $ilDB->queryF("SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7428  array('integer'),
7429  array($test_id)
7430  );
7431  if ($result->numRows())
7432  {
7433  $row = $ilDB->fetchAssoc($result);
7434  $object_id = $row["obj_fi"];
7435  }
7436  return $object_id;
7437  }
7438 
7446  function _getObjectIDFromActiveID($active_id)
7447  {
7448  global $ilDB;
7449  $object_id = FALSE;
7450  $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",
7451  array('integer'),
7452  array($active_id)
7453  );
7454  if ($result->numRows())
7455  {
7456  $row = $ilDB->fetchAssoc($result);
7457  $object_id = $row["obj_fi"];
7458  }
7459  return $object_id;
7460  }
7461 
7469  function _getTestIDFromObjectID($object_id)
7470  {
7471  global $ilDB;
7472  $test_id = FALSE;
7473  $result = $ilDB->queryF("SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7474  array('integer'),
7475  array($object_id)
7476  );
7477  if ($result->numRows())
7478  {
7479  $row = $ilDB->fetchAssoc($result);
7480  $test_id = $row["test_id"];
7481  }
7482  return $test_id;
7483  }
7484 
7493  function getTextAnswer($active_id, $question_id, $pass = NULL)
7494  {
7495  global $ilDB;
7496 
7497  $res = "";
7498  if (($active_id) && ($question_id))
7499  {
7500  if (is_null($pass))
7501  {
7502  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7503  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7504  }
7505  $result = $ilDB->queryF("SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7506  array('integer', 'integer', 'integer'),
7507  array($active_id, $question_id, $pass)
7508  );
7509  if ($result->numRows() == 1)
7510  {
7511  $row = $ilDB->fetchAssoc($result);
7512  $res = $row["value1"];
7513  }
7514  }
7515  return $res;
7516  }
7517 
7525  function getQuestiontext($question_id)
7526  {
7527  global $ilDB;
7528 
7529  $res = "";
7530  if ($question_id)
7531  {
7532  $result = $ilDB->queryF("SELECT question_text FROM qpl_questions WHERE question_id = %s",
7533  array('integer'),
7534  array($question_id)
7535  );
7536  if ($result->numRows() == 1)
7537  {
7538  $row = $ilDB->fetchAssoc($result);
7539  $res = $row["question_text"];
7540  }
7541  }
7542  return $res;
7543  }
7544 
7551  function &getInvitedUsers($user_id="", $order="login, lastname, firstname")
7552  {
7553  global $ilDB;
7554 
7555  $result_array = array();
7556 
7557  if ($this->getAnonymity())
7558  {
7559  if (is_numeric($user_id))
7560  {
7561  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7562  "tst_active.submitted test_finished, matriculation FROM usr_data, tst_invited_user " .
7563  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7564  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7565  "ORDER BY $order",
7566  array('text', 'text', 'text', 'integer', 'integer'),
7567  array("", $this->lng->txt("anonymous"), "", $this->getTestId(), $user_id)
7568  );
7569  }
7570  else
7571  {
7572  $result = $ilDB->queryF("SELECT tst_active.active_id, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7573  "tst_active.submitted test_finished, matriculation 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 " .
7576  "ORDER BY $order",
7577  array('text', 'text', 'text', 'integer'),
7578  array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7579  );
7580  }
7581  }
7582  else
7583  {
7584  if (is_numeric($user_id))
7585  {
7586  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7587  "tst_active.submitted test_finished, matriculation FROM usr_data, tst_invited_user " .
7588  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7589  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7590  "ORDER BY $order",
7591  array('integer', 'integer'),
7592  array($this->getTestId(), $user_id)
7593  );
7594  }
7595  else
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 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 " .
7601  "ORDER BY $order",
7602  array('integer'),
7603  array($this->getTestId())
7604  );
7605  }
7606  }
7607  $result_array = array();
7608  while ($row = $ilDB->fetchAssoc($result))
7609  {
7610  $result_array[$row['usr_id']]= $row;
7611  }
7612  return $result_array;
7613  }
7614 
7622  {
7623  global $ilDB;
7624 
7625  if ($this->getAnonymity())
7626  {
7627  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, tst_active.user_fi usr_id, %s login, %s lastname, %s firstname, tst_active.submitted test_finished, usr_data.matriculation, usr_data.active ".
7628  "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),
7629  array('text', 'text', 'text', 'integer'),
7630  array("", $this->lng->txt("anonymous"), "", $this->getTestId())
7631  );
7632  }
7633  else
7634  {
7635  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, tst_active.user_fi usr_id, usr_data.login, usr_data.lastname, usr_data.firstname, tst_active.submitted test_finished, usr_data.matriculation, usr_data.active ".
7636  "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),
7637  array('integer'),
7638  array($this->getTestId())
7639  );
7640  }
7641  $data = array();
7642  while ($row = $ilDB->fetchAssoc($result))
7643  {
7644  $data[$row['active_id']] = $row;
7645  }
7646  foreach ($data as $index => $participant)
7647  {
7648  if (strlen(trim($participant["firstname"].$participant["lastname"])) == 0)
7649  {
7650  $data[$index]["lastname"] = $this->lng->txt("deleted_user");
7651  }
7652  }
7653  return $data;
7654  }
7655 
7656  public function getTestParticipantsForManualScoring($filter = NULL)
7657  {
7658  global $ilDB;
7659 
7660  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7662  if (count($scoring) == 0) return array();
7663 
7664  $participants =& $this->getTestParticipants();
7665  $filtered_participants = array();
7666  foreach ($participants as $active_id => $participant)
7667  {
7668  $qstType_IN_manScoreableQstTypes = $ilDB->in('qpl_questions.question_type_fi', $scoring, false, 'integer');
7669 
7670  $queryString = "
7671  SELECT tst_test_result.manual
7672 
7673  FROM tst_test_result
7674 
7675  INNER JOIN qpl_questions
7676  ON tst_test_result.question_fi = qpl_questions.question_id
7677 
7678  WHERE tst_test_result.active_fi = %s
7679  AND $qstType_IN_manScoreableQstTypes
7680  ";
7681 
7682  $result = $ilDB->queryF(
7683  $queryString, array("integer"), array($active_id)
7684  );
7685 
7686  $count = $result->numRows();
7687 
7688  if ($count > 0)
7689  {
7690  switch ($filter)
7691  {
7692  case 1: // only active users
7693  if ($participant->active) $filtered_participants[$active_id] = $participant;
7694  break;
7695  case 2: // only inactive users
7696  if (!$participant->active) $filtered_participants[$active_id] = $participant;
7697  break;
7698  case 3: // all users
7699  $filtered_participants[$active_id] = $participant;
7700  break;
7701  case 4:
7702  // already scored participants
7703  //$found = 0;
7704  //while ($row = $ilDB->fetchAssoc($result))
7705  //{
7706  // if ($row["manual"]) $found++;
7707  //}
7708  //if ($found == $count)
7709  //{
7710  //$filtered_participants[$active_id] = $participant;
7711  //}
7712  //else
7713  //{
7714  $assessmentSetting = new ilSetting("assessment");
7715  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7716  if ($manscoring_done) $filtered_participants[$active_id] = $participant;
7717  //}
7718  break;
7719  case 5:
7720  // unscored participants
7721  //$found = 0;
7722  //while ($row = $ilDB->fetchAssoc($result))
7723  //{
7724  // if ($row["manual"]) $found++;
7725  //}
7726  //if ($found == 0)
7727  //{
7728  $assessmentSetting = new ilSetting("assessment");
7729  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7730  if (!$manscoring_done) $filtered_participants[$active_id] = $participant;
7731  //}
7732  break;
7733  case 6:
7734  // partially scored participants
7735  $found = 0;
7736  while ($row = $ilDB->fetchAssoc($result))
7737  {
7738  if ($row["manual"]) $found++;
7739  }
7740  if (($found > 0) && ($found < $count)) $filtered_participants[$active_id] = $participant;
7741  break;
7742  default:
7743  $filtered_participants[$active_id] = $participant;
7744  break;
7745  }
7746  }
7747  }
7748  return $filtered_participants;
7749  }
7750 
7758  function &getUserData($ids)
7759  {
7760  global $ilDB;
7761 
7762  if (!is_array($ids) || count($ids) ==0) return array();
7763 
7764  if ($this->getAnonymity())
7765  {
7766  $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",
7767  array('text', 'text', 'text'),
7768  array("", $this->lng->txt("anonymous"), "")
7769  );
7770  }
7771  else
7772  {
7773  $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");
7774  }
7775 
7776  $result_array = array();
7777  while ($row = $ilDB->fetchAssoc($result))
7778  {
7779  $result_array[$row["usr_id"]]= $row;
7780  }
7781  return $result_array;
7782  }
7783 
7784  function &getGroupData($ids)
7785  {
7786  if (!is_array($ids) || count($ids) ==0) return array();
7787  $result = array();
7788  foreach ($ids as $ref_id)
7789  {
7790  $obj_id = ilObject::_lookupObjId($ref_id);
7791  $result[$ref_id] = array("ref_id" => $ref_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7792  }
7793  return $result;
7794  }
7795 
7796  function &getRoleData($ids)
7797  {
7798  if (!is_array($ids) || count($ids) ==0) return array();
7799  $result = array();
7800  foreach ($ids as $obj_id)
7801  {
7802  $result[$obj_id] = array("obj_id" => $obj_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7803  }
7804  return $result;
7805  }
7806 
7807 
7814  function inviteGroup($group_id)
7815  {
7816  include_once "./Modules/Group/classes/class.ilObjGroup.php";
7817  $group = new ilObjGroup($group_id);
7818  $members = $group->getGroupMemberIds();
7819  include_once './Services/User/classes/class.ilObjUser.php';
7820  foreach ($members as $user_id)
7821  {
7822  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7823  }
7824  }
7825 
7832  function inviteRole($role_id)
7833  {
7834  global $rbacreview;
7835  $members = $rbacreview->assignedUsers($role_id,"usr_id");
7836  include_once './Services/User/classes/class.ilObjUser.php';
7837  foreach ($members as $user_id)
7838  {
7839  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7840  }
7841  }
7842 
7843 
7844 
7851  function disinviteUser($user_id)
7852  {
7853  global $ilDB;
7854 
7855  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7856  array('integer', 'integer'),
7857  array($this->getTestId(), $user_id)
7858  );
7859  }
7860 
7867  function inviteUser($user_id, $client_ip="")
7868  {
7869  global $ilDB;
7870 
7871  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7872  array('integer', 'integer'),
7873  array($this->getTestId(), $user_id)
7874  );
7875  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
7876  array('integer', 'integer', 'text', 'integer'),
7877  array($this->getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : NULL, time())
7878  );
7879  }
7880 
7881 
7882  function setClientIP($user_id, $client_ip)
7883  {
7884  global $ilDB;
7885 
7886  $affectedRows = $ilDB->manipulateF("UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
7887  array('text', 'integer', 'integer', 'integer'),
7888  array((strlen($client_ip)) ? $client_ip : NULL, time(), $this->getTestId(), $user_id)
7889  );
7890  }
7891 
7897  function _getSolvedQuestions($active_id, $question_fi = null)
7898  {
7899  global $ilDB;
7900  if (is_numeric($question_fi))
7901  {
7902  $result = $ilDB->queryF("SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
7903  array('integer', 'integer'),
7904  array($active_id, $question_fi)
7905  );
7906  }
7907  else
7908  {
7909  $result = $ilDB->queryF("SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
7910  array('integer'),
7911  array($active_id)
7912  );
7913  }
7914  $result_array = array();
7915  while ($row = $ilDB->fetchAssoc($result))
7916  {
7917  $result_array[$row["question_fi"]]= $row;
7918  }
7919  return $result_array;
7920  }
7921 
7922 
7926  function setQuestionSetSolved($value, $question_id, $user_id)
7927  {
7928  global $ilDB;
7929 
7930  $active_id = $this->getActiveIdOfUser($user_id);
7931  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
7932  array('integer', 'integer'),
7933  array($active_id, $question_id)
7934  );
7935  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
7936  array('integer', 'integer', 'integer'),
7937  array($value, $question_id, $active_id)
7938  );
7939  }
7940 
7944  function isTestFinished($active_id)
7945  {
7946  global $ilDB;
7947 
7948  $result = $ilDB->queryF("SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
7949  array('integer', 'integer'),
7950  array($active_id, 1)
7951  );
7952  return $result->numRows() == 1;
7953  }
7954 
7958  function isActiveTestSubmitted($user_id = null)
7959  {
7960  global $ilUser;
7961  global $ilDB;
7962 
7963  if (!is_numeric($user_id))
7964  $user_id = $ilUser->getId();
7965 
7966  $result = $ilDB->queryF("SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
7967  array('integer', 'integer', 'integer'),
7968  array($this->getTestId(), $user_id, 1)
7969  );
7970  return $result->numRows() == 1;
7971  }
7972 
7977  {
7978  return $this->getNrOfTries() != 0;
7979  }
7980 
7981 
7987  function isNrOfTriesReached($tries)
7988  {
7989  return $tries >= (int) $this->getNrOfTries();
7990  }
7991 
7992 
8001  function getAllTestResults($participants, $prepareForCSV = true)
8002  {
8003  $results = array();
8004  $row = array(
8005  "user_id" => $this->lng->txt("user_id"),
8006  "matriculation" => $this->lng->txt("matriculation"),
8007  "lastname" => $this->lng->txt("lastname"),
8008  "firstname" => $this->lng->txt("firstname"),
8009  "login" =>$this->lng->txt("login"),
8010  "reached_points" => $this->lng->txt("tst_reached_points"),
8011  "max_points" => $this->lng->txt("tst_maximum_points"),
8012  "percent_value" => $this->lng->txt("tst_percent_solved"),
8013  "mark" => $this->lng->txt("tst_mark"),
8014  "ects" => $this->lng->txt("ects_grade")
8015  );
8016  $results[] = $row;
8017  if (count($participants))
8018  {
8019  if($this->getECTSOutput())
8020  {
8021  $passed_array =& $this->getTotalPointsPassedArray();
8022  }
8023  foreach ($participants as $active_id => $user_rec)
8024  {
8025  $row = array();
8026  $reached_points = 0;
8027  $max_points = 0;
8028  foreach ($this->questions as $value)
8029  {
8030  $question =& ilObjTest::_instanciateQuestion($value);
8031  if (is_object($question))
8032  {
8033  $max_points += $question->getMaximumPoints();
8034  $reached_points += $question->getReachedPoints($active_id);
8035  }
8036  }
8037  if ($max_points > 0)
8038  {
8039  $percentvalue = $reached_points / $max_points;
8040  if ($percentvalue < 0) $percentvalue = 0.0;
8041  }
8042  else
8043  {
8044  $percentvalue = 0;
8045  }
8046  $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
8047  $passed = "";
8048  if ($mark_obj)
8049  {
8050  $mark = $mark_obj->getOfficialName();
8051  $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
8052  }
8053  if ($this->getAnonymity())
8054  {
8055  $user_rec['firstname'] = "";
8056  $user_rec['lastname'] = $this->lng->txt("anonymous");
8057  }
8058  $row = array(
8059  "user_id"=>$user_rec['usr_id'],
8060  "matriculation" => $user_rec['matriculation'],
8061  "lastname" => $user_rec['lastname'],
8062  "firstname" => $user_rec['firstname'],
8063  "login"=>$user_rec['login'],
8064  "reached_points" => $reached_points,
8065  "max_points" => $max_points,
8066  "percent_value" => $percentvalue,
8067  "mark" => $mark,
8068  "ects" => $ects_mark
8069  );
8070  $results[] = $prepareForCSV ? $this->processCSVRow ($row, true) : $row;
8071  }
8072  }
8073  return $results;
8074  }
8075 
8086  function &processCSVRow($row, $quoteAll = FALSE, $separator = ";")
8087  {
8088  $resultarray = array();
8089  foreach ($row as $rowindex => $entry)
8090  {
8091  $surround = FALSE;
8092  if ($quoteAll)
8093  {
8094  $surround = TRUE;
8095  }
8096  if (strpos($entry, "\"") !== FALSE)
8097  {
8098  $entry = str_replace("\"", "\"\"", $entry);
8099  $surround = TRUE;
8100  }
8101  if (strpos($entry, $separator) !== FALSE)
8102  {
8103  $surround = TRUE;
8104  }
8105  // replace all CR LF with LF (for Excel for Windows compatibility
8106  $entry = str_replace(chr(13).chr(10), chr(10), $entry);
8107 
8108  if ($surround)
8109  {
8110  $entry = "\"" . $entry . "\"";
8111  }
8112 
8113  $resultarray[$rowindex] = $entry;
8114  }
8115  return $resultarray;
8116  }
8117 
8126  function _getPass($active_id)
8127  {
8128  global $ilDB;
8129  $result = $ilDB->queryF("SELECT tries FROM tst_active WHERE active_id = %s",
8130  array('integer'),
8131  array($active_id)
8132  );
8133  if ($result->numRows())
8134  {
8135  $row = $ilDB->fetchAssoc($result);
8136  return $row["tries"];
8137  }
8138  else
8139  {
8140  return 0;
8141  }
8142  }
8143 
8153  function _getMaxPass($active_id)
8154  {
8155  global $ilDB;
8156  $result = $ilDB->queryF("SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s",
8157  array('integer'),
8158  array($active_id)
8159  );
8160  if ($result->numRows())
8161  {
8162  $row = $ilDB->fetchAssoc($result);
8163  $max = $row["maxpass"];
8164  }
8165  else
8166  {
8167  $max = NULL;
8168  }
8169  return $max;
8170  }
8171 
8182  function _getBestPass($active_id)
8183  {
8184  global $ilDB;
8185 
8186  $result = $ilDB->queryF("SELECT * FROM tst_pass_result WHERE active_fi = %s",
8187  array('integer'),
8188  array($active_id)
8189  );
8190  if ($result->numRows())
8191  {
8192  $bestrow = null;
8193  $bestfactor = 0;
8194  while ($row = $ilDB->fetchAssoc($result))
8195  {
8196  if($row["maxpoints"] > 0)
8197  {
8198  $factor = $row["points"] / $row["maxpoints"];
8199  }
8200  else
8201  {
8202  $factor = 0;
8203  }
8204 
8205  if($factor > $bestfactor)
8206  {
8207  $bestrow = $row;
8208  $bestfactor = $factor;
8209  }
8210  }
8211  if (is_array($bestrow))
8212  {
8213  return $bestrow["pass"];
8214  }
8215  else
8216  {
8217  return 0;
8218  }
8219  }
8220  else
8221  {
8222  return 0;
8223  }
8224  }
8225 
8234  function _getResultPass($active_id)
8235  {
8236  $counted_pass = NULL;
8237  if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS)
8238  {
8239  $counted_pass = ilObjTest::_getBestPass($active_id);
8240  }
8241  else
8242  {
8243  $counted_pass = ilObjTest::_getMaxPass($active_id);
8244  }
8245  return $counted_pass;
8246  }
8247 
8257  function getAnsweredQuestionCount($active_id, $pass = NULL)
8258  {
8259  if( $this->isDynamicTest() )
8260  {
8261  global $tree, $ilDB, $lng, $ilPluginAdmin;
8262 
8263  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
8264  $testSessionFactory = new ilTestSessionFactory($this);
8265  $testSession = $testSessionFactory->getSession($active_id);
8266 
8267  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
8268  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
8269  $testSequence = $testSequenceFactory->getSequence($testSession);
8270 
8271  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
8272  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
8273  $dynamicQuestionSetConfig->loadFromDb();
8274 
8275  $testSequence->loadFromDb($dynamicQuestionSetConfig);
8276  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
8277 
8278  return $testSequence->getTrackedQuestionCount();
8279  }
8280 
8281  if ($this->isRandomTest())
8282  {
8283  $this->loadQuestions($active_id, $pass);
8284  }
8285  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
8286  $workedthrough = 0;
8287  foreach ($this->questions as $value)
8288  {
8289  if (assQuestion::_isWorkedThrough($active_id, $value, $pass))
8290  {
8291  $workedthrough += 1;
8292  }
8293  }
8294  return $workedthrough;
8295  }
8296 
8306  function getPassFinishDate($active_id, $pass)
8307  {
8308  global $ilDB;
8309 
8310  if (is_null($pass))
8311  {
8312  $pass = 0;
8313  }
8314 
8315  $query = "
8316  SELECT tst_pass_result.tstamp pass_res_tstamp,
8317  tst_test_result.tstamp quest_res_tstamp
8318 
8319  FROM tst_pass_result
8320 
8321  LEFT JOIN tst_test_result
8322  ON tst_test_result.active_fi = tst_pass_result.active_fi
8323  AND tst_test_result.pass = tst_pass_result.pass
8324 
8325  WHERE tst_pass_result.active_fi = %s
8326  AND tst_pass_result.pass = %s
8327 
8328  ORDER BY tst_test_result.tstamp DESC
8329  ";
8330 
8331  $result = $ilDB->queryF($query,
8332  array('integer', 'integer'),
8333  array($active_id, $pass)
8334  );
8335 
8336  while( $row = $ilDB->fetchAssoc($result) )
8337  {
8338  if( $row['qres_tstamp'] )
8339  {
8340  return $row['quest_res_tstamp'];
8341  }
8342 
8343  return $row['pass_res_tstamp'];
8344  }
8345 
8346  return 0;
8347  }
8348 
8357  function isExecutable($testSession, $user_id, $allowPassIncrease = FALSE)
8358  {
8359  $result = array(
8360  "executable" => true,
8361  "errormessage" => ""
8362  );
8363  if (!$this->startingTimeReached())
8364  {
8365  $result["executable"] = false;
8366  $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilFormat::ftimestamp2datetimeDB($this->getStartingTime()));
8367  return $result;
8368  }
8369  if ($this->endingTimeReached())
8370  {
8371  $result["executable"] = false;
8372  $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilFormat::ftimestamp2datetimeDB($this->getEndingTime()));
8373  return $result;
8374  }
8375 
8376  $active_id = $this->getActiveIdOfUser($user_id);
8377 
8378  if ($this->getEnableProcessingTime())
8379  {
8380  if ($active_id > 0)
8381  {
8382  $starting_time = $this->getStartingTimeOfUser($active_id);
8383  if ($starting_time !== FALSE)
8384  {
8385  if ($this->isMaxProcessingTimeReached($starting_time, $active_id))
8386  {
8387  if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > ($this->_getPass($active_id)+1))))
8388  {
8389  // a test pass was quitted because the maximum processing time was reached, but the time
8390  // will be resetted for future passes, so if there are more passes allowed, the participant may
8391  // start the test again.
8392  // This code block is only called when $allowPassIncrease is TRUE which only happens when
8393  // the test info page is opened. Otherwise this will lead to unexpected results!
8394  $testSession->increasePass();
8395  $testSession->setLastSequence(0);
8396  $testSession->saveToDb();
8397  }
8398  else
8399  {
8400  $result["executable"] = false;
8401  $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8402  }
8403  return $result;
8404  }
8405  }
8406  }
8407  }
8408 
8409  if ($this->hasNrOfTriesRestriction() && ($active_id > 0))
8410  {
8411  require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8412  $testPassesSelector = new ilTestPassesSelector($GLOBALS['ilDB'], $this);
8413  $testPassesSelector->setActiveId($active_id);
8414  $testPassesSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8415 
8416  $closedPasses = $testPassesSelector->getClosedPasses();
8417 
8418  if( count($closedPasses) >= $this->getNrOfTries() )
8419  {
8420  $result["executable"] = false;
8421  $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8422  return $result;
8423  }
8424  }
8425 
8426  return $result;
8427  }
8428 
8435  function canViewResults()
8436  {
8437  $result = true;
8438  if ($this->getScoreReporting() == 4) return false;
8439  if ($this->getReportingDate())
8440  {
8441  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
8442  {
8443  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8444  $now = mktime();
8445  if ($now < $epoch_time)
8446  {
8447  $result = false;
8448  }
8449  }
8450  }
8451  return $result;
8452  }
8453 
8454  function canShowTestResults($testSession, $user_id)
8455  {
8456  $active_id = $this->getActiveIdOfUser($user_id);
8457  if ($active_id > 0)
8458  {
8459  $starting_time = $this->getStartingTimeOfUser($active_id);
8460  }
8461  $notimeleft = FALSE;
8462  if ($starting_time !== FALSE)
8463  {
8464  if ($this->isMaxProcessingTimeReached($starting_time, $active_id))
8465  {
8466  $notimeleft = TRUE;
8467  }
8468  }
8469  $result = TRUE;
8470  if (!$this->isTestFinishedToViewResults($active_id, $testSession->getPass()) && ($this->getScoreReporting() == REPORT_AFTER_TEST))
8471  {
8472  $result = FALSE;
8473  }
8474  if (($this->endingTimeReached()) || $notimeleft) $result = TRUE;
8475  $result = $result & $this->canViewResults();
8476  return $result;
8477  }
8478 
8486  function getStartingTimeOfUser($active_id, $pass = null)
8487  {
8488  global $ilDB;
8489 
8490  if ($active_id < 1) return FALSE;
8491  if($pass === null)
8492  {
8493  $pass = ($this->getResetProcessingTime()) ? $this->_getPass($active_id) : 0;
8494  }
8495  $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",
8496  array('integer', 'integer'),
8497  array($active_id, $pass)
8498  );
8499  if ($result->numRows())
8500  {
8501  $row = $ilDB->fetchAssoc($result);
8502  if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches))
8503  {
8504  return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8505  }
8506  else
8507  {
8508  return mktime();
8509  }
8510  }
8511  else
8512  {
8513  return mktime();
8514  }
8515  }
8516 
8526  {
8527  if ($this->getEnableProcessingTime())
8528  {
8529  $processing_time = $this->getProcessingTimeInSeconds($active_id);
8530  $now = mktime();
8531  if ($now > ($starting_time + $processing_time))
8532  {
8533  return TRUE;
8534  }
8535  else
8536  {
8537  return FALSE;
8538  }
8539  }
8540  else
8541  {
8542  return FALSE;
8543  }
8544  }
8545 
8546  function &getTestQuestions()
8547  {
8548  global $ilDB;
8549 
8550  $query = "
8551  SELECT questions.*,
8552  questtypes.type_tag,
8553  tstquest.sequence,
8554  tstquest.obligatory,
8555  origquest.obj_fi orig_obj_fi
8556 
8557  FROM qpl_questions questions
8558 
8559  INNER JOIN qpl_qst_type questtypes
8560  ON questtypes.question_type_id = questions.question_type_fi
8561 
8562  INNER JOIN tst_test_question tstquest
8563  ON tstquest.question_fi = questions.question_id
8564 
8565  LEFT JOIN qpl_questions origquest
8566  ON origquest.question_id = questions.original_id
8567 
8568  WHERE tstquest.test_fi = %s
8569 
8570  ORDER BY tstquest.sequence
8571  ";
8572 
8573  $query_result = $ilDB->queryF(
8574  $query, array('integer'), array($this->getTestId())
8575  );
8576 
8577  $questions = array();
8578 
8579  while ($row = $ilDB->fetchAssoc($query_result))
8580  {
8581  $question = $row;
8582 
8583  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8584 
8585  $questions[] = $question;
8586  }
8587 
8588  return $questions;
8589  }
8590 
8594  public function getPotentialRandomTestQuestions()
8595  {
8599  global $ilDB;
8600 
8601  $query = "
8602  SELECT questions.*,
8603  questtypes.type_tag,
8604  origquest.obj_fi orig_obj_fi
8605 
8606  FROM qpl_questions questions
8607 
8608  INNER JOIN qpl_qst_type questtypes
8609  ON questtypes.question_type_id = questions.question_type_fi
8610 
8611  INNER JOIN tst_rnd_cpy tstquest
8612  ON tstquest.qst_fi = questions.question_id
8613 
8614  LEFT JOIN qpl_questions origquest
8615  ON origquest.question_id = questions.original_id
8616 
8617  WHERE tstquest.tst_fi = %s
8618  ";
8619 
8620  $query_result = $ilDB->queryF(
8621  $query, array('integer'), array($this->getTestId())
8622  );
8623 
8624  $questions = array();
8625 
8626  while ($row = $ilDB->fetchAssoc($query_result))
8627  {
8628  $question = $row;
8629 
8630  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8631 
8632  $questions[] = $question;
8633  }
8634 
8635  return $questions;
8636  }
8637 
8645  {
8646  return ($this->shuffle_questions) ? 1 : 0;
8647  }
8648 
8655  function setShuffleQuestions($a_shuffle)
8656  {
8657  $this->shuffle_questions = ($a_shuffle) ? 1 : 0;
8658  }
8659 
8673  {
8674  return ($this->show_summary) ? $this->show_summary : 0;
8675  }
8676 
8689  function setListOfQuestionsSettings($a_value = 0)
8690  {
8691  $this->show_summary = $a_value;
8692  }
8693 
8701  {
8702  if (($this->show_summary & 1) > 0)
8703  {
8704  return TRUE;
8705  }
8706  else
8707  {
8708  return FALSE;
8709  }
8710  }
8711 
8718  function setListOfQuestions($a_value = TRUE)
8719  {
8720  if ($a_value)
8721  {
8722  $this->show_summary = 1;
8723  }
8724  else
8725  {
8726  $this->show_summary = 0;
8727  }
8728  }
8729 
8737  {
8738  if (($this->show_summary & 2) > 0)
8739  {
8740  return TRUE;
8741  }
8742  else
8743  {
8744  return FALSE;
8745  }
8746  }
8747 
8754  function setListOfQuestionsStart($a_value = TRUE)
8755  {
8756  if ($a_value && $this->getListOfQuestions())
8757  {
8758  $this->show_summary = $this->show_summary | 2;
8759  }
8760  if (!$a_value && $this->getListOfQuestions())
8761  {
8762  if ($this->getListOfQuestionsStart())
8763  {
8764  $this->show_summary = $this->show_summary ^ 2;
8765  }
8766  }
8767  }
8768 
8776  {
8777  if (($this->show_summary & 4) > 0)
8778  {
8779  return TRUE;
8780  }
8781  else
8782  {
8783  return FALSE;
8784  }
8785  }
8786 
8793  function setListOfQuestionsEnd($a_value = TRUE)
8794  {
8795  if ($a_value && $this->getListOfQuestions())
8796  {
8797  $this->show_summary = $this->show_summary | 4;
8798  }
8799  if (!$a_value && $this->getListOfQuestions())
8800  {
8801  if ($this->getListOfQuestionsEnd())
8802  {
8803  $this->show_summary = $this->show_summary ^ 4;
8804  }
8805  }
8806  }
8807 
8815  {
8816  if (($this->show_summary & 8) > 0)
8817  {
8818  return TRUE;
8819  }
8820  else
8821  {
8822  return FALSE;
8823  }
8824  }
8825 
8832  function setListOfQuestionsDescription($a_value = TRUE)
8833  {
8834  if ($a_value && $this->getListOfQuestions())
8835  {
8836  $this->show_summary = $this->show_summary | 8;
8837  }
8838  if (!$a_value && $this->getListOfQuestions())
8839  {
8840  if ($this->getListOfQuestionsDescription())
8841  {
8842  $this->show_summary = $this->show_summary ^ 8;
8843  }
8844  }
8845  }
8846 
8854  {
8855  return ($this->results_presentation) ? $this->results_presentation : 0;
8856  }
8857 
8865  {
8866  if (($this->results_presentation & 1) > 0)
8867  {
8868  return TRUE;
8869  }
8870  else
8871  {
8872  return FALSE;
8873  }
8874  }
8875 
8883  {
8884  if (($this->results_presentation & 2) > 0)
8885  {
8886  return TRUE;
8887  }
8888  else
8889  {
8890  return FALSE;
8891  }
8892  }
8893 
8901  {
8902  if (($this->results_presentation & 4) > 0)
8903  {
8904  return TRUE;
8905  }
8906  else
8907  {
8908  return FALSE;
8909  }
8910  }
8911 
8919  {
8920  if (($this->results_presentation & 8) > 0)
8921  {
8922  return TRUE;
8923  }
8924  else
8925  {
8926  return FALSE;
8927  }
8928  }
8929 
8937  {
8938  if (($this->results_presentation & 16) > 0)
8939  {
8940  return TRUE;
8941  }
8942  else
8943  {
8944  return FALSE;
8945  }
8946  }
8947 
8955  {
8956  if (($this->results_presentation & 32) > 0)
8957  {
8958  return TRUE;
8959  }
8960  else
8961  {
8962  return FALSE;
8963  }
8964  }
8965 
8971  {
8972  if (($this->results_presentation & 64) > 0)
8973  {
8974  return TRUE;
8975  }
8976  else
8977  {
8978  return FALSE;
8979  }
8980  }
8981 
8987  {
8988  if(($this->results_presentation & 128) > 0)
8989  {
8990  return TRUE;
8991  }
8992  else
8993  {
8994  return FALSE;
8995  }
8996  }
8997 
9004  function setResultsPresentation($a_results_presentation = 3)
9005  {
9006  $this->results_presentation = $a_results_presentation;
9007  }
9008 
9017  function setShowPassDetails($a_details = 1)
9018  {
9019  if ($a_details)
9020  {
9021  $this->results_presentation = $this->results_presentation | 1;
9022  }
9023  else
9024  {
9025  if ($this->getShowPassDetails())
9026  {
9027  $this->results_presentation = $this->results_presentation ^ 1;
9028  }
9029  }
9030  }
9031 
9038  function setShowSolutionDetails($a_details = 1)
9039  {
9040  if ($a_details)
9041  {
9042  $this->results_presentation = $this->results_presentation | 2;
9043  }
9044  else
9045  {
9046  if ($this->getShowSolutionDetails())
9047  {
9048  $this->results_presentation = $this->results_presentation ^ 2;
9049  }
9050  }
9051  }
9052 
9059  function canShowSolutionPrintview($user_id = NULL)
9060  {
9061  return $this->getShowSolutionPrintview();
9062  }
9063 
9070  function setShowSolutionPrintview($a_printview = 1)
9071  {
9072  if ($a_printview)
9073  {
9074  $this->results_presentation = $this->results_presentation | 4;
9075  }
9076  else
9077  {
9078  if ($this->getShowSolutionPrintview())
9079  {
9080  $this->results_presentation = $this->results_presentation ^ 4;
9081  }
9082  }
9083  }
9084 
9091  function setShowSolutionFeedback($a_feedback = TRUE)
9092  {
9093  if ($a_feedback)
9094  {
9095  $this->results_presentation = $this->results_presentation | 8;
9096  }
9097  else
9098  {
9099  if ($this->getShowSolutionFeedback())
9100  {
9101  $this->results_presentation = $this->results_presentation ^ 8;
9102  }
9103  }
9104  }
9105 
9112  function setShowSolutionAnswersOnly($a_full = TRUE)
9113  {
9114  if ($a_full)
9115  {
9116  $this->results_presentation = $this->results_presentation | 16;
9117  }
9118  else
9119  {
9120  if ($this->getShowSolutionAnswersOnly())
9121  {
9122  $this->results_presentation = $this->results_presentation ^ 16;
9123  }
9124  }
9125  }
9126 
9133  function setShowSolutionSignature($a_signature = FALSE)
9134  {
9135  if ($a_signature)
9136  {
9137  $this->results_presentation = $this->results_presentation | 32;
9138  }
9139  else
9140  {
9141  if ($this->getShowSolutionSignature())
9142  {
9143  $this->results_presentation = $this->results_presentation ^ 32;
9144  }
9145  }
9146  }
9147 
9154  function setShowSolutionSuggested($a_solution = FALSE)
9155  {
9156  if ($a_solution)
9157  {
9158  $this->results_presentation = $this->results_presentation | 64;
9159  }
9160  else
9161  {
9162  if ($this->getShowSolutionSuggested())
9163  {
9164  $this->results_presentation = $this->results_presentation ^ 64;
9165  }
9166  }
9167  }
9168 
9174  public function setShowSolutionListComparison($a_comparison = FALSE)
9175  {
9176  if($a_comparison)
9177  {
9178  $this->results_presentation = $this->results_presentation | 128;
9179  }
9180  else
9181  {
9182  if($this->getShowSolutionListComparison())
9183  {
9184  $this->results_presentation = $this->results_presentation ^ 128;
9185  }
9186  }
9187  }
9188 
9192  public static function _getUserIdFromActiveId($active_id)
9193  {
9194  global $ilDB;
9195  $result = $ilDB->queryF("SELECT user_fi FROM tst_active WHERE active_id = %s",
9196  array('integer'),
9197  array($active_id)
9198  );
9199  if ($result->numRows())
9200  {
9201  $row = $ilDB->fetchAssoc($result);
9202  return $row["user_fi"];
9203  }
9204  else
9205  {
9206  return -1;
9207  }
9208  }
9209 
9213  public function isLimitUsersEnabled()
9214  {
9215  return $this->limitUsersEnabled;
9216  }
9217 
9222  {
9223  $this->limitUsersEnabled = $limitUsersEnabled;
9224  }
9225 
9226  public function getAllowedUsers()
9227  {
9228  return ($this->allowedUsers) ? $this->allowedUsers : 0;
9229  }
9230 
9231  public function setAllowedUsers($a_allowed_users)
9232  {
9233  $this->allowedUsers = $a_allowed_users;
9234  }
9235 
9236  public function getAllowedUsersTimeGap()
9237  {
9238  return ($this->allowedUsersTimeGap) ? $this->allowedUsersTimeGap : 0;
9239  }
9240 
9241  public function setAllowedUsersTimeGap($a_allowed_users_time_gap)
9242  {
9243  $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
9244  }
9245 
9247  {
9248  global $ilDB;
9249 
9250  $nr_of_users = $this->getAllowedUsers();
9251  $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
9252  if (($nr_of_users > 0) && ($time_gap > 0))
9253  {
9254  $now = mktime();
9255  $time_border = $now - $time_gap;
9256  $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
9257  $query = "
9258  SELECT DISTINCT tst_times.active_fi
9259  FROM tst_times
9260  INNER JOIN tst_active
9261  ON tst_times.active_fi = tst_active.active_id
9262  AND (
9263  tst_times.pass > tst_active.last_finished_pass OR tst_active.last_finished_pass IS NULL
9264  )
9265  WHERE tst_times.tstamp > %s
9266  AND tst_active.test_fi = %s
9267  ";
9268  $result = $ilDB->queryF($query, array('integer', 'integer'), array($time_border, $this->getTestId()));
9269  if ($result->numRows() >= $nr_of_users)
9270  {
9271  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
9273  {
9274  $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
9275  }
9276  return FALSE;
9277  }
9278  else
9279  {
9280  return TRUE;
9281  }
9282  }
9283  return TRUE;
9284  }
9285 
9286  function _getLastAccess($active_id)
9287  {
9288  global $ilDB;
9289 
9290  $result = $ilDB->queryF("SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
9291  array('integer'),
9292  array($active_id)
9293  );
9294  if ($result->numRows())
9295  {
9296  $row = $ilDB->fetchAssoc($result);
9297  return $row["finished"];
9298  }
9299  return "";
9300  }
9301 
9309  function isHTML($a_text)
9310  {
9311  if (preg_match("/<[^>]*?>/", $a_text))
9312  {
9313  return TRUE;
9314  }
9315  else
9316  {
9317  return FALSE;
9318  }
9319  }
9320 
9328  function QTIMaterialToString($a_material)
9329  {
9330  $result = "";
9331  for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
9332  {
9333  $material = $a_material->getMaterial($i);
9334  if (strcmp($material["type"], "mattext") == 0)
9335  {
9336  $result .= $material["material"]->getContent();
9337  }
9338  if (strcmp($material["type"], "matimage") == 0)
9339  {
9340  $matimage = $material["material"];
9341  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
9342  {
9343  // import an mediaobject which was inserted using tiny mce
9344  if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
9345  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
9346  }
9347  }
9348  }
9349  global $ilLog;
9350  $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
9351  return $result;
9352  }
9353 
9362  function addQTIMaterial(&$a_xml_writer, $a_material)
9363  {
9364  include_once "./Services/RTE/classes/class.ilRTE.php";
9365  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9366 
9367  $a_xml_writer->xmlStartTag("material");
9368  $attrs = array(
9369  "texttype" => "text/plain"
9370  );
9371  if ($this->isHTML($a_material))
9372  {
9373  $attrs["texttype"] = "text/xhtml";
9374  }
9375  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
9376 
9377  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9378  foreach ($mobs as $mob)
9379  {
9380  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9381  if (strpos($a_material, "mm_$mob") !== FALSE)
9382  {
9383  if (ilObjMediaObject::_exists($mob))
9384  {
9385  $mob_obj =& new ilObjMediaObject($mob);
9386  $imgattrs = array(
9387  "label" => $moblabel,
9388  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9389  );
9390  }
9391  $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
9392  }
9393  }
9394  $a_xml_writer->xmlEndTag("material");
9395  }
9396 
9403  function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE, $omitNl2BrWhenTextArea = false)
9404  {
9405  include_once "./Services/Utilities/classes/class.ilUtil.php";
9406  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output, $omitNl2BrWhenTextArea);
9407  }
9408 
9415  function saveCertificateVisibility($a_value)
9416  {
9417  global $ilDB;
9418 
9419  $affectedRows = $ilDB->manipulateF("UPDATE tst_tests SET certificate_visibility = %s, tstamp = %s WHERE test_id = %s",
9420  array('text', 'integer', 'integer'),
9421  array($a_value, time(), $this->getTestId())
9422  );
9423  }
9424 
9432  {
9433  return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0;
9434  }
9435 
9442  function setCertificateVisibility($a_value)
9443  {
9444  $this->certificate_visibility = $a_value;
9445  }
9446 
9453  function getAnonymity()
9454  {
9455  return ($this->anonymity) ? 1 : 0;
9456  }
9457 
9464  function setAnonymity($a_value = 0)
9465  {
9466  switch ($a_value)
9467  {
9468  case 1:
9469  $this->anonymity = 1;
9470  break;
9471  default:
9472  $this->anonymity = 0;
9473  break;
9474  }
9475  }
9476 
9483  function getShowCancel()
9484  {
9485  return ($this->show_cancel) ? 1 : 0;
9486  }
9487 
9494  function setShowCancel($a_value = 1)
9495  {
9496  switch ($a_value)
9497  {
9498  case 1:
9499  $this->show_cancel = 1;
9500  break;
9501  default:
9502  $this->show_cancel = 0;
9503  break;
9504  }
9505  }
9506 
9513  function getShowMarker()
9514  {
9515  return ($this->show_marker) ? 1 : 0;
9516  }
9517 
9524  function setShowMarker($a_value = 1)
9525  {
9526  switch ($a_value)
9527  {
9528  case 1:
9529  $this->show_marker = 1;
9530  break;
9531  default:
9532  $this->show_marker = 0;
9533  break;
9534  }
9535  }
9536 
9544  {
9545  return ($this->fixed_participants) ? 1 : 0;
9546  }
9547 
9554  function setFixedParticipants($a_value = 1)
9555  {
9556  switch ($a_value)
9557  {
9558  case 1:
9559  $this->fixed_participants = 1;
9560  break;
9561  default:
9562  $this->fixed_participants = 0;
9563  break;
9564  }
9565  }
9566 
9574  function _lookupAnonymity($a_obj_id)
9575  {
9576  global $ilDB;
9577 
9578  $result = $ilDB->queryF("SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
9579  array('integer'),
9580  array($a_obj_id)
9581  );
9582  while($row = $ilDB->fetchAssoc($result))
9583  {
9584  return $row['anonymity'];
9585  }
9586  return 0;
9587  }
9588 
9595  public static function lookupQuestionSetTypeByActiveId($active_id)
9596  {
9597  global $ilDB;
9598 
9599  $query = "
9600  SELECT tst_tests.question_set_type
9601  FROM tst_active
9602  INNER JOIN tst_tests
9603  ON tst_active.test_fi = tst_tests.test_id
9604  WHERE tst_active.active_id = %s
9605  ";
9606 
9607  $res = $ilDB->queryF( $query, array('integer'), array($active_id) );
9608 
9609  while($row = $ilDB->fetchAssoc($res))
9610  {
9611  return $row['question_set_type'];
9612  }
9613 
9614  return null;
9615  }
9616 
9625  function _lookupRandomTestFromActiveId($active_id)
9626  {
9627  throw new Exception(__METHOD__.' is deprecated ... use ilObjTest::lookupQuestionSetTypeByActiveId() instead!');
9628 
9629  global $ilDB;
9630 
9631  $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",
9632  array('integer'),
9633  array($active_id)
9634  );
9635  while($row = $ilDB->fetchAssoc($result))
9636  {
9637  return $row['random_test'];
9638  }
9639  return 0;
9640  }
9641 
9652  function userLookupFullName($user_id, $overwrite_anonymity = FALSE, $sorted_order = FALSE, $suffix = "")
9653  {
9654  if ($this->getAnonymity() && !$overwrite_anonymity)
9655  {
9656  return $this->lng->txt("anonymous") . $suffix;
9657  }
9658  else
9659  {
9660  include_once './Services/User/classes/class.ilObjUser.php';
9661  $uname = ilObjUser::_lookupName($user_id);
9662  if (strlen($uname["firstname"].$uname["lastname"]) == 0) $uname["firstname"] = $this->lng->txt("deleted_user");
9663  if ($sorted_order)
9664  {
9665  return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9666  }
9667  else
9668  {
9669  return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9670  }
9671  }
9672  }
9673 
9681  function getStartTestLabel($active_id)
9682  {
9683  if ($this->getNrOfTries() == 1)
9684  {
9685  return $this->lng->txt("tst_start_test");
9686  }
9687  $active_pass = $this->_getPass($active_id);
9688  $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9689  if ($res == 0)
9690  {
9691  if ($active_pass == 0)
9692  {
9693  return $this->lng->txt("tst_start_test");
9694  }
9695  else
9696  {
9697  return $this->lng->txt("tst_start_new_test_pass");
9698  }
9699  }
9700  else
9701  {
9702  return $this->lng->txt("tst_resume_test");
9703  }
9704  }
9705 
9711  public function getAvailableDefaults()
9712  {
9717  global $ilDB, $ilUser;
9718 
9719  $result = $ilDB->queryF(
9720  "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
9721  array('integer'),
9722  array($ilUser->getId())
9723  );
9724  $defaults = array();
9725  while($row = $ilDB->fetchAssoc($result))
9726  {
9727  $defaults[$row["test_defaults_id"]] = $row;
9728  }
9729  return $defaults;
9730  }
9731 
9739  function &getTestDefaults($test_defaults_id)
9740  {
9741  return self::_getTestDefaults($test_defaults_id);
9742  }
9743 
9744  public static function _getTestDefaults($test_defaults_id)
9745  {
9746  global $ilDB;
9747 
9748  $result = $ilDB->queryF("SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9749  array('integer'),
9750  array($test_defaults_id)
9751  );
9752  if ($result->numRows() == 1)
9753  {
9754  $row = $ilDB->fetchAssoc($result);
9755  return $row;
9756  }
9757  else
9758  {
9759  return NULL;
9760  }
9761  }
9762 
9769  function deleteDefaults($test_default_id)
9770  {
9771  global $ilDB;
9772  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9773  array('integer'),
9774  array($test_default_id)
9775  );
9776  }
9777 
9784  function addDefaults($a_name)
9785  {
9786  global $ilDB;
9787  global $ilUser;
9788  $testsettings = array(
9789  "TitleOutput" => $this->getTitleOutput(),
9790  "PassScoring" => $this->getPassScoring(),
9791  "IntroEnabled" => $this->isIntroductionEnabled(),
9792  "Introduction" => $this->getIntroduction(),
9793  "FinalStatement" => $this->getFinalStatement(),
9794  "ShowInfo" => $this->getShowInfo(),
9795  "ForceJS" => $this->getForceJS(),
9796  "CustomStyle" => $this->getCustomStyle(),
9797  "ShowFinalStatement" => $this->getShowFinalStatement(),
9798  "SequenceSettings" => $this->getSequenceSettings(),
9799  "ScoreReporting" => $this->getScoreReporting(),
9800  "ScoreCutting" => $this->getScoreCutting(),
9801  'SpecificAnswerFeedback' => $this->getSpecificAnswerFeedback(),
9802  'PrintBsWithRes' => (int)$this->isBestSolutionPrintedWithResult(),
9803  "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9804  "AnswerFeedback" => $this->getAnswerFeedback(),
9805  "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9806  "ResultsPresentation" => $this->getResultsPresentation(),
9807  "Anonymity" => $this->getAnonymity(),
9808  "ShowCancel" => $this->getShowCancel(),
9809  "ShowMarker" => $this->getShowMarker(),
9810  "ReportingDate" => $this->getReportingDate(),
9811  "NrOfTries" => $this->getNrOfTries(),
9812  "Shuffle" => $this->getShuffleQuestions(),
9813  "Kiosk" => $this->getKiosk(),
9814  "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9815  "ProcessingTime" => $this->getProcessingTime(),
9816  "EnableProcessingTime" => $this->getEnableProcessingTime(),
9817  "ResetProcessingTime" => $this->getResetProcessingTime(),
9818  "StartingTimeEnabled" => $this->isStartingTimeEnabled(),
9819  "StartingTime" => $this->getStartingTime(),
9820  "EndingTimeEnabled" => $this->isEndingTimeEnabled(),
9821  "EndingTime" => $this->getEndingTime(),
9822  "ECTSOutput" => $this->getECTSOutput(),
9823  "ECTSFX" => $this->getECTSFX(),
9824  "ECTSGrades" => $this->getECTSGrades(),
9825  "questionSetType" => $this->getQuestionSetType(),
9826  "CountSystem" => $this->getCountSystem(),
9827  "MCScoring" => $this->getMCScoring(),
9828  "mailnotification" => $this->getMailNotification(),
9829  "mailnottype" => $this->getMailNotificationType(),
9830  "exportsettings" => $this->getExportSettings(),
9831  "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings(),
9832  'obligations_enabled' => (int)$this->areObligationsEnabled(),
9833  'offer_question_hints' => (int)$this->isOfferingQuestionHintsEnabled(),
9834  'pass_deletion_allowed' => (int)$this->isPassDeletionAllowed(),
9835  'enable_examview' => $this->getEnableExamview(),
9836  'show_examview_html' => $this->getShowExamviewHtml(),
9837  'show_examview_pdf' => $this->getShowExamviewPdf(),
9838  'char_selector_availability' => $this->getCharSelectorAvailability(),
9839  'char_selector_definition' => $this->getCharSelectorDefinition(),
9840  'skill_service' => (int)$this->isSkillServiceEnabled(),
9841  'result_tax_filters' => (array)$this->getResultFilterTaxIds(),
9842  'show_grading_status' => (int)$this->isShowGradingStatusEnabled(),
9843  'show_grading_mark' => (int)$this->isShowGradingMarkEnabled(),
9844 
9845  'inst_fb_answer_fixation' => $this->isInstantFeedbackAnswerFixationEnabled(),
9846  'redirection_mode' => $this->getRedirectionMode(),
9847  'redirection_url' => $this->getRedirectionUrl(),
9848  'sign_submission' => $this->getSignSubmission(),
9849  'autosave' => (int)$this->getAutosave(),
9850  'autosave_ival' => (int)$this->getAutosaveIval(),
9851  'examid_in_test_pass' => (int)$this->isShowExamIdInTestPassEnabled(),
9852  'examid_in_test_res' => (int)$this->isShowExamIdInTestResultsEnabled(),
9853 
9854  'enable_archiving' => (int)$this->getEnableArchiving(),
9855  'password_enabled' => (int)$this->isPasswordEnabled(),
9856  'password' => (string)$this->getPassword(),
9857  'fixed_participants' => $this->getFixedParticipants(),
9858  'limit_users_enabled' => $this->isLimitUsersEnabled(),
9859  'allowedusers' => $this->getAllowedUsers(),
9860  'alloweduserstimegap' => $this->getAllowedUsersTimeGap(),
9861  'pool_usage' => $this->getPoolUsage(),
9862  'activation_limited' => $this->isActivationLimited(),
9863  'activation_start_time' => $this->getActivationStartingTime(),
9864  'activation_end_time' => $this->getActivationEndingTime(),
9865  'activation_visibility' => $this->getActivationVisibility(),
9866  'highscore_enabled' => $this->getHighscoreEnabled(),
9867  'highscore_anon' => $this->getHighscoreAnon(),
9868  'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
9869  'highscore_score' => $this->getHighscoreScore(),
9870  'highscore_percentage' => $this->getHighscorePercentage(),
9871  'highscore_hints' => $this->getHighscoreHints(),
9872  'highscore_wtime' => $this->getHighscoreWTime(),
9873  'highscore_own_table' => $this->getHighscoreOwnTable(),
9874  'highscore_top_table' => $this->getHighscoreTopTable(),
9875  'highscore_top_num' => $this->getHighscoreTopNum(),
9876  'use_previous_answers' => (string)$this->getUsePreviousAnswers()
9877  );
9878 
9879  $next_id = $ilDB->nextId('tst_test_defaults');
9880  $ilDB->insert(
9881  'tst_test_defaults',
9882  array(
9883  'test_defaults_id' => array('integer', $next_id),
9884  'name' => array('text', $a_name),
9885  'user_fi' => array('integer', $ilUser->getId()),
9886  'defaults' => array('clob', serialize($testsettings)),
9887  'marks' => array('clob', serialize($this->mark_schema)),
9888  'tstamp' => array('integer', time())
9889  )
9890  );
9891  }
9892 
9900  public function applyDefaults($test_defaults)
9901  {
9902  $testsettings = unserialize($test_defaults["defaults"]);
9903  include_once "./Modules/Test/classes/class.assMarkSchema.php";
9904  $this->mark_schema = unserialize($test_defaults["marks"]);
9905 
9906  $this->setTitleOutput($testsettings["TitleOutput"]);
9907  $this->setPassScoring($testsettings["PassScoring"]);
9908  $this->setIntroductionEnabled($testsettings["IntroEnabled"]);
9909  $this->setIntroduction($testsettings["Introduction"]);
9910  $this->setFinalStatement($testsettings["FinalStatement"]);
9911  $this->setShowInfo($testsettings["ShowInfo"]);
9912  $this->setForceJS($testsettings["ForceJS"]);
9913  $this->setCustomStyle($testsettings["CustomStyle"]);
9914  $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
9915  $this->setSequenceSettings($testsettings["SequenceSettings"]);
9916  $this->setScoreReporting($testsettings["ScoreReporting"]);
9917  $this->setScoreCutting($testsettings['ScoreCutting']);
9918  $this->setSpecificAnswerFeedback($testsettings['SpecificAnswerFeedback']);
9919  $this->setPrintBestSolutionWithResult((bool)$testsettings['PrintBsWithRes']);
9920  $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
9921  $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
9922  $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
9923  $this->setResultsPresentation($testsettings["ResultsPresentation"]);
9924  $this->setAnonymity($testsettings["Anonymity"]);
9925  $this->setShowCancel($testsettings["ShowCancel"]);
9926  $this->setShuffleQuestions($testsettings["Shuffle"]);
9927  $this->setShowMarker($testsettings["ShowMarker"]);
9928  $this->setReportingDate($testsettings["ReportingDate"]);
9929  $this->setNrOfTries($testsettings["NrOfTries"]);
9930  $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
9931  $this->setRedirectionMode($testsettings['redirection_mode']);
9932  $this->setRedirectionUrl($testsettings['redirection_url']);
9933  $this->setProcessingTime($testsettings["ProcessingTime"]);
9934  $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
9935  $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
9936  $this->setStartingTimeEnabled($testsettings["StartingTimeEnabled"]);
9937  $this->setStartingTime($testsettings["StartingTime"]);
9938  $this->setKiosk($testsettings["Kiosk"]);
9939  $this->setEndingTimeEnabled($testsettings["EndingTimeEnabled"]);
9940  $this->setEndingTime($testsettings["EndingTime"]);
9941  $this->setECTSOutput($testsettings["ECTSOutput"]);
9942  $this->setECTSFX($testsettings["ECTSFX"]);
9943  $this->setECTSGrades($testsettings["ECTSGrades"]);
9944  if( isset($testsettings["isRandomTest"]) )
9945  {
9946  if( $testsettings["isRandomTest"] )
9947  {
9948  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
9949  }
9950  else
9951  {
9952  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
9953  }
9954  }
9955  elseif( isset($testsettings["questionSetType"]) )
9956  {
9957  $this->setQuestionSetType($testsettings["questionSetType"]);
9958  }
9959  $this->setCountSystem($testsettings["CountSystem"]);
9960  $this->setMCScoring($testsettings["MCScoring"]);
9961  $this->setMailNotification($testsettings["mailnotification"]);
9962  $this->setMailNotificationType($testsettings["mailnottype"]);
9963  $this->setExportSettings($testsettings['exportsettings']);
9964  $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
9965  $this->setObligationsEnabled($testsettings["obligations_enabled"]);
9966  $this->setOfferingQuestionHintsEnabled($testsettings["offer_question_hints"]);
9967  $this->setHighscoreEnabled($testsettings['highscore_enabled']);
9968  $this->setHighscoreAnon($testsettings['highscore_anon']);
9969  $this->setHighscoreAchievedTS($testsettings['highscore_achieved_ts']);
9970  $this->setHighscoreScore($testsettings['highscore_score']);
9971  $this->setHighscorePercentage($testsettings['highscore_percentage']);
9972  $this->setHighscoreHints($testsettings['highscore_hints']);
9973  $this->setHighscoreWTime($testsettings['highscore_wtime']);
9974  $this->setHighscoreOwnTable($testsettings['highscore_own_table']);
9975  $this->setHighscoreTopTable($testsettings['highscore_top_table']);
9976  $this->setHighscoreTopNum($testsettings['highscore_top_num']);
9977  $this->setPassDeletionAllowed($testsettings['pass_deletion_allowed']);
9978  if( isset($testsettings['examid_in_kiosk']) )
9979  {
9980  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_kiosk']);
9981  }
9982  else
9983  {
9984  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_test_pass']);
9985  }
9986  if( isset($testsettings['show_exam_id']) )
9987  {
9988  $this->setShowExamIdInTestResultsEnabled($testsettings['show_exam_id']);
9989  }
9990  else
9991  {
9992  $this->setShowExamIdInTestResultsEnabled($testsettings['examid_in_test_res']);
9993  }
9994  $this->setEnableExamview($testsettings['enable_examview']);
9995  $this->setShowExamviewHtml($testsettings['show_examview_html']);
9996  $this->setShowExamviewPdf($testsettings['show_examview_pdf']);
9997  $this->setEnableArchiving($testsettings['enable_archiving']);
9998  $this->setSignSubmission($testsettings['sign_submission']);
9999  $this->setCharSelectorAvailability($testsettings['char_selector_availability']);
10000  $this->setCharSelectorDefinition($testsettings['char_selector_definition']);
10001  $this->setSkillServiceEnabled((bool)$testsettings['skill_service']);
10002  $this->setResultFilterTaxIds((array)$testsettings['result_tax_filters']);
10003  $this->setShowGradingStatusEnabled((bool)$testsettings['show_grading_status']);
10004  $this->setShowGradingMarkEnabled((bool)$testsettings['show_grading_mark']);
10005 
10006  $this->setInstantFeedbackAnswerFixationEnabled($testsettings['inst_fb_answer_fixation']);
10007  $this->setRedirectionMode($testsettings['redirection_mode']);
10008  $this->setRedirectionUrl($testsettings['redirection_url']);
10009 
10010  $this->setAutosave($testsettings['autosave']);
10011  $this->setAutosaveIval($testsettings['autosave_ival']);
10012  $this->setShowExamIdInTestResultsEnabled((int)$testsettings['examid_in_test_res']);
10013  $this->setPasswordEnabled($testsettings['password_enabled']);
10014  $this->setPassword($testsettings['password']);
10015  $this->setFixedParticipants($testsettings['fixed_participants'] );
10016  $this->setLimitUsersEnabled($testsettings['limit_users_enabled']);
10017  $this->setAllowedUsers($testsettings['allowedusers']);
10018  $this->setAllowedUsersTimeGap($testsettings['alloweduserstimegap']);
10019  $this->setUsePreviousAnswers($testsettings['use_previous_answers']);
10020  $this->setPoolUsage($testsettings['pool_usage']);
10021  $this->setActivationLimited($testsettings['activation_limited']);
10022  $this->setActivationStartingTime($testsettings['activation_start_time']);
10023  $this->setActivationEndingTime($testsettings['activation_end_time']);
10024  $this->setActivationVisibility($testsettings['activation_visibility']);
10025 
10026  $this->saveToDb();
10027 
10028  return true;
10029  }
10030 
10038  function processPrintoutput2FO($print_output)
10039  {
10040  if (extension_loaded("tidy"))
10041  {
10042  $config = array(
10043  "indent" => false,
10044  "output-xml" => true,
10045  "numeric-entities" => true
10046  );
10047  $tidy = new tidy();
10048  $tidy->parseString($print_output, $config, 'utf8');
10049  $tidy->cleanRepair();
10050  $print_output = tidy_get_output($tidy);
10051  $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
10052  }
10053  else
10054  {
10055  $print_output = str_replace("&nbsp;", "&#160;", $print_output);
10056  $print_output = str_replace("&otimes;", "X", $print_output);
10057  }
10058  $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
10059 
10060  // additional font support
10061  $xsl = str_replace(
10062  'font-family="Helvetica, unifont"',
10063  'font-family="'.$GLOBALS['ilSetting']->get('rpc_pdf_font','Helvetica, unifont').'"',
10064  $xsl
10065  );
10066 
10067  $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
10068  $xh = xslt_create();
10069  $params = array();
10070  $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", NULL, $args, $params);
10071  xslt_error($xh);
10072  xslt_free($xh);
10073  return $output;
10074  }
10075 
10082  public function deliverPDFfromHTML($content, $title = NULL)
10083  {
10084  $content = preg_replace("/href=\".*?\"/", "", $content);
10085  $printbody = new ilTemplate("tpl.il_as_tst_print_body.html", TRUE, TRUE, "Modules/Test");
10086  $printbody->setVariable("TITLE", ilUtil::prepareFormOutput($this->getTitle()));
10087  $printbody->setVariable("ADM_CONTENT", $content);
10088  $printbody->setCurrentBlock("css_file");
10089  $printbody->setVariable("CSS_FILE", $this->getTestStyleLocation("filesystem"));
10090  $printbody->parseCurrentBlock();
10091  $printbody->setCurrentBlock("css_file");
10092  $printbody->setVariable("CSS_FILE", ilUtil::getStyleSheetLocation("filesystem", "delos.css"));
10093  $printbody->parseCurrentBlock();
10094  $printoutput = $printbody->get();
10095  $html = str_replace("href=\"./", "href=\"" . ILIAS_HTTP_PATH . "/", $printoutput);
10096  $html = preg_replace("/<div id=\"dontprint\">.*?<\\/div>/ims", "", $html);
10097  if (extension_loaded("tidy"))
10098  {
10099  $config = array(
10100  "indent" => false,
10101  "output-xml" => true,
10102  "numeric-entities" => true
10103  );
10104  $tidy = new tidy();
10105  $tidy->parseString($html, $config, 'utf8');
10106  $tidy->cleanRepair();
10107  $html = tidy_get_output($tidy);
10108  $html = preg_replace("/^.*?(<html)/", "\\1", $html);
10109  }
10110  else
10111  {
10112  $html = str_replace("&nbsp;", "&#160;", $html);
10113  $html = str_replace("&otimes;", "X", $html);
10114  }
10115  $html = preg_replace("/src=\".\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
10116  $this->deliverPDFfromFO($this->processPrintoutput2FO($html), $title);
10117  }
10118 
10125  public function deliverPDFfromFO($fo, $title = null)
10126  {
10127  global $ilLog;
10128 
10129  include_once "./Services/Utilities/classes/class.ilUtil.php";
10130  $fo_file = ilUtil::ilTempnam() . ".fo";
10131  $fp = fopen($fo_file, "w"); fwrite($fp, $fo); fclose($fp);
10132 
10133  include_once './Services/WebServices/RPC/classes/class.ilRpcClientFactory.php';
10134  try
10135  {
10136  $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo);
10137  $filename = (strlen($title)) ? $title : $this->getTitle();
10138  ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
10139  return true;
10140  }
10141  catch(XML_RPC2_FaultException $e)
10142  {
10143  $ilLog->write(__METHOD__.': '.$e->getMessage());
10144  return false;
10145  }
10146  catch(Exception $e)
10147  {
10148  $ilLog->write(__METHOD__.': '.$e->getMessage());
10149  return false;
10150  }
10151 
10152  /*
10153  include_once "./Services/Transformation/classes/class.ilFO2PDF.php";
10154  $fo2pdf = new ilFO2PDF();
10155  $fo2pdf->setFOString($fo);
10156  $result = $fo2pdf->send();
10157  $filename = (strlen($title)) ? $title : $this->getTitle();
10158  ilUtil::deliverData($result, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
10159  */
10160  }
10161 
10171  static function getManualFeedback($active_id, $question_id, $pass)
10172  {
10173  global $ilDB;
10174  $feedback = "";
10175  $result = $ilDB->queryF("SELECT feedback FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10176  array('integer', 'integer', 'integer'),
10177  array($active_id, $question_id, $pass)
10178  );
10179  if ($result->numRows())
10180  {
10181  $row = $ilDB->fetchAssoc($result);
10182  include_once("./Services/RTE/classes/class.ilRTE.php");
10183  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
10184  }
10185  return $feedback;
10186  }
10187 
10198  function saveManualFeedback($active_id, $question_id, $pass, $feedback)
10199  {
10200  global $ilDB;
10201 
10202  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
10203  array('integer', 'integer', 'integer'),
10204  array($active_id, $question_id, $pass)
10205  );
10206 
10207  if (strlen($feedback))
10208  {
10209  $next_id = $ilDB->nextId('tst_manual_fb');
10211  $result = $ilDB->insert('tst_manual_fb', array(
10212  'manual_feedback_id' => array( 'integer', $next_id ),
10213  'active_fi' => array( 'integer', $active_id ),
10214  'question_fi' => array( 'integer', $question_id ),
10215  'pass' => array( 'integer', $pass),
10216  'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( $feedback, 0) ),
10217  'tstamp' => array( 'integer', time() ),
10218  )
10219  );
10220  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
10222  {
10223  global $lng, $ilUser;
10224  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
10225  $username = ilObjTestAccess::_getParticipantData($active_id);
10226  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10227  $this->logAction(sprintf($lng->txtlng("assessment", "log_manual_feedback", ilObjAssessmentFolder::_getLogLanguage()), $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")", $username, assQuestion::_getQuestionTitle($question_id), $feedback));
10228  }
10229  }
10230  if (PEAR::isError($result))
10231  {
10232  global $ilias;
10233  $ilias->raiseError($result->getMessage());
10234  }
10235  else
10236  {
10237  return TRUE;
10238  }
10239  }
10240 
10249  {
10250  return TRUE;
10251 
10252 // global $ilUser;
10253 // if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
10254 // if ($this->getForceJS()) return TRUE;
10255 // $assessmentSetting = new ilSetting("assessment");
10256 // return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
10257  }
10258 
10259  function &createTestSequence($active_id, $pass, $shuffle)
10260  {
10261  include_once "./Modules/Test/classes/class.ilTestSequence.php";
10262  $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10263  }
10264 
10270  public function setTestId($a_id)
10271  {
10272  $this->test_id = $a_id;
10273  }
10274 
10283  function getDetailedTestResults($participants)
10284  {
10285  $results = array();
10286  if (count($participants))
10287  {
10288  foreach ($participants as $active_id => $user_rec)
10289  {
10290  $row = array();
10291  $reached_points = 0;
10292  $max_points = 0;
10293  foreach ($this->questions as $value)
10294  {
10295  $question =& ilObjTest::_instanciateQuestion($value);
10296  if (is_object($question))
10297  {
10298  $max_points += $question->getMaximumPoints();
10299  $reached_points += $question->getReachedPoints($active_id);
10300  if ($max_points > 0)
10301  {
10302  $percentvalue = $reached_points / $max_points;
10303  if ($percentvalue < 0) $percentvalue = 0.0;
10304  }
10305  else
10306  {
10307  $percentvalue = 0;
10308  }
10309  if ($this->getAnonymity())
10310  {
10311  $user_rec['firstname'] = "";
10312  $user_rec['lastname'] = $this->lng->txt("anonymous");
10313  }
10314  $row = array(
10315  "user_id"=>$user_rec['usr_id'],
10316  "matriculation" => $user_rec['matriculation'],
10317  "lastname" => $user_rec['lastname'],
10318  "firstname" => $user_rec['firstname'],
10319  "login"=>$user_rec['login'],
10320  "question_id" => $question->getId(),
10321  "question_title" => $question->getTitle(),
10322  "reached_points" => $reached_points,
10323  "max_points" => $max_points
10324  );
10325  $results[] = $row;
10326  }
10327  }
10328  }
10329  }
10330  return $results;
10331  }
10332 
10337  {
10338  global $ilDB;
10339 
10340  $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",
10341  array('integer'),
10342  array($a_q_id)
10343  );
10344  $rec = $ilDB->fetchAssoc($result);
10345  return $rec["obj_id"];
10346  }
10347 
10354  function isPluginActive($a_pname)
10355  {
10356  global $ilPluginAdmin;
10357  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
10358  {
10359  return TRUE;
10360  }
10361  else
10362  {
10363  return FALSE;
10364  }
10365  }
10366 
10367  public function getPassed($active_id)
10368  {
10369  global $ilDB;
10370 
10371  $result = $ilDB->queryF("SELECT passed FROM tst_result_cache WHERE active_fi = %s",
10372  array('integer'),
10373  array($active_id)
10374  );
10375  if ($result->numRows())
10376  {
10377  $row = $ilDB->fetchAssoc($result);
10378  return $row['passed'];
10379  }
10380  else
10381  {
10382  $counted_pass = ilObjTest::_getResultPass($active_id);
10383  $result_array =& $this->getTestResult($active_id, $counted_pass);
10384  return $result_array["test"]["passed"];
10385  }
10386  }
10387 
10393  function canShowCertificate($testSession, $user_id, $active_id)
10394  {
10395  if ($this->canShowTestResults($testSession, $user_id))
10396  {
10397  include_once "./Services/Certificate/classes/class.ilCertificate.php";
10398  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
10399  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
10400  if ($cert->isComplete())
10401  {
10402  $vis = $this->getCertificateVisibility();
10403  $showcert = FALSE;
10404  switch ($vis)
10405  {
10406  case 0:
10407  $showcert = TRUE;
10408  break;
10409  case 1:
10410  if ($this->getPassed($active_id))
10411  {
10412  $showcert = TRUE;
10413  }
10414  break;
10415  case 2:
10416  $showcert = FALSE;
10417  break;
10418  }
10419  if ($showcert)
10420  {
10421  return TRUE;
10422  }
10423  else
10424  {
10425  return FALSE;
10426  }
10427  }
10428  else
10429  {
10430  return FALSE;
10431  }
10432  }
10433  else
10434  {
10435  return FALSE;
10436  }
10437  }
10438 
10442  public function getParticipantsForTestAndQuestion($test_id, $question_id)
10443  {
10445  global $ilDB;
10446 
10447  $query = "
10448  SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
10449  FROM tst_test_result, tst_active, qpl_questions
10450  WHERE tst_active.active_id = tst_test_result.active_fi
10451  AND tst_active.test_fi = %s
10452  AND tst_test_result.question_fi = qpl_questions.question_id
10453  AND tst_test_result.question_fi = %s";
10454 
10455  $result = $ilDB->queryF($query,
10456  array('integer', 'integer'),
10457  array($test_id, $question_id)
10458  );
10459  $foundusers = array();
10461  while ($row = $ilDB->fetchAssoc($result))
10462  {
10463  if (!array_key_exists($row["active_fi"], $foundusers))
10464  {
10465  $foundusers[$row["active_fi"]] = array();
10466  }
10467  array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10468  }
10469  return $foundusers;
10470  }
10471 
10477  public function getAggregatedResultsData()
10478  {
10479  $data =& $this->getCompleteEvaluationData();
10480  $foundParticipants =& $data->getParticipants();
10481  $results = array("overview" => array(), "questions" => array());
10482  if (count($foundParticipants))
10483  {
10484  $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10485  $total_finished = $this->evalTotalFinished();
10486  $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10487  $average_time = $this->evalTotalStartedAverageTime();
10488  $diff_seconds = $average_time;
10489  $diff_hours = floor($diff_seconds/3600);
10490  $diff_seconds -= $diff_hours * 3600;
10491  $diff_minutes = floor($diff_seconds/60);
10492  $diff_seconds -= $diff_minutes * 60;
10493  $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10494  $total_passed = 0;
10495  $total_passed_reached = 0;
10496  $total_passed_max = 0;
10497  $total_passed_time = 0;
10498  foreach ($foundParticipants as $userdata)
10499  {
10500  if ($userdata->getPassed())
10501  {
10502  $total_passed++;
10503  $total_passed_reached += $userdata->getReached();
10504  $total_passed_max += $userdata->getMaxpoints();
10505  $total_passed_time += $userdata->getTimeOfWork();
10506  }
10507  }
10508  $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10509  $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10510  $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10511  $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10512  $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);
10513  $average_time = $average_passed_time;
10514  $diff_seconds = $average_time;
10515  $diff_hours = floor($diff_seconds/3600);
10516  $diff_seconds -= $diff_hours * 3600;
10517  $diff_minutes = floor($diff_seconds/60);
10518  $diff_seconds -= $diff_minutes * 60;
10519  $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10520  }
10521 
10522  foreach ($data->getQuestionTitles() as $question_id => $question_title)
10523  {
10524  $answered = 0;
10525  $reached = 0;
10526  $max = 0;
10527  foreach ($foundParticipants as $userdata)
10528  {
10529  for ($i = 0; $i <= $userdata->getLastPass(); $i++)
10530  {
10531  if (is_object($userdata->getPass($i)))
10532  {
10533  $question =& $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10534  if (is_array($question))
10535  {
10536  $answered++;
10537  $reached += $question["reached"];
10538  $max += $question["points"];
10539  }
10540  }
10541  }
10542  }
10543  $percent = $max ? $reached/$max * 100.0 : 0;
10544  $counter++;
10545  $results["questions"][$question_id] = array(
10546  $question_title,
10547  sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10548  sprintf("%.2f", $percent) . "%",
10549  $answered,
10550  sprintf("%.2f", $answered ? $reached / $answered : 0),
10551  sprintf("%.2f", $answered ? $max / $answered : 0),
10552  $percent / 100.0
10553  );
10554  }
10555  return $results;
10556  }
10557 
10561  function getXMLZip()
10562  {
10563  include_once("./Modules/Test/classes/class.ilTestExport.php");
10564  $test_exp = new ilTestExport($this, "xml");
10565  return $test_exp->buildExportFile();
10566  }
10567 
10571  public function getMailNotification()
10572  {
10573  return $this->mailnotification;
10574  }
10575 
10581  public function setMailNotification($a_notification)
10582  {
10583  $this->mailnotification = $a_notification;
10584  }
10585 
10586  public function sendSimpleNotification($active_id)
10587  {
10588  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10589 
10590  $mail = new ilTestMailNotification();
10591  $owner_id = $this->getOwner();
10592  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10593  $mail->sendSimpleNotification($owner_id, $this->getTitle(), $usr_data);
10594  }
10595 
10602  {
10603  include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
10604  include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
10605  $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI(), 'outEvaluation', $this->getAnonymity());
10606  return $table_gui->getSelectedColumns();
10607  }
10608 
10609  public function sendAdvancedNotification($active_id)
10610  {
10611  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10612 
10613  $mail = new ilTestMailNotification();
10614  $owner_id = $this->getOwner();
10615  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10616 
10617  include_once "./Modules/Test/classes/class.ilTestExport.php";
10618  $exportObj = new ilTestExport($this, "results");
10619  $file = $exportObj->exportToExcel($deliver = FALSE, 'active_id', $active_id, $passedonly = FALSE);
10620  include_once "./Services/Mail/classes/class.ilFileDataMail.php";
10621  $fd = new ilFileDataMail(ANONYMOUS_USER_ID);
10622  $fd->copyAttachmentFile($file, "result_" . $active_id . ".xls");
10623  $file_names[] = "result_" . $active_id . ".xls";
10624 
10625  $mail->sendAdvancedNotification($owner_id, $this->getTitle(), $usr_data, $file_names);
10626 
10627  if(count($file_names))
10628  {
10629  $fd->unlinkFiles($file_names);
10630  unset($fd);
10631  @unlink($file);
10632  }
10633  }
10634 
10635  function createRandomSolutions($number)
10636  {
10637  global $ilDB;
10638 
10639  // 1. get a user
10640  $query = "SELECT usr_id FROM usr_data";
10641  $result = $ilDB->query($query);
10642  while ($data = $ilDB->fetchAssoc($result))
10643  {
10644  $activequery = sprintf("SELECT user_fi FROM tst_active WHERE test_fi = %s AND user_fi = %s",
10645  $ilDB->quote($this->getTestId()),
10646  $ilDB->quote($data['usr_id'])
10647  );
10648  $activeresult = $ilDB->query($activequery);
10649  if ($activeresult->numRows() == 0)
10650  {
10651  $user_id = $data['usr_id'];
10652  if ($user_id != 13)
10653  {
10654  include_once "./Modules/Test/classes/class.ilTestSession.php";
10655  $testSession = FALSE;
10656  $testSession = new ilTestSession();
10657  $testSession->setRefId($this->getRefId());
10658  $testSession->setTestId($this->getTestId());
10659  $testSession->setUserId($user_id);
10660  $testSession->saveToDb();
10661  $passes = ($this->getNrOfTries()) ? $this->getNrOfTries() : 10;
10662  $nr_of_passes = rand(1, $passes);
10663  $active_id = $testSession->getActiveId();
10664  for ($pass = 0; $pass < $nr_of_passes; $pass++)
10665  {
10666  include_once "./Modules/Test/classes/class.ilTestSequence.php";
10667  $testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10668  if (!$testSequence->hasSequence())
10669  {
10670  $testSequence->createNewSequence($this->getQuestionCount(), $shuffle);
10671  $testSequence->saveToDb();
10672  }
10673  for ($seq = 1; $seq <= count($this->questions); $seq++)
10674  {
10675  $question_id = $testSequence->getQuestionForSequence($seq);
10676  $objQuestion = ilObjTest::_instanciateQuestion($question_id);
10677  $objQuestion->createRandomSolution($testSession->getActiveId(), $pass);
10678  }
10679  if ($pass < $nr_of_passes - 1)
10680  {
10681  $testSession->increasePass();
10682  $testSession->setLastSequence(0);
10683  $testSession->saveToDb();
10684  }
10685  else
10686  {
10687  $testSession->setSubmitted(1);
10688  $testSession->setSubmittedTimestamp(date('Y-m-d H:i:s'));
10689  $testSession->saveToDb();
10690  }
10691  }
10692  $number--;
10693  if ($number == 0) return;
10694  }
10695  }
10696  }
10697  }
10698 
10699  public function getResultsForActiveId($active_id)
10700  {
10701  global $ilDB;
10702 
10703  $query = "
10704  SELECT *
10705  FROM tst_result_cache
10706  WHERE active_fi = %s
10707  ";
10708 
10709  $result = $ilDB->queryF(
10710  $query, array('integer'), array($active_id)
10711  );
10712 
10713  if( !$result->numRows() )
10714  {
10715  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10716 
10718 
10719  $query = "
10720  SELECT *
10721  FROM tst_result_cache
10722  WHERE active_fi = %s
10723  ";
10724 
10725  $result = $ilDB->queryF(
10726  $query, array('integer'), array($active_id)
10727  );
10728  }
10729 
10730  $row = $ilDB->fetchAssoc($result);
10731 
10732  return $row;
10733 
10734  }
10735 
10736  public function getMailNotificationType()
10737  {
10738  if ($this->mailnottype == 1)
10739  {
10740  return $this->mailnottype;
10741  }
10742  else
10743  {
10744  return 0;
10745  }
10746  }
10747 
10748  public function setMailNotificationType($a_type)
10749  {
10750  if ($a_type == 1)
10751  {
10752  $this->mailnottype = 1;
10753  }
10754  else
10755  {
10756  $this->mailnottype = 0;
10757  }
10758  }
10759 
10760  public function getExportSettings()
10761  {
10762  if ($this->exportsettings)
10763  {
10764  return $this->exportsettings;
10765  }
10766  else
10767  {
10768  return 0;
10769  }
10770  }
10771 
10772  public function setExportSettings($a_settings)
10773  {
10774  if ($a_settings)
10775  {
10776  $this->exportsettings = $a_settings;
10777  }
10778  else
10779  {
10780  $this->exportsettings = 0;
10781  }
10782  }
10783 
10785  {
10786  if (($this->exportsettings & 1) > 0)
10787  {
10788  return true;
10789  }
10790  else
10791  {
10792  return false;
10793  }
10794  }
10795 
10796  public function setExportSettingsSingleChoiceShort($a_settings)
10797  {
10798  if ($a_settings)
10799  {
10800  $this->exportsettings = $this->exportsettings | 1;
10801  }
10802  else
10803  {
10805  {
10806  $this->exportsettings = $this->exportsettings ^ 1;
10807  }
10808  }
10809  }
10810 
10811  public function getEnabledViewMode() {
10812  return $this->enabled_view_mode;
10813  }
10814 
10815  public function setEnabledViewMode($mode) {
10816  $this->enabled_view_mode = $mode;
10817  }
10818 
10820  $this->template_id = (int)$template_id;
10821  }
10822 
10823  function getTemplate() {
10824  return $this->template_id;
10825  }
10826 
10827  public function moveQuestionAfterOLD($previous_question_id, $new_question_id) {
10828  $new_array = array();
10829  $position = 1;
10830 
10831  $query = 'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
10832  $types = array('integer');
10833  $values = array($this->getTestId());
10834 
10835  $new_question_id += 1;
10836 
10837  global $ilDB;
10838  $inserted = false;
10839  $res = $ilDB->queryF($query, $types, $values);
10840  while($row = $ilDB->fetchAssoc($res)) {
10841 
10842  $qid = $row['question_fi'];
10843 
10844  if ($qid == $new_question_id) {
10845  continue;
10846  }
10847  else if ($qid == $previous_question_id) {
10848  $new_array[$position++] = $qid;
10849  $new_array[$position++] = $new_question_id;
10850  $inserted = true;
10851  }
10852  else {
10853  $new_array[$position++] = $qid;
10854  }
10855  }
10856 
10857  $update_query = 'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
10858  $update_types = array('integer', 'integer', 'integer');
10859 
10860  foreach($new_array as $position => $qid) {
10861  $ilDB->manipulateF(
10862  $update_query,
10863  $update_types,
10864  $vals = array(
10865  $position,
10866  $this->getTestId(),
10867  $qid
10868  )
10869  );
10870  }
10871  }
10872 
10874  {
10875  if (is_array($options))
10876  {
10877  $this->setGenericAnswerFeedback( in_array('instant_feedback_generic', $options) ? 1 : 0);
10878  $this->setSpecificAnswerFeedback( in_array('instant_feedback_specific', $options) ? 1 : 0);
10879  $this->setAnswerFeedbackPoints( in_array('instant_feedback_points', $options) ? 1 : 0);
10880  $this->setInstantFeedbackSolution( in_array('instant_feedback_solution', $options) ? 1 : 0);
10881  $this->setInstantFeedbackAnswerFixationEnabled( in_array('instant_feedback_answer_fixation', $options) ? true : false);
10882  }
10883  else
10884  {
10885  $this->setGenericAnswerFeedback(0);
10886  $this->setSpecificAnswerFeedback(0);
10887  $this->setAnswerFeedbackPoints(0);
10888  $this->setInstantFeedbackSolution(0);
10890  }
10891  }
10892 
10894  $setter = array(
10895  'pass_details' => 'setShowPassDetails',
10896  'solution_details' => 'setShowSolutionDetails',
10897  'solution_printview' => 'setShowSolutionPrintview',
10898  'solution_feedback' => 'setShowSolutionFeedback',
10899  'solution_answers_only' => 'setShowSolutionAnswersOnly',
10900  'solution_signature' => 'setShowSolutionSignature',
10901  'solution_suggested' => 'setShowSolutionSuggested',
10902  );
10903  foreach($setter as $key => $setter) {
10904  if (in_array($key, $options)) {
10905  $this->$setter(1);
10906  }
10907  else {
10908  $this->$setter(0);
10909  }
10910  }
10911  }
10912 
10913  public function getPoolUsage() {
10914  return (boolean) $this->poolUsage;
10915  }
10916 
10917  public function setPoolUsage($usage) {
10918  $this->poolUsage = (boolean)$usage;
10919  }
10920 
10921  public function setQuestionOrderAndObligations($orders, $obligations)
10922  {
10923  global $ilDB;
10924 
10925  asort($orders);
10926 
10927  $i = 0;
10928 
10929  foreach($orders as $id => $position)
10930  {
10931  $i++;
10932 
10933  $obligatory = (
10934  isset($obligations[$id]) && $obligations[$id] ? 1 : 0
10935  );
10936 
10937  $query = "
10938  UPDATE tst_test_question
10939  SET sequence = %s,
10940  obligatory = %s
10941  WHERE question_fi = %s
10942  ";
10943 
10944  $ilDB->manipulateF(
10945  $query, array('integer', 'integer', 'integer'), array($i, $obligatory, $id)
10946  );
10947  }
10948 
10949  $this->loadQuestions();
10950  }
10951 
10952  public function moveQuestionAfter($question_to_move, $question_before) {
10953  global $ilDB;
10954  //var_dump(func_get_args());
10955  if ($question_before) {
10956  $query = 'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
10957  $types = array('integer');
10958  $values = array($question_before);
10959  $rset = $ilDB->queryF($query, $types, $values);
10960  }
10961 
10962  if (!$question_before || ($rset && !($row = $ilDB->fetchAssoc($rset)))) {
10963  $row = array(
10964  'sequence' => 0,
10965  'test_fi' => $this->getTestId(),
10966  );
10967  }
10968 
10969  $update = 'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
10970  $types = array('integer', 'integer');
10971  $values = array($row['sequence'], $row['test_fi']);
10972  $ilDB->manipulateF($update, $types, $values);
10973 
10974  $update = 'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
10975  $types = array('integer', 'integer');
10976  $values = array($row['sequence'] + 1, $question_to_move);
10977  $ilDB->manipulateF($update, $types, $values);
10978 
10979  }
10980 
10982  {
10983  global $ilDB;
10984 
10986 
10987  $IN_questions = $ilDB->in('q1.question_id', array_keys($questions), false, 'integer');
10988 
10989  $query = "
10990  SELECT count(q1.question_id) cnt
10991 
10992  FROM qpl_questions q1
10993 
10994  INNER JOIN qpl_questions q2
10995  ON q2.question_id = q1.original_id
10996 
10997  WHERE $IN_questions
10998  AND q1.obj_fi = q2.obj_fi
10999  ";
11000 
11001  $rset = $ilDB->query($query);
11002 
11003  $row = $ilDB->fetchAssoc($rset);
11004 
11005  return $row['cnt'] > 0;
11006  }
11007 
11014  public static function _lookupFinishedUserTests($a_user_id)
11015  {
11016  global $ilDB;
11017 
11018  $result = $ilDB->queryF("SELECT test_fi,MAX(pass) AS pass FROM tst_active".
11019  " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)".
11020  " WHERE user_fi=%s".
11021  " GROUP BY test_fi",
11022  array('integer', 'integer'),
11023  array($a_user_id, 1)
11024  );
11025  $all = array();
11026  while($row = $ilDB->fetchAssoc($result))
11027  {
11028  $obj_id = self::_getObjectIDFromTestID($row["test_fi"]);
11029  $all[$obj_id] = (bool)$row["pass"];
11030  }
11031  return $all;
11032  }
11033  public function getQuestions()
11034  {
11035  return $this->questions;
11036  }
11037 
11038  public function isOnline()
11039  {
11040  return $this->online;
11041  }
11042 
11043  public function setOnline($a_online = true)
11044  {
11045  $this->online = (bool)$a_online;
11046  }
11047 
11048  public function setPrintBestSolutionWithResult($status)
11049  {
11050  $this->print_best_solution_with_result = (bool) $status;
11051  }
11052 
11054  {
11056  }
11057 
11064  {
11066  }
11067 
11074  {
11075  $this->offeringQuestionHintsEnabled = (bool)$offeringQuestionHintsEnabled;
11076  }
11077 
11078  function setActivationVisibility($a_value)
11079  {
11080  $this->activation_visibility = (bool) $a_value;
11081  }
11082 
11084  {
11086  }
11087 
11089  {
11090  return (bool)$this->activation_limited;
11091  }
11092 
11093  function setActivationLimited($a_value)
11094  {
11095  $this->activation_limited = (bool)$a_value;
11096  }
11097 
11098  /* GET/SET for highscore feature */
11099 
11105  public function setHighscoreEnabled($a_enabled)
11106  {
11107  $this->_highscore_enabled = (bool)$a_enabled;
11108  }
11109 
11115  public function getHighscoreEnabled()
11116  {
11117  return (bool) $this->_highscore_enabled;
11118  }
11119 
11127  public function setHighscoreAnon($a_anon)
11128  {
11129  $this->_highscore_anon = (bool)$a_anon;
11130  }
11131 
11141  public function getHighscoreAnon()
11142  {
11143  return (bool) $this->_highscore_anon;
11144  }
11145 
11154  public function isHighscoreAnon()
11155  {
11156  if ($this->getAnonymity() == 1)
11157  {
11158  return true;
11159  }
11160  else
11161  {
11162  return (bool)$this->getHighscoreAnon();
11163  }
11164  }
11165 
11171  public function setHighscoreAchievedTS($a_achieved_ts)
11172  {
11173  $this->_highscore_achieved_ts = (bool)$a_achieved_ts;
11174  }
11175 
11181  public function getHighscoreAchievedTS()
11182  {
11183  return (bool) $this->_highscore_achieved_ts;
11184  }
11185 
11191  public function setHighscoreScore($a_score)
11192  {
11193  $this->_highscore_score = (bool)$a_score;
11194  }
11195 
11201  public function getHighscoreScore()
11202  {
11203  return (bool) $this->_highscore_score;
11204  }
11205 
11211  public function setHighscorePercentage($a_percentage)
11212  {
11213  $this->_highscore_percentage = (bool)$a_percentage;
11214  }
11215 
11221  public function getHighscorePercentage()
11222  {
11223  return (bool) $this->_highscore_percentage;
11224  }
11225 
11231  public function setHighscoreHints($a_hints)
11232  {
11233  $this->_highscore_hints = (bool)$a_hints;
11234  }
11235 
11241  public function getHighscoreHints()
11242  {
11243  return (bool) $this->_highscore_hints;
11244  }
11245 
11251  public function setHighscoreWTime($a_wtime)
11252  {
11253  $this->_highscore_wtime = (bool)$a_wtime;
11254  }
11255 
11261  public function getHighscoreWTime()
11262  {
11263  return (bool) $this->_highscore_wtime;
11264  }
11265 
11271  public function setHighscoreOwnTable($a_own_table)
11272  {
11273  $this->_highscore_own_table = (bool)$a_own_table;
11274  }
11275 
11281  public function getHighscoreOwnTable()
11282  {
11283  return (bool) $this->_highscore_own_table;
11284  }
11285 
11291  public function setHighscoreTopTable($a_top_table)
11292  {
11293  $this->_highscore_top_table = (bool)$a_top_table;
11294  }
11295 
11301  public function getHighscoreTopTable()
11302  {
11303  return (bool) $this->_highscore_top_table;
11304  }
11305 
11312  public function setHighscoreTopNum($a_top_num)
11313  {
11314  $this->_highscore_top_num = (int)$a_top_num;
11315  }
11316 
11325  public function getHighscoreTopNum($a_retval = 10)
11326  {
11327  $retval = $a_retval;
11328  if ( (int) $this->_highscore_top_num != 0)
11329  {
11330  $retval = $this->_highscore_top_num;
11331  }
11332 
11333  return $retval;
11334  }
11335 
11339  public function getHighscoreMode()
11340  {
11341  switch(true)
11342  {
11343  case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
11345  break;
11346 
11347  case $this->getHighscoreTopTable():
11349  break;
11350 
11351  case $this->getHighscoreOwnTable():
11352  default:
11354  break;
11355  }
11356  }
11357 
11361  public function setHighscoreMode($mode)
11362  {
11363  switch($mode)
11364  {
11365  case self::HIGHSCORE_SHOW_ALL_TABLES:
11366  $this->setHighscoreTopTable(1);
11367  $this->setHighscoreOwnTable(1);
11368  break;
11369 
11370  case self::HIGHSCORE_SHOW_TOP_TABLE:
11371  $this->setHighscoreTopTable(1);
11372  $this->setHighscoreOwnTable(0);
11373  break;
11374 
11375  case self::HIGHSCORE_SHOW_OWN_TABLE:
11376  default:
11377  $this->setHighscoreTopTable(0);
11378  $this->setHighscoreOwnTable(1);
11379  break;
11380  }
11381  }
11382  /* End GET/SET for highscore feature*/
11383 
11384  public function setSpecificAnswerFeedback($specific_answer_feedback)
11385  {
11386  switch ($specific_answer_feedback)
11387  {
11388  case 1:
11389  $this->specific_answer_feedback = 1;
11390  break;
11391  default:
11392  $this->specific_answer_feedback = 0;
11393  break;
11394  }
11395  }
11396 
11397  public function getSpecificAnswerFeedback()
11398  {
11399  switch ($this->specific_answer_feedback)
11400  {
11401  case 1:
11402  return 1;
11403  default:
11404  return 0;
11405  }
11406  }
11407 
11414  {
11415  $this->obligationsEnabled = (bool)$obligationsEnabled;
11416  }
11417 
11423  public function areObligationsEnabled()
11424  {
11425  return (bool)$this->obligationsEnabled;
11426  }
11427 
11434  public static function isQuestionObligationPossible($questionId)
11435  {
11436  require_once('Modules/TestQuestionPool/classes/class.assQuestion.php');
11437 
11438  $classConcreteQuestion = assQuestion::_getQuestionType($questionId);
11439 
11440  assQuestion::_includeClass($classConcreteQuestion, 0);
11441 
11442  // static binder is not at work yet (in PHP < 5.3)
11443  //$obligationPossible = $classConcreteQuestion::isObligationPossible();
11444  $obligationPossible = call_user_func(array($classConcreteQuestion, 'isObligationPossible'), $questionId);
11445 
11446  return $obligationPossible;
11447  }
11448 
11455  public static function isQuestionObligatory($question_id)
11456  {
11457  global $ilDB;
11458 
11459  $rset = $ilDB->queryF('SELECT obligatory FROM tst_test_question WHERE question_fi = %s', array('integer'), array($question_id));
11460 
11461  if( $row = $ilDB->fetchAssoc($rset) )
11462  {
11463  return (bool) $row['obligatory'];
11464  }
11465 
11466  return false;
11467  }
11468 
11481  public static function allObligationsAnswered($test_id, $active_id, $pass)
11482  {
11483  global $ilDB;
11484 
11485  $rset = $ilDB->queryF(
11486  'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
11487  array('integer', 'integer'),
11488  array($active_id, $pass)
11489  );
11490 
11491  if( $row = $ilDB->fetchAssoc($rset) )
11492  {
11493  return (bool)$row['obligations_answered'];
11494  }
11495 
11496  return !self::hasObligations($test_id);
11497  }
11498 
11507  public static function hasObligations($test_id)
11508  {
11509  global $ilDB;
11510 
11511  $rset = $ilDB->queryF(
11512  'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
11513  array('integer'), array($test_id)
11514  );
11515 
11516  $row = $ilDB->fetchAssoc($rset);
11517 
11518  return (bool)$row['cnt'] > 0;
11519  }
11520 
11521  public function setAutosave($autosave)
11522  {
11523  $this->autosave = $autosave;
11524  }
11525 
11526  public function getAutosave()
11527  {
11528  return $this->autosave;
11529  }
11530 
11532  {
11533  $this->autosave_ival = $autosave_ival;
11534  }
11535 
11536  public function getAutosaveIval()
11537  {
11538  return $this->autosave_ival;
11539  }
11540 
11546  public function isPassDeletionAllowed()
11547  {
11549  }
11550 
11557  {
11558  $this->passDeletionAllowed = (bool)$passDeletionAllowed;
11559  }
11560 
11561  #region Examview / PDF Examview
11562 
11566  {
11567  $this->show_examview_html = $show_examview_html;
11568  }
11569 
11573  public function getShowExamviewHtml()
11574  {
11576  }
11577 
11582  {
11583  $this->show_examview_pdf = $show_examview_pdf;
11584  }
11585 
11589  public function getShowExamviewPdf()
11590  {
11591  return $this->show_examview_pdf;
11592  }
11593 
11598  {
11599  $this->enable_examview = $enable_examview;
11600  }
11601 
11605  public function getEnableExamview()
11606  {
11607  return $this->enable_examview;
11608  }
11609 
11610  #endregion
11611 
11613  {
11614  $this->activation_starting_time = $starting_time;
11615  }
11616 
11618  {
11619  $this->activation_ending_time = $ending_time;
11620  }
11621 
11623  {
11624  return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : NULL;
11625  }
11626 
11628  {
11629  return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : NULL;
11630  }
11631 
11633  {
11634  global $ilDB;
11635 
11636  $times = array();
11637  $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");
11638  while ($row = $ilDB->fetchAssoc($result))
11639  {
11640  $times[$row['active_fi']] = $row['started'];
11641  }
11642  return $times;
11643  }
11644 
11646  {
11647  global $ilDB;
11648 
11649  $times = array();
11650  $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",
11651  array('integer'),
11652  array($this->getTestId())
11653  );
11654  while ($row = $ilDB->fetchAssoc($result))
11655  {
11656  $times[$row['active_fi']] = $row['additionaltime'];
11657  }
11658  return $times;
11659  }
11660 
11661  public function getExtraTime($active_id)
11662  {
11663  global $ilDB;
11664 
11665  $result = $ilDB->queryF("SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
11666  array('integer'),
11667  array($active_id)
11668  );
11669  if ($result->numRows() > 0)
11670  {
11671  $row = $ilDB->fetchAssoc($result);
11672  return $row['additionaltime'];
11673  }
11674  return 0;
11675  }
11676 
11677  public function addExtraTime($active_id, $minutes)
11678  {
11679  global $ilDB;
11680 
11681  $participants = array();
11682  if ($active_id == 0)
11683  {
11684  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s",
11685  array('integer'),
11686  array($this->getTestId())
11687  );
11688  while ($row = $ilDB->fetchAssoc($result))
11689  {
11690  array_push($participants, $row['active_id']);
11691  }
11692  }
11693  else
11694  {
11695  array_push($participants, $active_id);
11696  }
11697  foreach ($participants as $active_id)
11698  {
11699  $result = $ilDB->queryF("SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
11700  array('integer'),
11701  array($active_id)
11702  );
11703  if ($result->numRows() > 0)
11704  {
11705  $ilDB->manipulateF("DELETE FROM tst_addtime WHERE active_fi = %s",
11706  array('integer'),
11707  array($active_id)
11708  );
11709  }
11710 
11711  $ilDB->manipulateF("UPDATE tst_active SET tries = %s, submitted = %s, submittimestamp = %s WHERE active_id = %s",
11712  array('integer','integer','timestamp','integer'),
11713  array(0, 0, NULL, $active_id)
11714  );
11715 
11716  $ilDB->manipulateF("INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
11717  array('integer','integer','integer'),
11718  array($active_id, $minutes, time())
11719  );
11720 
11721  require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
11723  {
11724  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_added_extratime", ilObjAssessmentFolder::_getLogLanguage()), $minutes, $active_id));
11725  }
11726  }
11727  }
11728 
11735  {
11736  $this->enable_archiving = $enable_archiving;
11737  return $this;
11738  }
11739 
11743  public function getEnableArchiving()
11744  {
11745  return $this->enable_archiving;
11746  }
11747 
11748  public function getMaxPassOfTest()
11749  {
11753  global $ilDB;
11754 
11755  $query = '
11756  SELECT MAX(tst_pass_result.pass) + 1 max_res
11757  FROM tst_pass_result
11758  INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
11759  WHERE test_fi = '.$ilDB->quote($this->getTestId(), 'integer').'
11760  ';
11761  $res = $ilDB->query($query);
11762  $data = $ilDB->fetchAssoc($res);
11763  return (int)$data['max_res'];
11764  }
11765 
11771  public function lookupExamId($active_id, $pass)
11772  {
11774  global $ilDB, $ilSetting;
11775 
11776  $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
11777  $exam_id_result = $ilDB->queryF( $exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ) );
11778  if ($ilDB->numRows( $exam_id_result ) == 1)
11779  {
11780  $exam_id_row = $ilDB->fetchAssoc( $exam_id_result );
11781 
11782  if ($exam_id_row['exam_id'] != null)
11783  {
11784  return $exam_id_row['exam_id'];
11785  }
11786  }
11787 
11788  return null;
11789  }
11790 
11797  public static function buildExamId($active_id, $pass, $test_obj_id = null)
11798  {
11800  global $ilSetting;
11801 
11802  $inst_id = $ilSetting->get( 'inst_id', null );
11803 
11804  if($test_obj_id === null)
11805  {
11806  $obj_id = self::_getObjectIDFromActiveID($active_id);
11807  }
11808  else
11809  {
11810  $obj_id = $test_obj_id;
11811  }
11812 
11813  $examId = 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
11814 
11815  return $examId;
11816  }
11817 
11819  {
11820  $this->show_exam_id_in_test_pass_enabled = $show_exam_id_in_test_pass_enabled;
11821  }
11822 
11824  {
11826  }
11827 
11832  {
11833  $this->show_exam_id_in_test_results_enabled = $show_exam_id_in_test_results_enabled;
11834  }
11835 
11840  {
11842  }
11843 
11848  {
11849  $this->sign_submission = $sign_submission;
11850  }
11851 
11855  public function getSignSubmission()
11856  {
11857  return $this->sign_submission;
11858  }
11859 
11863  public function setCharSelectorAvailability($availability)
11864  {
11865  $this->char_selector_availability = (int) $availability;
11866  }
11867 
11872  {
11873  return (int) $this->char_selector_availability;
11874  }
11875 
11879  public function setCharSelectorDefinition($definition = '')
11880  {
11881  $this->char_selector_definition = $definition;
11882  }
11883 
11887  public function getCharSelectorDefinition()
11888  {
11890  }
11891 
11892 
11899  {
11900  $this->questionSetType = $questionSetType;
11901  }
11902 
11908  public function getQuestionSetType()
11909  {
11910  return $this->questionSetType;
11911  }
11912 
11920  public static function lookupQuestionSetType($objId)
11921  {
11922  global $ilDB;
11923 
11924  $query = "SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
11925 
11926  $res = $ilDB->queryF($query, array('integer'), array($objId));
11927 
11928  $questionSetType = null;
11929 
11930  while( $row = $ilDB->fetchAssoc($res) )
11931  {
11932  $questionSetType = $row['question_set_type'];
11933  }
11934 
11935  return $questionSetType;
11936  }
11937 
11943  public function isFixedTest()
11944  {
11946  }
11947 
11953  public function isRandomTest()
11954  {
11956  }
11957 
11963  public function isDynamicTest()
11964  {
11966  }
11967 
11975  public static function _lookupRandomTest($a_obj_id)
11976  {
11978  }
11979 
11981  {
11982  switch( $questionSetType )
11983  {
11985  return $lng->txt('tst_question_set_type_fixed');
11986 
11988  return $lng->txt('tst_question_set_type_random');
11989 
11991  return $lng->txt('tst_question_set_type_dynamic');
11992  }
11993 
11994  throw new ilTestException('invalid question set type value given: '.$questionSetType);
11995  }
11996 
11997  public function participantDataExist()
11998  {
11999  if( $this->participantDataExist === null )
12000  {
12001  $this->participantDataExist = (bool)$this->evalTotalPersons();
12002  }
12003 
12005  }
12006 
12007  public function isScoreReportingAvailable()
12008  {
12009  if ($this->getScoreReporting() == 4)
12010  {
12011  return false;
12012  }
12013 
12014  if ($this->getScoreReporting() == 3 && $this->getReportingDate() > time())
12015  {
12016  return false;
12017  }
12018 
12019  return true;
12020  }
12021 
12022  public function recalculateScores($preserve_manscoring = false)
12023  {
12024  require_once 'class.ilTestScoring.php';
12025  $scoring = new ilTestScoring($this);
12026  $scoring->setPreserveManualScores($preserve_manscoring);
12027  $scoring->recalculateSolutions();
12028  }
12029 
12030  public static function getPoolQuestionChangeListeners(ilDB $db, $poolObjId)
12031  {
12032  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
12033 
12034  $questionChangeListeners = array(
12036  );
12037 
12038  return $questionChangeListeners;
12039  }
12040 
12041  public static function getTestObjIdsWithActiveForUserId($userId)
12042  {
12043  global $ilDB;
12044 
12045  $query = "
12046  SELECT obj_fi
12047  FROM tst_active
12048  INNER JOIN tst_tests
12049  ON test_id = test_fi
12050  WHERE user_fi = %s
12051  ";
12052 
12053  $res = $ilDB->queryF($query, array('integer'), array($userId));
12054 
12055  $objIds = array();
12056 
12057  while( $row = $ilDB->fetchAssoc($res) )
12058  {
12059  $objIds[] = (int)$row['obj_fi'];
12060  }
12061 
12062  return $objIds;
12063  }
12064 
12066  {
12067  $this->skillServiceEnabled = $skillServiceEnabled;
12068  }
12069 
12070  public function isSkillServiceEnabled()
12071  {
12073  }
12074 
12076  {
12077  $this->resultFilterTaxIds = $resultFilterTaxIds;
12078  }
12079 
12080  public function getResultFilterTaxIds()
12081  {
12083  }
12084 
12086  {
12087  if( !$this->isSkillServiceEnabled() )
12088  {
12089  return false;
12090  }
12091 
12092  if( !self::isSkillManagementGloballyActivated() )
12093  {
12094  return false;
12095  }
12096 
12097  return true;
12098  }
12099 
12101 
12102  public static function isSkillManagementGloballyActivated()
12103  {
12104  if( self::$isSkillManagementGloballyActivated === null )
12105  {
12106  include_once 'Services/Skill/classes/class.ilSkillManagementSettings.php';
12107  $skmgSet = new ilSkillManagementSettings();
12108 
12109  self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
12110  }
12111 
12113  }
12114 
12116  {
12117  $this->showGradingStatusEnabled = $showGradingStatusEnabled;
12118  }
12119 
12120  public function isShowGradingStatusEnabled()
12121  {
12123  }
12124 
12126  {
12127  $this->showGradingMarkEnabled = $showGradingMarkEnabled;
12128  }
12129 
12130 
12131  public function isShowGradingMarkEnabled()
12132  {
12134  }
12135 
12137  {
12138  $this->instantFeedbackAnswerFixationEnabled = $instantFeedbackAnswerFixationEnabled;
12139  }
12140 
12142  {
12144  }
12145 
12146  public static function ensureParticipantsLastActivePassFinished($testObjId, $userId, $a_force_new_run = FALSE)
12147  {
12148  global $ilDB, $lng, $ilPluginAdmin;
12149 
12150  /* @var ilObjTest $testOBJ */
12151 
12152  $testOBJ = ilObjectFactory::getInstanceByRefId($testObjId,false);
12153 
12154  $activeId = $testOBJ->getActiveIdOfUser($userId);
12155 
12156  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12157  $testSessionFactory = new ilTestSessionFactory($testOBJ);
12158 
12159  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12160  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12161 
12162  $testSession = $testSessionFactory->getSession($activeId);
12163  $testSequence = $testSequenceFactory->getSequenceByPass($testSession, $testSession->getPass());
12164  $testSequence->loadFromDb();
12165 
12166  // begin-patch lok changed smeyer
12167  if($a_force_new_run)
12168  {
12169  if( $testSequence->hasSequence() )
12170  {
12171  $testSession->increasePass();
12172  }
12173  $testSession->setLastSequence(0);
12174  $testSession->saveToDb();
12175  }
12176  // end-patch lok
12177  }
12178 
12179  public static function isParticipantsLastPassActive($testObjId, $userId)
12180  {
12181  global $ilDB, $lng, $ilPluginAdmin;
12182 
12183  /* @var ilObjTest $testOBJ */
12184 
12185  $testOBJ = ilObjectFactory::getInstanceByRefId($testObjId,false);
12186 
12187 
12188  $activeId = $testOBJ->getActiveIdOfUser($userId);
12189 
12190  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
12191  $testSessionFactory = new ilTestSessionFactory($testOBJ);
12192  // Added temporarily bugfix smeyer
12193  $testSessionFactory->reset();
12194 
12195  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
12196  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $testOBJ);
12197 
12198  $testSession = $testSessionFactory->getSession($activeId);
12199  $testSequence = $testSequenceFactory->getSequenceByPass($testSession, $testSession->getPass());
12200  $testSequence->loadFromDb();
12201 
12202  return $testSequence->hasSequence();
12203  }
12204 
12208  public function isTestFinalBroken()
12209  {
12210  return $this->testFinalBroken;
12211  }
12212 
12217  {
12218  $this->testFinalBroken = $testFinalBroken;
12219  }
12220 }