ILIAS  Release_4_4_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 include_once "./Services/Object/classes/class.ilObject.php";
5 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
6 
17 class ilObjTest extends ilObject
18 {
19  #region Properties
20 
24  const QUESTION_SET_TYPE_FIXED = 'FIXED_QUEST_SET';
25 
29  const QUESTION_SET_TYPE_RANDOM = 'RANDOM_QUEST_SET';
30 
34  const QUESTION_SET_TYPE_DYNAMIC = 'DYNAMIC_QUEST_SET';
35 
42 
50  protected $_kiosk;
51 
57  var $test_id;
58 
65 
72  var $author;
73 
79  var $metadata;
80 
87 
95 
102 
111 
122 
131 
138 
148 
155 
163 
171 
181 
188 
195 
202 
209 
216 
223 
229  var $ects_fx;
230 
237 
238 
246 
253 
260 
268 
275 
282 
289 
296 
303 
310 
317 
324 
331 
338 
345 
352 
359 
366 
373 
380 
386  private $_showinfo;
387 
393  private $_forcejs;
394 
400  private $_customStyle;
401 
402  protected $mailnotification;
403 
404  protected $mailnottype;
405 
406  protected $exportsettings;
407 
408  protected $poolUsage;
409 
410  private $template_id;
411 
417  private $online = null;
418 
423 
430 
436  private $obligationsEnabled = null;
437 
439 
441 
443 
444  protected $autosave;
445 
446  protected $autosave_ival;
447 
454  private $passDeletionAllowed = null;
455 
461  private $participantDataExist = null;
462 
464  protected $enable_examview;
465 
468 
471 
473  protected $enable_archiving;
474 
478  private $redirection_mode = 0;
479 
483  private $redirection_url = NULL;
484 
487 
490 
492  protected $sign_submission;
493 
496 
499 
503  protected $testFinalBroken;
504 
505  #endregion
506 
515  public function __construct($a_id = 0,$a_call_by_reference = true)
516  {
517  global $ilUser, $lng;
518  $this->type = "tst";
519 
520  $lng->loadLanguageModule("assessment");
521  // Defaults:
522  include_once "./Modules/Test/classes/class.assMarkSchema.php";
523  $this->mark_schema = new ASS_MarkSchema();
524  $this->mark_schema->createSimpleSchema(
525  $lng->txt("failed_short"),
526  $lng->txt("failed_official"),
527  0,
528  0,
529  $lng->txt("passed_short"),
530  $lng->txt("passed_official"),
531  50,
532  1
533  );
534 
535  $this->test_id = -1;
536  $this->author = $ilUser->fullname;
537  $this->introduction = "";
538  $this->questions = array();
539  $this->sequence_settings = TEST_FIXED_SEQUENCE;
540  $this->score_reporting = REPORT_AFTER_TEST;
541  $this->instant_verification = 0;
542  $this->answer_feedback_points = 0;
543  $this->reporting_date = "";
544  $this->nr_of_tries = 0;
545  $this->_kiosk = 0;
546  $this->use_previous_answers = 1;
547  $this->title_output = 0;
548  $this->starting_time = "";
549  $this->ending_time = "";
550  $this->processing_time = "00:00:00";
551  $this->enable_processing_time = "0";
552  $this->reset_processing_time = 0;
553  $this->ects_output = 0;
554  $this->ects_fx = NULL;
555  $this->shuffle_questions = FALSE;
556  $this->mailnottype = 0;
557  $this->exportsettings = 0;
558  $this->show_summary = 8;
559  $this->count_system = COUNT_PARTIAL_SOLUTIONS;
560  $this->mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED;
561  $this->score_cutting = SCORE_CUT_QUESTION;
562  $this->pass_scoring = SCORE_LAST_PASS;
563  $this->answer_feedback = 0;
564  $this->password = "";
565  $this->certificate_visibility = 0;
566  $this->allowedUsers = "";
567  $this->_showfinalstatement = FALSE;
568  $this->_finalstatement = "";
569  $this->_showinfo = TRUE;
570  $this->_forcejs = FALSE;
571  $this->_customStyle = "";
572  $this->allowedUsersTimeGap = "";
573  $this->anonymity = 0;
574  $this->show_cancel = 0;
575  $this->show_marker = 0;
576  $this->fixed_participants = 0;
577  $this->setShowPassDetails(TRUE);
578  $this->setShowSolutionDetails(TRUE);
579  $this->setShowSolutionAnswersOnly(FALSE);
580  $this->setShowSolutionSignature(FALSE);
581  $this->testSession = FALSE;
582  $this->testSequence = FALSE;
583  $this->mailnotification = 0;
584  $this->poolUsage = 1;
585 
586  $this->ects_grades = array(
587  "A" => 90,
588  "B" => 65,
589  "C" => 35,
590  "D" => 10,
591  "E" => 0
592  );
593 
594  $this->autosave = FALSE;
595  $this->autosave_ival = 30000;
596 
597  $this->enable_examview = false;
598  $this->show_examview_html = false;
599  $this->show_examview_pdf = false;
600  $this->enable_archiving = false;
601 
602  $this->express_mode = false;
603  $this->template_id = '';
604  $this->redirection_mode = 0;
605  $this->redirection_url = NULL;
606  $this->show_exam_id_in_test_pass_enabled = false;
607  $this->show_exam_id_in_test_results_enabled = false;
608  $this->sign_submission = false;
609  $this->char_selector_availability = 0;
610  $this->char_selector_definition = null;
611 
612  $this->testFinalBroken = false;
613 
614  $this->ilObject($a_id, $a_call_by_reference);
615  }
616 
620  function create($a_upload = false)
621  {
622  parent::create();
623 
624  // meta data will be created by
625  // import parser
626  if (!$a_upload)
627  {
628  $this->createMetaData();
629  }
630  }
631 
638  function update()
639  {
640  if (!parent::update())
641  {
642  return false;
643  }
644 
645  // put here object specific stuff
646 
647  return true;
648  }
649 
655  function read($a_force_db = false)
656  {
657  parent::read($a_force_db);
658  $this->loadFromDb();
659  }
660 
661 
668  function delete()
669  {
670  // always call parent delete function first!!
671  if (!parent::delete())
672  {
673  return false;
674  }
675 
676  // delet meta data
677  $this->deleteMetaData();
678 
679  //put here your module specific stuff
680  $this->deleteTest();
681 
682  return true;
683  }
684 
690  function deleteTest()
691  {
692  global $tree, $ilDB, $ilPluginAdmin;
693 
694  // first of all remove all test editings, because the delete statements used for this
695  // contain a subquery for active ids, that are deleted in the next steps
696  $this->removeAllTestEditings();
697 
698  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s",
699  array('integer'),
700  array($this->getTestId())
701  );
702  $active_array = array();
703  while ($row = $ilDB->fetchAssoc($result))
704  {
705  array_push($active_array, $row["active_id"]);
706  }
707 
708  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE test_fi = %s",
709  array('integer'),
710  array($this->getTestId())
711  );
712 
713  if (count($active_array))
714  {
715  foreach ($active_array as $active_id)
716  {
717  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_times WHERE active_fi = %s",
718  array('integer'),
719  array($active_id)
720  );
721 
722  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_sequence WHERE active_fi = %s",
723  array('integer'),
724  array($active_id)
725  );
726  }
727  }
728 
729  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_mark WHERE test_fi = %s",
730  array('integer'),
731  array($this->getTestId())
732  );
733 
734  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_tests WHERE test_id = %s",
735  array('integer'),
736  array($this->getTestId())
737  );
738 
739  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
740  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
741  $testQuestionSetConfigFactory->getQuestionSetConfig()->removeQuestionSetRelatedData();
742 
743  // delete export files
744  include_once "./Services/Utilities/classes/class.ilUtil.php";
745  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
746  $directory = $tst_data_dir."/tst_".$this->getId();
747  if (is_dir($directory))
748  {
749  include_once "./Services/Utilities/classes/class.ilUtil.php";
750  ilUtil::delDir($directory);
751  }
752  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
753  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
754  // remaining usages are not in text anymore -> delete them
755  // and media objects (note: delete method of ilObjMediaObject
756  // checks whether object is used in another context; if yes,
757  // the object is not deleted!)
758  foreach($mobs as $mob)
759  {
760  ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
761  if (ilObjMediaObject::_exists($mob))
762  {
763  $mob_obj =& new ilObjMediaObject($mob);
764  $mob_obj->delete();
765  }
766  }
767  }
768 
778  function initDefaultRoles()
779  {
780  global $rbacadmin;
781  return array();
782  }
783 
797  function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
798  {
799  global $tree;
800 
801  switch ($a_event)
802  {
803  case "link":
804 
805  //var_dump("<pre>",$a_params,"</pre>");
806  //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
807  //exit;
808  break;
809 
810  case "cut":
811 
812  //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
813  //exit;
814  break;
815 
816  case "copy":
817 
818  //var_dump("<pre>",$a_params,"</pre>");
819  //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
820  //exit;
821  break;
822 
823  case "paste":
824 
825  //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
826  //exit;
827  break;
828 
829  case "new":
830 
831  //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
832  //exit;
833  break;
834  }
835 
836  // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
837  if ($a_node_id==$_GET["ref_id"])
838  {
839  $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
840  $parent_type = $parent_obj->getType();
841  if ($parent_type == $this->getType())
842  {
843  $a_node_id = (int) $tree->getParentId($a_node_id);
844  }
845  }
846 
847  parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
848  }
849 
856  {
857  include_once "./Services/Utilities/classes/class.ilUtil.php";
858  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
859  ilUtil::makeDir($tst_data_dir);
860  if (!is_writable($tst_data_dir))
861  {
862  $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
863  .") not writeable.",$this->ilias->error_obj->MESSAGE);
864  }
865 
866  // create learning module directory (data_dir/lm_data/lm_<id>)
867  $tst_dir = $tst_data_dir."/tst_".$this->getId();
868  ilUtil::makeDir($tst_dir);
869  if (!@is_dir($tst_dir))
870  {
871  $this->ilias->raiseError("Creation of Test Directory failed.",$this->ilias->error_obj->MESSAGE);
872  }
873  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
874  $export_dir = $tst_dir."/export";
875  ilUtil::makeDir($export_dir);
876  if (!@is_dir($export_dir))
877  {
878  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->MESSAGE);
879  }
880  }
881 
888  {
889  include_once "./Services/Utilities/classes/class.ilUtil.php";
890  $export_dir = ilUtil::getDataDir()."/tst_data"."/tst_".$this->getId()."/export";
891  return $export_dir;
892  }
893 
900  function getExportFiles($dir)
901  {
902  // quit if import dir not available
903  if(!@is_dir($dir) || !is_writeable($dir))
904  {
905  return array();
906  }
907 
908  $files = array();
909  foreach(new DirectoryIterator($dir) as $file)
910  {
914  if($file->isDir())
915  {
916  continue;
917  }
918 
919  $files[] = $file->getBasename();
920  }
921 
922  sort($files);
923 
924  return $files;
925  }
926 
930  function _setImportDirectory($a_import_dir = null)
931  {
932  if (strlen($a_import_dir))
933  {
934  $_SESSION["tst_import_dir"] = $a_import_dir;
935  }
936  else
937  {
938  unset($_SESSION["tst_import_dir"]);
939  }
940  }
941 
949  {
950  if (strlen($_SESSION["tst_import_dir"]))
951  {
952  return $_SESSION["tst_import_dir"];
953  }
954  return null;
955  }
956 
958  {
960  }
961 
968  {
969  global $ilias;
970  include_once "./Services/Utilities/classes/class.ilUtil.php";
971  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
972  ilUtil::makeDir($tst_data_dir);
973 
974  if (!is_writable($tst_data_dir))
975  {
976  $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
977  .") not writeable.",$this->ilias->error_obj->FATAL);
978  }
979 
980  // create test directory (data_dir/tst_data/tst_import)
981  $tst_dir = $tst_data_dir."/tst_import";
982  ilUtil::makeDir($tst_dir);
983  if (!@is_dir($tst_dir))
984  {
985  $ilias->raiseError("Creation of test import directory failed.",$ilias->error_obj->FATAL);
986  }
987  return $tst_dir;
988  }
989 
997  {
998  global $ilDB;
999 
1000  $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",
1001  array('integer'),
1002  array($this->getTestId())
1003  );
1004  $hasSC = false;
1005  while ($row = $ilDB->fetchAssoc($result))
1006  {
1007  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0)
1008  {
1009  $hasSC = true;
1010  }
1011  }
1012  return $hasSC;
1013  }
1014 
1022  {
1023  global $ilDB;
1024 
1025  $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",
1026  array('integer'),
1027  array($this->getTestId())
1028  );
1029  if ($result->numRows() == 1)
1030  {
1031  $row = $ilDB->fetchAssoc($result);
1032  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0)
1033  {
1034  return TRUE;
1035  }
1036  else
1037  {
1038  return false;
1039  }
1040  }
1041  return FALSE;
1042  }
1043 
1051  {
1052  global $ilDB;
1053 
1054  if (!$this->hasSingleChoiceQuestions()) return false;
1055 
1056  $result = $ilDB->queryF("
1057  SELECT DISTINCT(qpl_qst_sc.shuffle) foundshuffles
1058  FROM qpl_questions,
1059  qpl_qst_sc,
1060  tst_test_result,
1061  qpl_qst_type,
1062  tst_active
1063  WHERE tst_test_result.question_fi = qpl_questions.question_id
1064  AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
1065  AND tst_test_result.active_fi = tst_active.active_id
1066  AND qpl_questions.question_id = qpl_qst_sc.question_fi
1067  AND tst_active.test_fi = %s
1068  AND qpl_qst_type.type_tag = %s
1069  ",
1070  array('integer', 'text'),
1071  array($this->getTestId(), 'assSingleChoice')
1072  );
1073  if ($result->numRows() == 1)
1074  {
1075  $row = $ilDB->fetchAssoc($result);
1076  return ($row['foundshuffles'] == 0);
1077  }
1078  return FALSE;
1079  }
1080 
1087  final public function isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
1088  {
1089  if( !count($this->mark_schema->mark_steps) )
1090  {
1091  return false;
1092  }
1093 
1094  if( !$testQuestionSetConfig->isQuestionSetConfigured() )
1095  {
1096  return false;
1097  }
1098 
1099  return true;
1100  }
1101 
1108  function _isComplete($obj_id)
1109  {
1110  global $tree, $ilDB, $ilPluginAdmin;
1111 
1112  $test = new ilObjTest($obj_id, false);
1113  $test->loadFromDb();
1114 
1115  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1116  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $test);
1117 
1118  return $test->isComplete( $testQuestionSetConfigFactory->getQuestionSetConfig() );
1119  }
1120 
1126  function saveECTSStatus($ects_output = 0, $fx_support = "", $ects_a = 90, $ects_b = 65, $ects_c = 35, $ects_d = 10, $ects_e = 0)
1127  {
1128  global $ilDB;
1129  if ($this->test_id > 0)
1130  {
1131  $fx_support = preg_replace("/,/", ".", $fx_support);
1132  if (preg_match("/\d+/", $fx_support))
1133  {
1134  $fx_support = $fx_support;
1135  }
1136  else
1137  {
1138  $fx_support = NULL;
1139  }
1140  $affectedRows = $ilDB->manipulateF("UPDATE tst_tests SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s WHERE test_id = %s",
1141  array('text','float','float','float','float','float','float','integer'),
1142  array($ects_output, $ects_a, $ects_b, $ects_c, $ects_d, $ects_e, $fx_support, $this->getTestId())
1143  );
1144  $this->ects_output = $ects_output;
1145  $this->ects_fx = $fx_support;
1146  }
1147  }
1148 
1154  function saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
1155  {
1156  global $ilDB;
1157 
1158  $complete = 0;
1159  if ($this->isComplete($testQuestionSetConfig))
1160  {
1161  $complete = 1;
1162  }
1163  if ($this->test_id > 0)
1164  {
1165  $affectedRows = $ilDB->manipulateF("UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1166  array('text','integer'),
1167  array($complete, $this->test_id)
1168  );
1169  }
1170  }
1171 
1177  function getAllRTEContent()
1178  {
1179  $result = array();
1180  array_push($result, $this->getIntroduction());
1181  array_push($result, $this->getFinalStatement());
1182  return $result;
1183  }
1184 
1191  {
1192  include_once("./Services/RTE/classes/class.ilRTE.php");
1193  $completecontent = "";
1194  foreach ($this->getAllRTEContent() as $content)
1195  {
1196  $completecontent .= $content;
1197  }
1198  ilRTE::_cleanupMediaObjectUsage($completecontent, $this->getType() . ":html",
1199  $this->getId());
1200  }
1201 
1207  public function saveToDb($properties_only = FALSE)
1208  {
1209  global $tree, $ilDB, $ilPluginAdmin;
1210 
1211  // moved online_status to ilObjectActivation (see below)
1212 
1213  // cleanup RTE images
1214  $this->cleanupMediaobjectUsage();
1215 
1216  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
1217  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
1218  $testQuestionSetConfig = $testQuestionSetConfigFactory->getQuestionSetConfig();
1219 
1220  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1221  if ($this->test_id == -1)
1222  {
1223  // Create new dataset
1224  $next_id = $ilDB->nextId('tst_tests');
1225 
1226  $ilDB->insert('tst_tests', array(
1227  'test_id' => array('integer', $next_id),
1228  'obj_fi' => array('integer', $this->getId()),
1229  'author' => array('text', $this->getAuthor()),
1230  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1231  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1232  'showinfo' => array('integer', $this->getShowInfo()),
1233  'forcejs' => array('integer', $this->getForceJS()),
1234  'customstyle' => array('text', $this->getCustomStyle()),
1235  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1236  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1237  'score_reporting' => array('integer', $this->getScoreReporting()),
1238  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1239  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1240  'answer_feedback' => array('text', $this->getAnswerFeedback()),
1241  'anonymity' => array('text', $this->getAnonymity()),
1242  'show_cancel' => array('text', $this->getShowCancel()),
1243  'show_marker' => array('integer', $this->getShowMarker()),
1244  'fixed_participants' => array('text', $this->getFixedParticipants()),
1245  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1246  'kiosk' => array('integer', $this->getKiosk()),
1247  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1248  'title_output' => array('text', $this->getTitleOutput()),
1249  'processing_time' => array('text', $this->getProcessingTime()),
1250  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1251  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1252  'reporting_date' => array('text', $this->getReportingDate()),
1253  'starting_time' => array('text', $this->getStartingTime()),
1254  'ending_time' => array('text', $this->getEndingTime()),
1255  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1256  'ects_output' => array('text', $this->getECTSOutput()),
1257  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : NULL),
1258  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : NULL),
1259  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : NULL),
1260  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : NULL),
1261  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : NULL),
1262  'ects_fx' => array('float', $this->getECTSFX()),
1263  'count_system' => array('text', $this->getCountSystem()),
1264  'mc_scoring' => array('text', $this->getMCScoring()),
1265  'score_cutting' => array('text', $this->getScoreCutting()),
1266  'pass_scoring' => array('text', $this->getPassScoring()),
1267  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1268  'results_presentation' => array('integer', $this->getResultsPresentation()),
1269  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1270  'password' => array('text', $this->getPassword()),
1271  'allowedusers' => array('integer', $this->getAllowedUsers()),
1272  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1273  'mailnottype' => array('integer', $this->getMailNotificationType()),
1274  'exportsettings' => array('integer', $this->getExportSettings()),
1275  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1276  'mailnotification' => array('integer', $this->getMailNotification()),
1277  'created' => array('integer', time()),
1278  'tstamp' => array('integer', time()),
1279  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1280  'template_id' => array('integer', $this->getTemplate()),
1281  'pool_usage' => array('integer', $this->getPoolUsage()),
1282  'print_bs_with_res' => array('integer', (int)$this->isBestSolutionPrintedWithResult()),
1283  'obligations_enabled' => array('integer', (int)$this->areObligationsEnabled()),
1284  'offer_question_hints' => array('integer', (int)$this->isOfferingQuestionHintsEnabled()),
1285  'highscore_enabled' => array('integer', (int)$this->getHighscoreEnabled()),
1286  'highscore_anon' => array('integer', (int)$this->getHighscoreAnon()),
1287  'highscore_achieved_ts' => array('integer', (int)$this->getHighscoreAchievedTS()),
1288  'highscore_score' => array('integer', (int)$this->getHighscoreScore()),
1289  'highscore_percentage' => array('integer', (int)$this->getHighscorePercentage()),
1290  'highscore_hints' => array('integer', (int)$this->getHighscoreHints()),
1291  'highscore_wtime' => array('integer', (int)$this->getHighscoreWTime()),
1292  'highscore_own_table' => array('integer', (int)$this->getHighscoreOwnTable()),
1293  'highscore_top_table' => array('integer', (int)$this->getHighscoreTopTable()),
1294  'highscore_top_num' => array('integer', (int)$this->getHighscoreTopNum()),
1295  'online_status' => array('integer', (int)$this->isOnline()),
1296  'specific_feedback' => array('integer', (int)$this->getSpecificAnswerFeedback()),
1297  'autosave' => array('integer', (int)$this->getAutosave()),
1298  'autosave_ival' => array('integer', (int)$this->getAutosaveIval()),
1299  'pass_deletion_allowed' => array('integer', (int)$this->isPassDeletionAllowed()),
1300  'enable_examview' => array('integer', (int)$this->getEnableExamview()),
1301  'show_examview_html' => array('integer', (int)$this->getShowExamviewHtml()),
1302  'show_examview_pdf' => array('integer', (int)$this->getShowExamviewPdf()),
1303  'redirection_mode' => array('integer', (int)$this->getRedirectionMode()),
1304  'redirection_url' => array('text', (string)$this->getRedirectionUrl()),
1305  'enable_archiving' => array('integer', (int)$this->getEnableArchiving()),
1306  'examid_in_test_pass' => array('integer', (int)$this->isShowExamIdInTestPassEnabled()),
1307  'examid_in_test_res' => array('integer', (int)$this->isShowExamIdInTestResultsEnabled()),
1308  'sign_submission' => array('integer', (int)$this->getSignSubmission()),
1309  'question_set_type' => array('text', $this->getQuestionSetType()),
1310  'char_selector_availability' => array('integer', (int)$this->getCharSelectorAvailability()),
1311  'char_selector_definition' => array('text', (string)$this->getCharSelectorDefinition()),
1312  'broken' => array('integer', (int)$this->isTestFinalBroken())
1313  ));
1314 
1315  $this->test_id = $next_id;
1316 
1318  {
1319  $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1320  }
1321  }
1322  else
1323  {
1324  // Modify existing dataset
1325  $oldrow = array();
1327  {
1328  $result = $ilDB->queryF("SELECT * FROM tst_tests WHERE test_id = %s",
1329  array('integer'),
1330  array($this->test_id)
1331  );
1332  if ($result->numRows() == 1)
1333  {
1334  $oldrow = $ilDB->fetchAssoc($result);
1335  }
1336  }
1337 
1338  $ilDB->update('tst_tests',
1339  array(
1340  'author' => array('text', $this->getAuthor()),
1341  'introduction' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)),
1342  'finalstatement' => array('text', ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1343  'showinfo' => array('integer', $this->getShowInfo()),
1344  'forcejs' => array('integer', $this->getForceJS()),
1345  'customstyle' => array('text', $this->getCustomStyle()),
1346  'showfinalstatement' => array('integer', $this->getShowFinalStatement()),
1347  'sequence_settings' => array('integer', $this->getSequenceSettings()),
1348  'score_reporting' => array('integer', $this->getScoreReporting()),
1349  'instant_verification' => array('text', $this->getInstantFeedbackSolution()),
1350  'answer_feedback_points' => array('text', $this->getAnswerFeedbackPoints()),
1351  'answer_feedback' => array('text', $this->getGenericAnswerFeedback()),
1352  'anonymity' => array('text', $this->getAnonymity()),
1353  'show_cancel' => array('text', $this->getShowCancel()),
1354  'show_marker' => array('integer', $this->getShowMarker()),
1355  'fixed_participants' => array('text', $this->getFixedParticipants()),
1356  'nr_of_tries' => array('integer', $this->getNrOfTries()),
1357  'kiosk' => array('integer', $this->getKiosk()),
1358  'use_previous_answers' => array('text', $this->getUsePreviousAnswers()),
1359  'title_output' => array('text', $this->getTitleOutput()),
1360  'processing_time' => array('text', $this->getProcessingTime()),
1361  'enable_processing_time' => array('text', $this->getEnableProcessingTime()),
1362  'reset_processing_time' => array('integer', $this->getResetProcessingTime()),
1363  'reporting_date' => array('text', $this->getReportingDate()),
1364  'starting_time' => array('text', $this->getStartingTime()),
1365  'ending_time' => array('text', $this->getEndingTime()),
1366  'complete' => array('text', $this->isComplete($testQuestionSetConfig)),
1367  'ects_output' => array('text', $this->getECTSOutput()),
1368  'ects_a' => array('float', strlen($this->ects_grades["A"]) ? $this->ects_grades["A"] : NULL),
1369  'ects_b' => array('float', strlen($this->ects_grades["B"]) ? $this->ects_grades["B"] : NULL),
1370  'ects_c' => array('float', strlen($this->ects_grades["C"]) ? $this->ects_grades["C"] : NULL),
1371  'ects_d' => array('float', strlen($this->ects_grades["D"]) ? $this->ects_grades["D"] : NULL),
1372  'ects_e' => array('float', strlen($this->ects_grades["E"]) ? $this->ects_grades["E"] : NULL),
1373  'ects_fx' => array('float', $this->getECTSFX()),
1374  'count_system' => array('text', $this->getCountSystem()),
1375  'mc_scoring' => array('text', $this->getMCScoring()),
1376  'score_cutting' => array('text', $this->getScoreCutting()),
1377  'pass_scoring' => array('text', $this->getPassScoring()),
1378  'shuffle_questions' => array('text', $this->getShuffleQuestions()),
1379  'results_presentation' => array('integer', $this->getResultsPresentation()),
1380  'show_summary' => array('integer', $this->getListOfQuestionsSettings()),
1381  'password' => array('text', $this->getPassword()),
1382  'allowedusers' => array('integer', $this->getAllowedUsers()),
1383  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1384  'mailnottype' => array('integer', $this->getMailNotificationType()),
1385  'exportsettings' => array('integer', $this->getExportSettings()),
1386  'print_bs_with_res' => array('integer', (int)$this->isBestSolutionPrintedWithResult()),
1387  'alloweduserstimegap' => array('integer', $this->getAllowedUsersTimeGap()),
1388  'certificate_visibility' => array('text', $this->getCertificateVisibility()),
1389  'mailnotification' => array('integer', $this->getMailNotification()),
1390  'tstamp' => array('integer', time()),
1391  'enabled_view_mode' => array('text', $this->getEnabledViewMode()),
1392  'template_id' => array('integer', $this->getTemplate()),
1393  'pool_usage' => array('integer', $this->getPoolUsage()),
1394  'print_bs_with_res' => array('integer', (int)$this->isBestSolutionPrintedWithResult()),
1395  'obligations_enabled' => array('integer', (int)$this->areObligationsEnabled()),
1396  'offer_question_hints' => array('integer', (int)$this->isOfferingQuestionHintsEnabled()),
1397  'highscore_enabled' => array('integer', (int)$this->getHighscoreEnabled()),
1398  'highscore_anon' => array('integer', (int)$this->getHighscoreAnon()),
1399  'highscore_achieved_ts' => array('integer', (int)$this->getHighscoreAchievedTS()),
1400  'highscore_score' => array('integer', (int)$this->getHighscoreScore()),
1401  'highscore_percentage' => array('integer', (int)$this->getHighscorePercentage()),
1402  'highscore_hints' => array('integer', (int)$this->getHighscoreHints()),
1403  'highscore_wtime' => array('integer', (int)$this->getHighscoreWTime()),
1404  'highscore_own_table' => array('integer', (int)$this->getHighscoreOwnTable()),
1405  'highscore_top_table' => array('integer', (int)$this->getHighscoreTopTable()),
1406  'highscore_top_num' => array('integer', (int)$this->getHighscoreTopNum()),
1407  'online_status' => array('integer', (int)$this->isOnline()),
1408  'specific_feedback' => array('integer', (int)$this->getSpecificAnswerFeedback()),
1409  'autosave' => array('integer', (int)$this->getAutosave()),
1410  'autosave_ival' => array('integer', (int)$this->getAutosaveIval()),
1411  'pass_deletion_allowed' => array('integer', (int)$this->isPassDeletionAllowed()),
1412  'enable_examview' => array('integer', (int)$this->getEnableExamview()),
1413  'show_examview_html' => array('integer', (int)$this->getShowExamviewHtml()),
1414  'show_examview_pdf' => array('integer', (int)$this->getShowExamviewPdf()),
1415  'redirection_mode' => array('integer', (int)$this->getRedirectionMode()),
1416  'redirection_url' => array('text', (string)$this->getRedirectionUrl()),
1417  'enable_archiving' => array('integer', (int)$this->getEnableArchiving()),
1418  'examid_in_test_pass' => array('integer', (int)$this->isShowExamIdInTestPassEnabled()),
1419  'examid_in_test_res' => array('integer', (int)$this->isShowExamIdInTestResultsEnabled()),
1420  'sign_submission' => array('integer', (int)$this->getSignSubmission()),
1421  'question_set_type' => array('text', $this->getQuestionSetType()),
1422  'char_selector_availability' => array('integer', (int)$this->getCharSelectorAvailability()),
1423  'char_selector_definition' => array('text', (string)$this->getCharSelectorDefinition()),
1424  'broken' => array('integer', (int)$this->isTestFinalBroken())
1425  ),
1426  array(
1427  'test_id' => array('integer', (int)$this->getTestId())
1428  )
1429  );
1430 
1431  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1433  {
1434  $logresult = $ilDB->queryF("SELECT * FROM tst_tests WHERE test_id = %s",
1435  array('integer'),
1436  array($this->getTestId())
1437  );
1438  $newrow = array();
1439  if ($logresult->numRows() == 1)
1440  {
1441  $newrow = $ilDB->fetchAssoc($logresult);
1442  }
1443  $changed_fields = array();
1444  foreach ($oldrow as $key => $value)
1445  {
1446  if (strcmp($oldrow[$key], $newrow[$key]) != 0)
1447  {
1448  array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1449  }
1450  }
1451  $changes = join($changed_fields, ", ");
1452  if (count($changed_fields) > 0)
1453  {
1454  $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [".$changes."]");
1455  }
1456  }
1457  if ($this->evalTotalPersons() > 0)
1458  {
1459  // reset the finished status of participants if the nr of test passes did change
1460  if ($this->getNrOfTries() > 0)
1461  {
1462  // set all unfinished tests with nr of passes >= allowed passes finished
1463  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
1464  array('integer', 'integer', 'integer'),
1465  array($this->getTestId(), $this->getNrOfTries(), 0)
1466  );
1467  while ($row = $ilDB->fetchAssoc($aresult))
1468  {
1469  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1470  array('integer', 'timestamp', 'integer'),
1471  array(1, date('Y-m-d H:i:s'), $row["active_id"])
1472  );
1473  }
1474 
1475  // set all finished tests with nr of passes < allowed passes not finished
1476  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
1477  array('integer', 'integer', 'integer'),
1478  array($this->getTestId(), $this->getNrOfTries()-1, 1)
1479  );
1480  while ($row = $ilDB->fetchAssoc($aresult))
1481  {
1482  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1483  array('integer', 'timestamp', 'integer'),
1484  array(0, NULL, $row["active_id"])
1485  );
1486  }
1487  }
1488  else
1489  {
1490  // set all finished tests with nr of passes >= allowed passes not finished
1491  $aresult = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
1492  array('integer', 'integer'),
1493  array($this->getTestId(), 1)
1494  );
1495  while ($row = $ilDB->fetchAssoc($aresult))
1496  {
1497  $ilDB->manipulateF("UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
1498  array('integer', 'timestamp', 'integer'),
1499  array(0, NULL, $row["active_id"])
1500  );
1501  }
1502  }
1503  }
1504  }
1505 
1506  // moved activation to ilObjectActivation
1507  if($this->ref_id)
1508  {
1509  include_once "./Services/Object/classes/class.ilObjectActivation.php";
1510  ilObjectActivation::getItem($this->ref_id);
1511 
1512  $item = new ilObjectActivation;
1513  if(!$this->isActivationLimited())
1514  {
1516  }
1517  else
1518  {
1519  $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
1520  $item->setTimingStart($this->getActivationStartingTime());
1521  $item->setTimingEnd($this->getActivationEndingTime());
1522  $item->toggleVisible($this->getActivationVisibility());
1523  }
1524 
1525  $item->update($this->ref_id);
1526  }
1527 
1528  if (!$properties_only)
1529  {
1530  if (PEAR::isError($result))
1531  {
1532  global $ilias;
1533  $ilias->raiseError($result->getMessage());
1534  }
1535  else
1536  {
1538  {
1539  $this->saveQuestionsToDb();
1540  }
1541  $this->mark_schema->saveToDb($this->test_id);
1542  }
1543  }
1544  }
1545 
1553  {
1554  global $ilDB;
1555 
1556  $oldquestions = array();
1557  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1559  {
1560  $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1561  array('integer'),
1562  array($this->getTestId())
1563  );
1564  if ($result->numRows() > 0)
1565  {
1566  while ($row = $ilDB->fetchAssoc($result))
1567  {
1568  array_push($oldquestions, $row["question_fi"]);
1569  }
1570  }
1571  }
1572  // workaround for lost obligations
1573  // this method is called if a question is removed
1574  $currentQuestionsObligationsQuery = 'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
1575  $rset = $ilDB->queryF($currentQuestionsObligationsQuery, array('integer'), array($this->getTestId()));
1576  while ($row = $ilDB->fetchAssoc($rset)) {
1577  $obligatoryQuestionState[$row['question_fi']] = $row['obligatory'];
1578  }
1579  // delete existing category relations
1580  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_question WHERE test_fi = %s",
1581  array('integer'),
1582  array($this->getTestId())
1583  );
1584  // create new category relations
1585  foreach ($this->questions as $key => $value)
1586  {
1587  // workaround for import witout obligations information
1588  if( !isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value]) )
1589  {
1590  $obligatoryQuestionState[$value] = 0;
1591  }
1592 
1593  // insert question
1594  $next_id = $ilDB->nextId('tst_test_question');
1595  $ilDB->insert('tst_test_question', array(
1596  'test_question_id' => array('integer', $next_id),
1597  'test_fi' => array('integer', $this->getTestId()),
1598  'question_fi' => array('integer', $value),
1599  'sequence' => array('integer', $key),
1600  'obligatory' => array('integer', $obligatoryQuestionState[$value]),
1601  'tstamp' => array('integer', time())
1602  ));
1603  }
1604  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1606  {
1607  $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1608  array('integer'),
1609  array($this->getTestId())
1610  );
1611  $newquestions = array();
1612  if ($result->numRows() > 0)
1613  {
1614  while ($row = $ilDB->fetchAssoc($result))
1615  {
1616  array_push($newquestions, $row["question_fi"]);
1617  }
1618  }
1619  foreach ($oldquestions as $index => $question_id)
1620  {
1621  if (strcmp($newquestions[$index], $question_id) != 0)
1622  {
1623  $pos = array_search($question_id, $newquestions);
1624  if ($pos === FALSE)
1625  {
1626  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1627  }
1628  else
1629  {
1630  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1) . " => " . ($pos+1), $question_id);
1631  }
1632  }
1633  }
1634  foreach ($newquestions as $index => $question_id)
1635  {
1636  if (array_search($question_id, $oldquestions) === FALSE)
1637  {
1638  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1), $question_id);
1639  }
1640  }
1641  }
1642  }
1643 
1649  protected function isNewRandomTest()
1650  {
1651  global $ilDB;
1652  $result = $ilDB->queryF('SELECT copy_id FROM tst_rnd_cpy WHERE tst_fi = %s',
1653  array('integer'),
1654  array($this->getTestId())
1655  );
1656  return $result->numRows() > 0;
1657  }
1658 
1671  function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = NULL)
1672  {
1673  global $rbacsystem;
1674  global $ilDB;
1675 
1676  // retrieve object id instead of ref id if necessary
1677  if (($questionpool != 0) && (!$use_obj_id)) $questionpool = ilObject::_lookupObjId($questionpool);
1678 
1679  // get original ids of all existing questions in the test
1680  $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",
1681  array("integer"),
1682  array($this->getTestId())
1683  );
1684  $original_ids = array();
1685  $paramtypes = array();
1686  $paramvalues = array();
1687  while ($row = $ilDB->fetchAssoc($result))
1688  {
1689  array_push($original_ids, $row['original_id']);
1690  }
1691 
1692  $available = "";
1693  // get a list of all available questionpools
1694  if (($questionpool == 0) && (!is_array($qpls)))
1695  {
1696  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1697  $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())));
1698  if (count($available_pools))
1699  {
1700  $available = " AND " . $ilDB->in('obj_fi', $available_pools, false, 'integer');
1701  }
1702  else
1703  {
1704  return array();
1705  }
1706  }
1707 
1708  $constraint_qpls = "";
1709  $result_array = array();
1710  if ($questionpool == 0)
1711  {
1712  if (is_array($qpls))
1713  {
1714  if (count($qpls) > 0)
1715  {
1716  $constraint_qpls = " AND " . $ilDB->in('obj_fi', $qpls, false, 'integer');
1717  }
1718  }
1719  }
1720 
1721  $original_clause = "";
1722  if (count($original_ids))
1723  {
1724  $original_clause = " AND " . $ilDB->in('question_id', $original_ids, true, 'integer');
1725  }
1726 
1727  if ($questionpool == 0)
1728  {
1729  $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",
1730  array('integer', 'text'),
1731  array(0, "1")
1732  );
1733  }
1734  else
1735  {
1736  $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",
1737  array('integer','integer', 'text'),
1738  array($questionpool, 0, "1")
1739  );
1740  }
1741  $found_ids = array();
1742  while ($row = $ilDB->fetchAssoc($result))
1743  {
1744  array_push($found_ids, $row['question_id']);
1745  }
1746  $nr_of_questions = ($nr_of_questions > count($found_ids)) ? count($found_ids) : $nr_of_questions;
1747  if ($nr_of_questions == 0) return array();
1748  $rand_keys = array_rand($found_ids, $nr_of_questions);
1749  $result = array();
1750  if (is_array($rand_keys))
1751  {
1752  foreach ($rand_keys as $key)
1753  {
1754  $result[$found_ids[$key]] = $found_ids[$key];
1755  }
1756  }
1757  else
1758  {
1759  $result[$found_ids[$rand_keys]] = $found_ids[$rand_keys];
1760  }
1761  return $result;
1762  }
1763 
1771  function getNrOfResultsForPass($active_id, $pass)
1772  {
1773  global $ilDB;
1774 
1775  $result = $ilDB->queryF("SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1776  array('integer','integer'),
1777  array($active_id, $pass)
1778  );
1779  return $result->numRows();
1780  }
1781 
1792  function hasRandomQuestionsForPass($active_id, $pass)
1793  {
1794  global $ilDB;
1795  $result = $ilDB->queryF("SELECT test_random_question_id FROM tst_test_rnd_qst WHERE active_fi = %s AND pass = %s",
1796  array('integer','integer'),
1797  array($active_id, $pass)
1798  );
1799  return ($result->numRows() > 0) ? true : false;
1800  }
1801 
1805  public function loadFromDb()
1806  {
1807  global $ilDB;
1808 
1809  $result = $ilDB->queryF("SELECT * FROM tst_tests WHERE obj_fi = %s",
1810  array('integer'),
1811  array($this->getId())
1812  );
1813  if ($result->numRows() == 1)
1814  {
1815  $data = $ilDB->fetchObject($result);
1816  $this->setTestId($data->test_id);
1817  if (strlen($this->getAuthor()) == 0)
1818  {
1819  $this->saveAuthorToMetadata($data->author);
1820  }
1821  $this->setAuthor($data->author);
1822  include_once("./Services/RTE/classes/class.ilRTE.php");
1823  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc($data->introduction, 1));
1824  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc($data->finalstatement, 1));
1825  $this->setShowInfo($data->showinfo);
1826  $this->setForceJS($data->forcejs);
1827  $this->setCustomStyle($data->customstyle);
1828  $this->setShowFinalStatement($data->showfinalstatement);
1829  $this->setSequenceSettings($data->sequence_settings);
1830  $this->setScoreReporting($data->score_reporting);
1831  $this->setInstantFeedbackSolution($data->instant_verification);
1832  $this->setAnswerFeedbackPoints($data->answer_feedback_points);
1833  $this->setAnswerFeedback($data->answer_feedback);
1834  $this->setAnonymity($data->anonymity);
1835  $this->setShowCancel($data->show_cancel);
1836  $this->setShowMarker($data->show_marker);
1837  $this->setFixedParticipants($data->fixed_participants);
1838  $this->setNrOfTries($data->nr_of_tries);
1839  $this->setKiosk($data->kiosk);
1840  $this->setUsePreviousAnswers($data->use_previous_answers);
1841  $this->setRedirectionMode($data->redirection_mode);
1842  $this->setRedirectionUrl($data->redirection_url);
1843  $this->setTitleOutput($data->title_output);
1844  $this->setProcessingTime($data->processing_time);
1845  $this->setEnableProcessingTime($data->enable_processing_time);
1846  $this->setResetProcessingTime($data->reset_processing_time);
1847  $this->setReportingDate($data->reporting_date);
1848  $this->setShuffleQuestions($data->shuffle_questions);
1849  $this->setResultsPresentation($data->results_presentation);
1850  $this->setStartingTime($data->starting_time);
1851  $this->setEndingTime($data->ending_time);
1852  $this->setListOfQuestionsSettings($data->show_summary);
1853  $this->setECTSOutput($data->ects_output);
1854  $this->setECTSGrades(
1855  array(
1856  "A" => $data->ects_a,
1857  "B" => $data->ects_b,
1858  "C" => $data->ects_c,
1859  "D" => $data->ects_d,
1860  "E" => $data->ects_e
1861  )
1862  );
1863  $this->setECTSFX($data->ects_fx);
1864  $this->mark_schema->flush();
1865  $this->mark_schema->loadFromDb($this->getTestId());
1866  $this->setCountSystem($data->count_system);
1867  $this->setMCScoring($data->mc_scoring);
1868  $this->setMailNotification($data->mailnotification);
1869  $this->setMailNotificationType($data->mailnottype);
1870  $this->setExportSettings($data->exportsettings);
1871  $this->setScoreCutting($data->score_cutting);
1872  $this->setPassword($data->password);
1873  $this->setAllowedUsers($data->allowedusers);
1874  $this->setAllowedUsersTimeGap($data->alloweduserstimegap);
1875  $this->setPassScoring($data->pass_scoring);
1876  $this->setObligationsEnabled($data->obligations_enabled);
1877  $this->setOfferingQuestionHintsEnabled($data->offer_question_hints);
1878  $this->setCertificateVisibility($data->certificate_visibility);
1879  $this->setEnabledViewMode($data->enabled_view_mode);
1880  $this->setTemplate($data->template_id);
1881  $this->setPoolUsage($data->pool_usage);
1882  $this->setPrintBestSolutionWithResult((bool) $data->print_bs_with_res);
1883  $this->setHighscoreEnabled((bool) $data->highscore_enabled);
1884  $this->setHighscoreAnon((bool) $data->highscore_anon);
1885  $this->setHighscoreAchievedTS((bool) $data->highscore_achieved_ts);
1886  $this->setHighscoreScore((bool) $data->highscore_score);
1887  $this->setHighscorePercentage((bool) $data->highscore_percentage);
1888  $this->setHighscoreHints((bool) $data->highscore_hints);
1889  $this->setHighscoreWTime((bool) $data->highscore_wtime);
1890  $this->setHighscoreOwnTable((bool) $data->highscore_own_table);
1891  $this->setHighscoreTopTable((bool) $data->highscore_top_table);
1892  $this->setHighscoreTopNum((int) $data->highscore_top_num);
1893  $this->setOnline((bool) $data->online_status);
1894  $this->setSpecificAnswerFeedback((int) $data->specific_feedback);
1895  $this->setAutosave((bool)$data->autosave);
1896  $this->setAutosaveIval((int)$data->autosave_ival);
1897  $this->setPassDeletionAllowed($data->pass_deletion_allowed);
1898  $this->setEnableExamview((bool)$data->enable_examview);
1899  $this->setShowExamviewHtml((bool)$data->show_examview_html);
1900  $this->setShowExamviewPdf((bool)$data->show_examview_pdf);
1901  $this->setEnableArchiving((bool)$data->enable_archiving);
1902  $this->setShowExamIdInTestPassEnabled( (bool)$data->examid_in_test_pass);
1903  $this->setShowExamIdInTestResultsEnabled( (bool)$data->examid_in_test_res);
1904  $this->setSignSubmission( (bool)$data->sign_submission );
1905  $this->setQuestionSetType($data->question_set_type);
1906  $this->setCharSelectorAvailability((int)$data->char_selector_availability);
1907  $this->setCharSelectorDefinition($data->char_selector_definition);
1908  $this->setTestFinalBroken((bool)$data->broken);
1909  $this->loadQuestions();
1910  }
1911 
1912  // moved activation to ilObjectActivation
1913  if($this->ref_id)
1914  {
1915  include_once "./Services/Object/classes/class.ilObjectActivation.php";
1916  $activation = ilObjectActivation::getItem($this->ref_id);
1917  switch($activation["timing_type"])
1918  {
1920  $this->setActivationLimited(true);
1921  $this->setActivationStartingTime($activation["timing_start"]);
1922  $this->setActivationEndingTime($activation["timing_end"]);
1923  $this->setActivationVisibility($activation["visible"]);
1924  break;
1925 
1926  default:
1927  $this->setActivationLimited(false);
1928  break;
1929  }
1930  }
1931  }
1932 
1939 function loadQuestions($active_id = "", $pass = NULL)
1940 {
1941  global $ilUser;
1942  global $ilDB;
1943 
1944  $this->questions = array();
1945  if (strcmp($active_id, "") == 0)
1946  {
1947  $active_id = $this->getActiveIdOfUser($ilUser->getId());
1948  }
1949  if ($this->isRandomTest())
1950  {
1951  if (is_null($pass))
1952  {
1953  $pass = $this->_getPass($active_id);
1954  }
1955  $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",
1956  array('integer', 'integer'),
1957  array($active_id, $pass)
1958  );
1959  // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
1960  // is only one test pass (pass = 0) in tst_test_rnd_qst while with ILIAS 3.8 there are questions for every test pass.
1961  // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
1962  // no questions are present for a newer pass.
1963  if ($result->numRows() == 0)
1964  {
1965  $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",
1966  array('integer'),
1967  array($active_id)
1968  );
1969  }
1970  }
1971  else
1972  {
1973  $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",
1974  array('integer'),
1975  array($this->test_id)
1976  );
1977  }
1978  $index = 1;
1979  while ($data = $ilDB->fetchAssoc($result))
1980  {
1981  $this->questions[$index++] = $data["question_fi"];
1982  }
1983 }
1984 
1993  {
1994  $this->introduction = $introduction;
1995  }
1996 
2004  public function setFinalStatement($a_statement = "")
2005  {
2006  $this->_finalstatement = $a_statement;
2007  }
2008 
2016  public function setShowInfo($a_info = 1)
2017  {
2018  $this->_showinfo = ($a_info) ? 1 : 0;
2019  }
2020 
2028  public function setForceJS($a_js = 1)
2029  {
2030  $this->_forcejs = ($a_js) ? 1 : 0;
2031  }
2032 
2040  public function setCustomStyle($a_customStyle = NULL)
2041  {
2042  $this->_customStyle = $a_customStyle;
2043  }
2044 
2052  public function getCustomStyle()
2053  {
2054  return (strlen($this->_customStyle)) ? $this->_customStyle : NULL;
2055  }
2056 
2064  public function getCustomStyles()
2065  {
2066  $css_path = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2067  $css_path = str_replace("ta.css", "customstyles", $css_path) . "/";
2068  $customstyles = array();
2069  if (is_dir($css_path))
2070  {
2071  $results = array();
2072  include_once "./Services/Utilities/classes/class.ilFileUtils.php";
2074  if (is_array($results["file"]))
2075  {
2076  foreach ($results["file"] as $filename)
2077  {
2078  if (strpos($filename, ".css"))
2079  {
2080  array_push($customstyles, $filename);
2081  }
2082  }
2083  }
2084  }
2085  return $customstyles;
2086  }
2087 
2095  public function getTestStyleLocation($mode = "output")
2096  {
2097  if (strlen($this->getCustomStyle()))
2098  {
2099  $default = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2100  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $default);
2101  if (file_exists($custom))
2102  {
2103  $custom = ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2104  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $custom);
2105  return $custom;
2106  }
2107  else
2108  {
2109  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2110  }
2111  }
2112  else
2113  {
2114  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2115  }
2116  }
2117 
2125  public function setShowFinalStatement($show = 0)
2126  {
2127  $this->_showfinalstatement = ($show) ? 1 : 0;
2128  }
2129 
2136  public function getIntroduction()
2137  {
2138  return (strlen($this->introduction)) ? $this->introduction : NULL;
2139  }
2140 
2147  public function getFinalStatement()
2148  {
2149  return (strlen($this->_finalstatement)) ? $this->_finalstatement : NULL;
2150  }
2151 
2159  public function getShowInfo()
2160  {
2161  return ($this->_showinfo) ? 1 : 0;
2162  }
2163 
2171  public function getForceJS()
2172  {
2173  return ($this->_forcejs) ? 1 : 0;
2174  }
2175 
2183  public function getShowFinalStatement()
2184  {
2185  return ($this->_showfinalstatement) ? 1 : 0;
2186  }
2187 
2195  function getTestId()
2196  {
2197  return $this->test_id;
2198  }
2199 
2207  function getECTSOutput()
2208  {
2209  return ($this->ects_output) ? 1 : 0;
2210  }
2211 
2219  function setECTSOutput($a_ects_output)
2220  {
2221  $this->ects_output = $a_ects_output ? 1 : 0;
2222  }
2223 
2231  function getECTSFX()
2232  {
2233  return (strlen($this->ects_fx)) ? $this->ects_fx : NULL;
2234  }
2235 
2243  function setECTSFX($a_ects_fx)
2244  {
2245  $this->ects_fx = $a_ects_fx;
2246  }
2247 
2255  function &getECTSGrades()
2256  {
2257  return $this->ects_grades;
2258  }
2259 
2267  function setECTSGrades($a_ects_grades)
2268  {
2269  if (is_array($a_ects_grades))
2270  {
2271  $this->ects_grades = $a_ects_grades;
2272  }
2273  }
2274 
2283  {
2284  $this->sequence_settings = $sequence_settings;
2285  }
2286 
2295  {
2296  $this->score_reporting = $score_reporting;
2297  }
2298 
2306  function setInstantFeedbackSolution($instant_feedback = 0)
2307  {
2308  switch ($instant_feedback)
2309  {
2310  case 1:
2311  $this->instant_verification = 1;
2312  break;
2313  default:
2314  $this->instant_verification = 0;
2315  break;
2316  }
2317  }
2318 
2327 {
2328  switch ($answer_feedback)
2329  {
2330  case 1:
2331  $this->answer_feedback = 1;
2332  break;
2333  default:
2334  $this->answer_feedback = 0;
2335  break;
2336  }
2337 }
2338 
2345 function setGenericAnswerFeedback($generic_answer_feedback = 0)
2346 {
2347  switch ($generic_answer_feedback)
2348  {
2349  case 1:
2350  $this->answer_feedback = 1;
2351  break;
2352  default:
2353  $this->answer_feedback = 0;
2354  break;
2355  }
2356 }
2357 
2366  {
2367  switch ($answer_feedback_points)
2368  {
2369  case 1:
2370  $this->answer_feedback_points = 1;
2371  break;
2372  default:
2373  $this->answer_feedback_points = 0;
2374  break;
2375  }
2376  }
2377 
2386  {
2387  if (!$reporting_date)
2388  {
2389  $this->reporting_date = "";
2390  $this->ects_output = 0;
2391  }
2392  else
2393  {
2394  $this->reporting_date = $reporting_date;
2395  }
2396  }
2397 
2407  {
2408  return ($this->sequence_settings) ? $this->sequence_settings : 0;
2409  }
2410 
2419  {
2420  return ($this->score_reporting) ? $this->score_reporting : 0;
2421  }
2422 
2431  {
2432  return ($this->instant_verification) ? $this->instant_verification : 0;
2433  }
2434 
2443  public function getAnswerFeedback()
2444  {
2445  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2446  }
2447 
2456  public function getGenericAnswerFeedback()
2457  {
2458  return ($this->answer_feedback) ? $this->answer_feedback : 0;
2459  }
2460 
2469 {
2470  return ($this->answer_feedback_points) ? $this->answer_feedback_points : 0;
2471 }
2472 
2480  function getCountSystem()
2481  {
2482  return ($this->count_system) ? $this->count_system : 0;
2483  }
2484 
2492  function _getCountSystem($active_id)
2493  {
2494  global $ilDB;
2495  $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",
2496  array('integer'),
2497  array($active_id)
2498  );
2499  if ($result->numRows())
2500  {
2501  $row = $ilDB->fetchAssoc($result);
2502  return $row["count_system"];
2503  }
2504  return FALSE;
2505  }
2506 
2514  function getMCScoring()
2515  {
2516  return ($this->mc_scoring) ? $this->mc_scoring : 0;
2517  }
2518 
2526  function getScoreCutting()
2527  {
2528  return ($this->score_cutting) ? $this->score_cutting : 0;
2529  }
2530 
2538  function getPassword()
2539  {
2540  return (strlen($this->password)) ? $this->password : NULL;
2541  }
2542 
2550  function getPassScoring()
2551  {
2552  return ($this->pass_scoring) ? $this->pass_scoring : 0;
2553  }
2554 
2562  function _getPassScoring($active_id)
2563  {
2564  global $ilDB;
2565  $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",
2566  array('integer'),
2567  array($active_id)
2568  );
2569  if ($result->numRows())
2570  {
2571  $row = $ilDB->fetchAssoc($result);
2572  return $row["pass_scoring"];
2573  }
2574  return 0;
2575  }
2576 
2584  function _getMCScoring($active_id)
2585  {
2586  global $ilDB;
2587  $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",
2588  array('integer'),
2589  array($active_id)
2590  );
2591  if ($result->numRows())
2592  {
2593  $row = $ilDB->fetchAssoc($result);
2594  return $row["mc_scoring"];
2595  }
2596  return FALSE;
2597  }
2598 
2606  function _getScoreCutting($active_id)
2607  {
2608  global $ilDB;
2609  $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",
2610  array('integer'),
2611  array($active_id)
2612  );
2613  if ($result->numRows())
2614  {
2615  $row = $ilDB->fetchAssoc($result);
2616  return $row["score_cutting"];
2617  }
2618  return FALSE;
2619  }
2620 
2628  function getReportingDate()
2629  {
2630  return (strlen($this->reporting_date)) ? $this->reporting_date : NULL;
2631  }
2632 
2640  function getNrOfTries()
2641  {
2642  return ($this->nr_of_tries) ? $this->nr_of_tries : 0;
2643  }
2644 
2652  function getKiosk()
2653  {
2654  return ($this->_kiosk) ? $this->_kiosk : 0;
2655  }
2656 
2657 
2665  function setKiosk($kiosk = 0)
2666  {
2667  $this->_kiosk = $kiosk;
2668  }
2669 
2677  function getKioskMode()
2678  {
2679  if (($this->_kiosk & 1) > 0)
2680  {
2681  return TRUE;
2682  }
2683  else
2684  {
2685  return FALSE;
2686  }
2687  }
2688 
2696  public function setKioskMode($a_kiosk = FALSE)
2697  {
2698  if ($a_kiosk)
2699  {
2700  $this->_kiosk = $this->_kiosk | 1;
2701  }
2702  else
2703  {
2704  if ($this->getKioskMode())
2705  {
2706  $this->_kiosk = $this->_kiosk ^ 1;
2707  }
2708  }
2709  }
2710 
2718  public function getShowKioskModeTitle()
2719  {
2720  if (($this->_kiosk & 2) > 0)
2721  {
2722  return TRUE;
2723  }
2724  else
2725  {
2726  return FALSE;
2727  }
2728  }
2729 
2736  public function setShowKioskModeTitle($a_title = FALSE)
2737  {
2738  if ($a_title)
2739  {
2740  $this->_kiosk = $this->_kiosk | 2;
2741  }
2742  else
2743  {
2744  if ($this->getShowKioskModeTitle())
2745  {
2746  $this->_kiosk = $this->_kiosk ^ 2;
2747  }
2748  }
2749  }
2750 
2759  {
2760  if (($this->_kiosk & 4) > 0)
2761  {
2762  return TRUE;
2763  }
2764  else
2765  {
2766  return FALSE;
2767  }
2768  }
2769 
2776  public function setShowKioskModeParticipant($a_participant = FALSE)
2777  {
2778  if ($a_participant)
2779  {
2780  $this->_kiosk = $this->_kiosk | 4;
2781  }
2782  else
2783  {
2784  if ($this->getShowKioskModeParticipant())
2785  {
2786  $this->_kiosk = $this->_kiosk ^ 4;
2787  }
2788  }
2789  }
2790 
2799  {
2800  return ($this->use_previous_answers) ? $this->use_previous_answers : 0;
2801  }
2802 
2810  function getTitleOutput()
2811  {
2812  return ($this->title_output) ? $this->title_output : 0;
2813  }
2814 
2823  function _getTitleOutput($active_id)
2824  {
2825  global $ilDB;
2826 
2827  $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",
2828  array('integer'),
2829  array($active_id)
2830  );
2831  if ($result->numRows())
2832  {
2833  $row = $ilDB->fetchAssoc($result);
2834  return $row["title_output"];
2835  }
2836  return 0;
2837  }
2838 
2848  function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
2849  {
2850  global $ilDB;
2851  global $ilUser;
2852 
2854 
2855  $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",
2856  array("integer"),
2857  array($active_id)
2858  );
2859  if ($result->numRows())
2860  {
2861  $row = $ilDB->fetchAssoc($result);
2862  $use_previous_answers = $row["use_previous_answers"];
2863  }
2864 
2865  if ($use_previous_answers == 1)
2866  {
2867  if ($user_active_user_setting)
2868  {
2869  $res = $ilUser->getPref("tst_use_previous_answers");
2870  if ($res !== FALSE)
2871  {
2873  }
2874  }
2875  }
2876  return $use_previous_answers;
2877  }
2878 
2887  {
2888  return (strlen($this->processing_time)) ? $this->processing_time : NULL;
2889  }
2890 
2897  public function getProcessingTimeAsArray()
2898  {
2899  if (strlen($this->processing_time))
2900  {
2901  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/is", $this->processing_time, $matches))
2902  {
2903  if ((int)$matches[1]+(int)$matches[2]+(int)$matches[3] == 0)
2904  {
2905  return $this->getEstimatedWorkingTime();
2906  }
2907  else
2908  {
2909  return array(
2910  'hh' => $matches[1],
2911  'mm' => $matches[2],
2912  'ss' => $matches[3],
2913  );
2914  }
2915  }
2916  }
2917  return $this->getEstimatedWorkingTime();
2918  }
2919 
2927  function getProcessingTimeInSeconds($active_id = "")
2928  {
2929  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches))
2930  {
2931  $extratime = $this->getExtraTime($active_id) * 60;
2932  return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
2933  }
2934  else
2935  {
2936  return 0;
2937  }
2938  }
2939 
2948  {
2949  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndingTime(), $matches))
2950  {
2951  $ending = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
2952  $now = time();
2953  return $ending - $now;
2954  }
2955  else
2956  {
2957  return 0;
2958  }
2959  }
2960 
2969  {
2970  return ($this->enable_processing_time) ? $this->enable_processing_time : 0;
2971  }
2972 
2981  {
2982  return ($this->reset_processing_time) ? $this->reset_processing_time : 0;
2983  }
2984 
2992  function getStartingTime()
2993  {
2994  return (strlen($this->starting_time)) ? $this->starting_time : NULL;
2995  }
2996 
3004  function getEndingTime()
3005  {
3006  return (strlen($this->ending_time)) ? $this->ending_time : NULL;
3007  }
3008 
3017  {
3018  $this->nr_of_tries = $nr_of_tries;
3019  }
3020 
3029  {
3031  {
3032  $this->use_previous_answers = 1;
3033  }
3034  else
3035  {
3036  $this->use_previous_answers = 0;
3037  }
3038  }
3039 
3041  {
3042  $this->redirection_mode = $redirection_mode;
3043  }
3045  {
3046  return $this->redirection_mode;
3047  }
3049  {
3050  $this->redirection_url = $redirection_url;
3051  }
3053  {
3054  return $this->redirection_url;
3055  }
3056 
3065  {
3066  switch ($title_output)
3067  {
3068  case 1:
3069  $this->title_output = 1;
3070  break;
3071  case 2:
3072  $this->title_output = 2;
3073  break;
3074  default:
3075  $this->title_output = 0;
3076  break;
3077  }
3078  }
3079 
3087  function setProcessingTime($processing_time = "00:00:00")
3088  {
3089  $this->processing_time = $processing_time;
3090  }
3091 
3099  function setEnableProcessingTime($enable = 0)
3100  {
3101  if ($enable) {
3102  $this->enable_processing_time = "1";
3103  } else {
3104  $this->enable_processing_time = "0";
3105  }
3106  }
3107 
3115  function setResetProcessingTime($reset = 0)
3116  {
3117  if ($reset)
3118  {
3119  $this->reset_processing_time = 1;
3120  }
3121  else
3122  {
3123  $this->reset_processing_time = 0;
3124  }
3125  }
3126 
3135  {
3136  $this->starting_time = $starting_time;
3137  }
3138 
3146  function setEndingTime($ending_time = NULL)
3147  {
3148  $this->ending_time = $ending_time;
3149  }
3150 
3158  function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3159  {
3160  $this->count_system = $a_count_system;
3161  }
3162 
3170  function setPassword($a_password = NULL)
3171  {
3172  $this->password = $a_password;
3173  }
3174 
3182  function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3183  {
3184  $this->score_cutting = $a_score_cutting;
3185  }
3186 
3195  {
3196  $this->mc_scoring = $a_mc_scoring;
3197  }
3198 
3206  function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3207  {
3208  switch ($a_pass_scoring)
3209  {
3210  case SCORE_BEST_PASS:
3211  $this->pass_scoring = SCORE_BEST_PASS;
3212  break;
3213  default:
3214  $this->pass_scoring = SCORE_LAST_PASS;
3215  break;
3216  }
3217  }
3218 
3226  function removeQuestion($question_id)
3227  {
3228  $question =& ilObjTest::_instanciateQuestion($question_id);
3229  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3231  {
3232  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3233  }
3234  $question->delete($question_id);
3235  $this->removeAllTestEditings($question_id);
3236  $this->loadQuestions();
3237  $this->saveQuestionsToDb();
3238  }
3239 
3247  public function removeAllTestEditings($question_id = "")
3248  {
3249  global $ilDB;
3250 
3251  // remove the question from tst_solutions
3252  if ($question_id)
3253  {
3254  $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",
3255  array('integer','integer'),
3256  array($this->getTestId(), $question_id)
3257  );
3258  $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",
3259  array('integer','integer'),
3260  array($this->getTestId(), $question_id)
3261  );
3262  $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",
3263  array('integer','integer'),
3264  array($this->getTestId(), $question_id)
3265  );
3266  $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)",
3267  array('integer'),
3268  array($this->getTestId())
3269  );
3270 
3271  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3273  }
3274  else
3275  {
3276  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE tst_solutions.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3277  array('integer'),
3278  array($this->getTestId())
3279  );
3280  $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)",
3281  array('integer'),
3282  array($this->getTestId())
3283  );
3284  $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)",
3285  array('integer'),
3286  array($this->getTestId())
3287  );
3288  $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)",
3289  array('integer'),
3290  array($this->getTestId())
3291  );
3292 
3293  $query = "SELECT active_id FROM tst_active WHERE test_fi = %s";
3294  $res = $ilDB->queryF($query, array('integer'), array($this->getTestId()));
3295  $activeIds = array();
3296  while( $row = $ilDB->fetchAssoc($res) )
3297  {
3298  $activeIds[] = $row['active_id'];
3299  }
3300 
3301  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3303 
3304  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3306  {
3307  $this->logAction($this->lng->txtlng("assessment", "log_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()));
3308  }
3309  }
3310 
3311  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_sequence WHERE tst_sequence.active_fi IN (SELECT active_id FROM tst_active WHERE test_fi = %s)",
3312  array('integer'),
3313  array($this->getTestId())
3314  );
3315 
3316  if ($this->isRandomTest())
3317  {
3318  $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)",
3319  array('integer'),
3320  array($this->getTestId())
3321  );
3322  }
3323 
3324  // remove test_active entries, because test has changed
3325  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE test_fi = %s",
3326  array('integer'),
3327  array($this->getTestId())
3328  );
3329 
3330  // remove saved user passwords
3331  $affectedRows = $ilDB->manipulateF("DELETE FROM usr_pref WHERE keyword = %s",
3332  array('text'),
3333  array("tst_password_".$this->getTestId())
3334  );
3335 
3336  // TODO: this shouldn't be here since it is question stuff and should be modular but there's no other solution yet
3337  // remove file uploads
3338  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId()))
3339  {
3340  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId());
3341  }
3342  }
3343 
3344  public function removeTestResults(ilTestParticipantData $participantData)
3345  {
3346  if( count($participantData->getAnonymousActiveIds()) )
3347  {
3348  $this->removeTestResultsByActiveIds($participantData->getAnonymousActiveIds());
3349  }
3350 
3351  if( count($participantData->getUserIds()) )
3352  {
3353  /* @var ilTestLP $testLP */
3354  require_once 'Services/Object/classes/class.ilObjectLP.php';
3355  $testLP = ilObjectLP::getInstance($this->getId());
3356  $testLP->resetLPDataForUserIds($participantData->getUserIds(), false);
3357  }
3358 
3359  if( count($participantData->getActiveIds()) )
3360  {
3361  $this->removeTestActives($participantData->getActiveIds());
3362  }
3363  }
3364 
3365  public function removeTestResultsByUserIds($userIds)
3366  {
3367  global $ilDB, $lng;
3368 
3369  require_once 'Modules/Test/classes/class.ilTestParticipantData.php';
3370  $participantData = new ilTestParticipantData($ilDB, $lng);
3371  $participantData->setUserIds($userIds);
3372  $participantData->load($this->getTestId());
3373 
3374  $IN_userIds = $ilDB->in('usr_id', $participantData->getUserIds(), false, 'integer');
3375  $ilDB->manipulateF("DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
3376  array('text'), array("tst_password_".$this->getTestId())
3377  );
3378 
3379  if( count($participantData->getActiveIds()) )
3380  {
3381  $this->removeTestResultsByActiveIds($participantData->getActiveIds());
3382  }
3383  }
3384 
3385  public function removeTestResultsByActiveIds($activeIds)
3386  {
3387  global $ilDB;
3388 
3389  $IN_activeIds = $ilDB->in('active_fi', $activeIds, false, 'integer');
3390 
3391  $ilDB->manipulate("DELETE FROM tst_solutions WHERE $IN_activeIds");
3392  $ilDB->manipulate("DELETE FROM tst_qst_solved WHERE $IN_activeIds");
3393  $ilDB->manipulate("DELETE FROM tst_test_result WHERE $IN_activeIds");
3394  $ilDB->manipulate("DELETE FROM tst_pass_result WHERE $IN_activeIds");
3395  $ilDB->manipulate("DELETE FROM tst_result_cache WHERE $IN_activeIds");
3396  $ilDB->manipulate("DELETE FROM tst_sequence WHERE $IN_activeIds");
3397 
3398  if( $this->isRandomTest() )
3399  {
3400  $ilDB->manipulate("DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
3401  }
3402  elseif( $this->isDynamicTest() )
3403  {
3404  $ilDB->manipulate("DELETE FROM tst_seq_qst_tracking WHERE $IN_activeIds");
3405  $ilDB->manipulate("DELETE FROM tst_seq_qst_answstatus WHERE $IN_activeIds");
3406  $ilDB->manipulate("DELETE FROM tst_seq_qst_postponed WHERE $IN_activeIds");
3407  $ilDB->manipulate("DELETE FROM tst_seq_qst_checked WHERE $IN_activeIds");
3408  }
3409 
3410  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3411 
3412  foreach ($activeIds as $active_id)
3413  {
3414  // TODO: this shouldn't be here since it is question stuff and should be modular but there's no other solution yet
3415  // remove file uploads
3416  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id"))
3417  {
3418  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3419  }
3420 
3422  {
3423  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3424  }
3425  }
3426 
3427  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3429  }
3430 
3431  public function removeTestActives($activeIds)
3432  {
3433  global $ilDB;
3434 
3435  $IN_activeIds = $ilDB->in('active_id', $activeIds, false, 'integer');
3436  $ilDB->manipulate("DELETE FROM tst_active WHERE $IN_activeIds");
3437  }
3438 
3439  function removeTestResultsForUser($user_id)
3440  {
3441  global $ilDB;
3442 
3443  $active_id = $this->getActiveIdOfUser($user_id);
3444 
3445  // remove the question from tst_solutions
3446  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s",
3447  array('integer'),
3448  array($active_id)
3449  );
3450  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_qst_solved WHERE active_fi = %s",
3451  array('integer'),
3452  array($active_id)
3453  );
3454  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_result WHERE active_fi = %s",
3455  array('integer'),
3456  array($active_id)
3457  );
3458  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_pass_result WHERE active_fi = %s",
3459  array('integer'),
3460  array($active_id)
3461  );
3462 
3463  if ($this->isRandomTest())
3464  {
3465  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_rnd_qst WHERE active_fi = %s",
3466  array('integer'),
3467  array($active_id)
3468  );
3469  }
3470 
3471  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3473  {
3474  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3475  }
3476 
3477  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_sequence WHERE active_fi = %s",
3478  array('integer'),
3479  array($active_id)
3480  );
3481 
3482  // remove test_active entry
3483  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE active_id = %s",
3484  array('integer'),
3485  array($active_id)
3486  );
3487 
3488  // remove saved user password
3489  if ($user_id > 0)
3490  {
3491  $affectedRows = $ilDB->manipulateF("DELETE FROM usr_pref WHERE usr_id = %s AND keyword = %s",
3492  array('integer', 'text'),
3493  array($user_id, "tst_password_".$this->getTestId())
3494  );
3495  }
3496 
3497  // TODO: this shouldn't be here since it is question stuff and should be modular but there's no other solution yet
3498  // remove file uploads
3499  if (@is_dir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id"))
3500  {
3501  ilUtil::delDir(CLIENT_WEB_DIR . "/assessment/tst_" . $this->getTestId() . "/$active_id");
3502  }
3503 
3504  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
3506  }
3507 
3515  function questionMoveUp($question_id)
3516  {
3517  global $ilDB;
3518 
3519  // Move a question up in sequence
3520  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3521  array('integer', 'integer'),
3522  array($this->getTestId(), $question_id)
3523  );
3524  $data = $ilDB->fetchObject($result);
3525  if ($data->sequence > 1)
3526  {
3527  // OK, it's not the top question, so move it up
3528  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3529  array('integer','integer'),
3530  array($this->getTestId(), $data->sequence - 1)
3531  );
3532  $data_previous = $ilDB->fetchObject($result);
3533  // change previous dataset
3534  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3535  array('integer','integer'),
3536  array($data->sequence, $data_previous->test_question_id)
3537  );
3538  // move actual dataset up
3539  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3540  array('integer','integer'),
3541  array($data->sequence - 1, $data->test_question_id)
3542  );
3543  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3545  {
3546  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence-1), $question_id);
3547  }
3548  }
3549  $this->loadQuestions();
3550  }
3551 
3559  function questionMoveDown($question_id)
3560  {
3561  global $ilDB;
3562 
3563  // Move a question down in sequence
3564  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3565  array('integer','integer'),
3566  array($this->getTestId(), $question_id)
3567  );
3568  $data = $ilDB->fetchObject($result);
3569  $result = $ilDB->queryF("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3570  array('integer','integer'),
3571  array($this->getTestId(), $data->sequence + 1)
3572  );
3573  if ($result->numRows() == 1)
3574  {
3575  // OK, it's not the last question, so move it down
3576  $data_next = $ilDB->fetchObject($result);
3577  // change next dataset
3578  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3579  array('integer','integer'),
3580  array($data->sequence, $data_next->test_question_id)
3581  );
3582  // move actual dataset down
3583  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3584  array('integer','integer'),
3585  array($data->sequence + 1, $data->test_question_id)
3586  );
3587  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3589  {
3590  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence+1), $question_id);
3591  }
3592  }
3593  $this->loadQuestions();
3594  }
3595 
3603  function duplicateQuestionForTest($question_id)
3604  {
3605  global $ilUser;
3606  $question =& ilObjTest::_instanciateQuestion($question_id);
3607  $duplicate_id = $question->duplicate(true, null, null, null, $this->getId());
3608 
3609  return $duplicate_id;
3610  }
3611 
3620  public function insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly = false)
3621  {
3622  global $ilDB;
3623 #var_dump($question_id);
3624  if ($linkOnly)
3625  {
3626  $duplicate_id = $question_id;
3627  }
3628  else
3629  {
3630  $duplicate_id = $this->duplicateQuestionForTest($question_id);
3631  }
3632 
3633  // get maximum sequence index in test
3634  $result = $ilDB->queryF("SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
3635  array('integer'),
3636  array($this->getTestId())
3637  );
3638  $sequence = 1;
3639 
3640  if ($result->numRows() == 1)
3641  {
3642  $data = $ilDB->fetchObject($result);
3643  $sequence = $data->seq + 1;
3644  }
3645 
3646  $next_id = $ilDB->nextId('tst_test_question');
3647  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
3648  array('integer', 'integer','integer','integer','integer'),
3649  array($next_id, $this->getTestId(), $duplicate_id, $sequence, time())
3650  );
3651  if ($affectedRows == 1)
3652  {
3653  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3655  {
3656  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3657  }
3658  }
3659  // remove test_active entries, because test has changed
3660  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_active WHERE test_fi = %s",
3661  array('integer'),
3662  array($this->getTestId())
3663  );
3664  $this->loadQuestions();
3665  $this->saveCompleteStatus($testQuestionSetConfig);
3666  return $duplicate_id;
3667  }
3668 
3676  function &getQuestionTitles()
3677  {
3678  $titles = array();
3679  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED)
3680  {
3681  global $ilDB;
3682  $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",
3683  array('integer'),
3684  array($this->getTestId())
3685  );
3686  while ($row = $ilDB->fetchAssoc($result))
3687  {
3688  array_push($titles, $row["title"]);
3689  }
3690  }
3691  return $titles;
3692  }
3693 
3702  {
3703  $titles = array();
3704  if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED)
3705  {
3706  global $ilDB;
3707  $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",
3708  array('integer'),
3709  array($this->getTestId())
3710  );
3711  while ($row = $ilDB->fetchAssoc($result))
3712  {
3713  $titles[$row['question_id']] = $row["title"];
3714  }
3715  }
3716  return $titles;
3717  }
3718 
3728  {
3729  if ($this->getTitleOutput() == 2)
3730  {
3731  return $this->lng->txt("ass_question");
3732  }
3733  else
3734  {
3735  return $title;
3736  }
3737  }
3738 
3747  function getQuestionDataset($question_id)
3748  {
3749  global $ilDB;
3750 
3751  $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",
3752  array('integer'),
3753  array($question_id)
3754  );
3755  $row = $ilDB->fetchObject($result);
3756  return $row;
3757  }
3758 
3765  function &getExistingQuestions($pass = NULL)
3766  {
3767  global $ilUser;
3768  global $ilDB;
3769 
3770  $existing_questions = array();
3771  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3772  if ($this->isRandomTest())
3773  {
3774  if (is_null($pass)) $pass = 0;
3775  $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",
3776  array('integer','integer'),
3777  array($active_id, $pass)
3778  );
3779  }
3780  else
3781  {
3782  $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",
3783  array('integer'),
3784  array($this->getTestId())
3785  );
3786  }
3787  while ($data = $ilDB->fetchObject($result))
3788  {
3789  if( $data->original_id === null )
3790  {
3791  continue;
3792  }
3793 
3794  array_push($existing_questions, $data->original_id);
3795  }
3796  return $existing_questions;
3797  }
3798 
3806  function getQuestionType($question_id)
3807  {
3808  global $ilDB;
3809 
3810  if ($question_id < 1) return -1;
3811  $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",
3812  array('integer'),
3813  array($question_id)
3814  );
3815  if ($result->numRows() == 1)
3816  {
3817  $data = $ilDB->fetchObject($result);
3818  return $data->type_tag;
3819  }
3820  else
3821  {
3822  return "";
3823  }
3824  }
3825 
3832  function startWorkingTime($active_id, $pass)
3833  {
3834  global $ilDB;
3835 
3836  $next_id = $ilDB->nextId('tst_times');
3837  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
3838  array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'),
3839  array($next_id, $active_id, strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"), $pass, time())
3840  );
3841  return $next_id;
3842  }
3843 
3850  function updateWorkingTime($times_id)
3851  {
3852  global $ilDB;
3853 
3854  $affectedRows = $ilDB->manipulateF("UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
3855  array('timestamp', 'integer', 'integer'),
3856  array(strftime("%Y-%m-%d %H:%M:%S"), time(), $times_id)
3857  );
3858  }
3859 
3866  function &getWorkedQuestions($active_id, $pass = NULL)
3867  {
3868  global $ilUser;
3869  global $ilDB;
3870 
3871  if (is_null($pass))
3872  {
3873  $result = $ilDB->queryF("SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3874  array('integer','integer'),
3875  array($active_id, 0)
3876  );
3877  }
3878  else
3879  {
3880  $result = $ilDB->queryF("SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
3881  array('integer','integer'),
3882  array($active_id, $pass)
3883  );
3884  }
3885  $result_array = array();
3886  while ($row = $ilDB->fetchAssoc($result))
3887  {
3888  array_push($result_array, $row["question_fi"]);
3889  }
3890  return $result_array;
3891  }
3892 
3901  function isTestFinishedToViewResults($active_id, $currentpass)
3902  {
3903  $num = $this->getPassFinishDate($active_id, $currentpass);
3904  return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ? true : false;
3905  }
3906 
3913  function &getAllQuestions($pass = NULL)
3914  {
3915  global $ilUser;
3916  global $ilDB;
3917 
3918  $result_array = array();
3919  if ($this->isRandomTest())
3920  {
3921  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3922  $this->loadQuestions($active_id, $pass);
3923  if (count($this->questions) == 0) return $result_array;
3924  if (is_null($pass))
3925  {
3926  $pass = $this->_getPass($active_id);
3927  }
3928  $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'),
3929  array('integer','integer'),
3930  array($active_id, $pass)
3931  );
3932  }
3933  else
3934  {
3935  if (count($this->questions) == 0) return $result_array;
3936  $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'));
3937  }
3938  while ($row = $ilDB->fetchAssoc($result))
3939  {
3940  $result_array[$row["question_id"]] = $row;
3941  }
3942  return $result_array;
3943  }
3944 
3953  function getActiveIdOfUser($user_id = "", $anonymous_id = "")
3954  {
3955  global $ilDB;
3956  global $ilUser;
3957 
3958  if (!$user_id) $user_id = $ilUser->getId();
3959  if (($_SESSION["AccountId"] == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()])))
3960  {
3961  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3962  array('integer','integer','text'),
3963  array($user_id, $this->test_id, $_SESSION["tst_access_code"][$this->getTestId()])
3964  );
3965  }
3966  else if (strlen($anonymous_id))
3967  {
3968  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
3969  array('integer','integer','text'),
3970  array($user_id, $this->test_id, $anonymous_id)
3971  );
3972  }
3973  else
3974  {
3975  if ($_SESSION["AccountId"] == ANONYMOUS_USER_ID)
3976  {
3977  return NULL;
3978  }
3979  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
3980  array('integer','integer'),
3981  array($user_id, $this->test_id)
3982  );
3983  }
3984  if ($result->numRows())
3985  {
3986  $row = $ilDB->fetchAssoc($result);
3987  return $row["active_id"];
3988  }
3989  else
3990  {
3991  return 0;
3992  }
3993  }
3994 
4003  function _getActiveIdOfUser($user_id = "", $test_id = "")
4004  {
4005  global $ilDB;
4006  global $ilUser;
4007 
4008  if (!$user_id) {
4009  $user_id = $ilUser->id;
4010  }
4011  if (!$test_id)
4012  {
4013  return "";
4014  }
4015  $result = $ilDB->queryF("SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4016  array('integer', 'integer'),
4017  array($user_id, $test_id)
4018  );
4019  if ($result->numRows())
4020  {
4021  $row = $ilDB->fetchAssoc($result);
4022  return $row["active_id"];
4023  }
4024  else
4025  {
4026  return "";
4027  }
4028  }
4029 
4036  function pcArrayShuffle($array)
4037  {
4038  $keys = array_keys($array);
4039  shuffle($keys);
4040  $result = array();
4041  foreach ($keys as $key)
4042  {
4043  $result[$key] = $array[$key];
4044  }
4045  return $result;
4046  }
4047 
4055  function &getTestResult($active_id, $pass = NULL, $ordered_sequence = FALSE)
4056  {
4057  global $tree, $ilDB, $lng, $ilPluginAdmin;
4058 
4059  $results = $this->getResultsForActiveId($active_id);
4060 
4061  if( is_null($pass) )
4062  {
4063  $pass = $results['pass'];
4064  }
4065 
4066  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
4067  $testSessionFactory = new ilTestSessionFactory($this);
4068  $testSession = $testSessionFactory->getSession($active_id);
4069 
4070  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
4071  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
4072  $testSequence = $testSequenceFactory->getSequenceByPass($testSession, $pass);
4073 
4074  if( $this->isDynamicTest() )
4075  {
4076  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
4077  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
4078  $dynamicQuestionSetConfig->loadFromDb();
4079 
4080  $testSequence->loadFromDb($dynamicQuestionSetConfig);
4081  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
4082 
4083  $sequence = $testSequence->getUserSequenceQuestions();
4084  }
4085  else
4086  {
4087  $testSequence->loadFromDb();
4088  $testSequence->loadQuestions();
4089 
4090  if( $ordered_sequence )
4091  {
4092  $sequence = $testSequence->getOrderedSequenceQuestions();
4093  }
4094  else
4095  {
4096  $sequence = $testSequence->getUserSequenceQuestions();
4097  }
4098  }
4099 
4100  $arrResults = array();
4101 
4102  $query = "
4103  SELECT tst_test_result.question_fi,
4104  tst_test_result.points reached,
4105  tst_test_result.hint_count requested_hints,
4106  tst_test_result.hint_points hint_points,
4107  tst_test_result.answered answered
4108 
4109  FROM tst_test_result
4110 
4111  LEFT JOIN tst_solutions
4112  ON tst_solutions.active_fi = tst_test_result.active_fi
4113  AND tst_solutions.question_fi = tst_test_result.question_fi
4114 
4115  WHERE tst_test_result.active_fi = %s
4116  AND tst_test_result.pass = %s
4117  ";
4118 
4119  $solutionresult = $ilDB->queryF(
4120  $query, array('integer', 'integer'), array($active_id, $pass)
4121  );
4122 
4123  while( $row = $ilDB->fetchAssoc($solutionresult) )
4124  {
4125  $arrResults[ $row['question_fi'] ] = $row;
4126  }
4127 
4128  $numWorkedThrough = count($arrResults);
4129 
4130  require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4131 
4132  $IN_question_ids = $ilDB->in('qpl_questions.question_id', $sequence, false, 'integer');
4133 
4134  $query = "
4135  SELECT qpl_questions.*,
4136  qpl_qst_type.type_tag,
4137  qpl_sol_sug.question_fi has_sug_sol
4138 
4139  FROM qpl_qst_type,
4140  qpl_questions
4141 
4142  LEFT JOIN qpl_sol_sug
4143  ON qpl_sol_sug.question_fi = qpl_questions.question_id
4144 
4145  WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi
4146  AND $IN_question_ids
4147  ";
4148 
4149  $result = $ilDB->query($query);
4150 
4151  $unordered = array();
4152 
4153  $key = 1;
4154 
4155  $obligationsAnswered = true;
4156 
4157  while( $row = $ilDB->fetchAssoc($result) )
4158  {
4159  $percentvalue = (
4160  $row['points'] ? $arrResults[ $row['question_id'] ]['reached'] / $row['points'] : 0
4161  );
4162 
4163  if( $percentvalue < 0 ) $percentvalue = 0.0;
4164 
4165  $data = array(
4166  "nr" => "$key",
4167  "title" => ilUtil::prepareFormOutput($row['title']),
4168  "max" => round($row['points'], 2),
4169  "reached" => round($arrResults[$row['question_id']]['reached'],2),
4170  'requested_hints' => $arrResults[$row['question_id']]['requested_hints'],
4171  'hint_points' => $arrResults[$row['question_id']]['hint_points'],
4172  "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4173  "solution" => ($row['has_sug_sol']) ? assQuestion::_getSuggestedSolutionOutput($row['question_id']) : '',
4174  "type" => $row["type_tag"],
4175  "qid" => $row['question_id'],
4176  "original_id" => $row["original_id"],
4177  "workedthrough" => isset($arrResults[$row['question_id']]) ? 1 : 0,
4178  'answered' => $arrResults[$row['question_id']]['answered']
4179  );
4180 
4181  if( !$arrResults[ $row['question_id'] ]['answered'] )
4182  {
4183  $obligationsAnswered = false;
4184  }
4185 
4186  $unordered[ $row['question_id'] ] = $data;
4187 
4188  $key++;
4189  }
4190 
4191  $pass_max = 0;
4192  $pass_reached = 0;
4193  $pass_requested_hints = 0;
4194  $pass_hint_points = 0;
4195  $key = 1;
4196 
4197  $found = array();
4198 
4199  foreach( $sequence as $qid )
4200  {
4201  // building pass point sums based on prepared data
4202  // for question that exists in users qst sequence
4203  $pass_max += round($unordered[$qid]['max'], 2);
4204  $pass_reached += round($unordered[$qid]['reached'], 2);
4205  $pass_requested_hints += $unordered[$qid]['requested_hints'];
4206  $pass_hint_points += $unordered[$qid]['hint_points'];
4207 
4208  // pickup prepared data for question
4209  // that exists in users qst sequence
4210  $unordered[$qid]['nr'] = $key;
4211  array_push($found, $unordered[$qid]);
4212 
4213  // increment key counter
4214  $key++;
4215  }
4216 
4217  $unordered = null;
4218 
4219  if( $this->getScoreCutting() == 1 )
4220  {
4221  if( $results['reached_points'] < 0 )
4222  {
4223  $results['reached_points'] = 0;
4224  }
4225 
4226  if( $pass_reached < 0 ) $pass_reached = 0;
4227  }
4228 
4229  $found['pass']['total_max_points'] = $pass_max;
4230  $found['pass']['total_reached_points'] = $pass_reached;
4231  $found['pass']['total_requested_hints'] = $pass_requested_hints;
4232  $found['pass']['total_hint_points'] = $pass_hint_points;
4233  $found['pass']['percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
4234  $found['pass']['obligationsAnswered'] = $obligationsAnswered;
4235  $found['pass']['num_workedthrough'] = $numWorkedThrough;
4236 
4237  $found["test"]["total_max_points"] = $results['max_points'];
4238  $found["test"]["total_reached_points"] = $results['reached_points'];
4239  $found["test"]["total_requested_hints"] = $results['hint_count'];
4240  $found["test"]["total_hint_points"] = $results['hint_points'];
4241  $found["test"]["result_pass"] = $results['pass'];
4242  $found['test']['obligations_answered'] = $results['obligations_answered'];
4243 
4244  if( (!$total_reached_points) or (!$total_max_points) )
4245  {
4246  $percentage = 0.0;
4247  }
4248  else
4249  {
4250  $percentage = ($total_reached_points / $total_max_points) * 100.0;
4251 
4252  if( $percentage < 0 ) $percentage = 0.0;
4253  }
4254 
4255  $found["test"]["passed"] = $results['passed'];
4256 
4257  return $found;
4258  }
4259 
4266  function evalTotalPersons()
4267  {
4268  global $ilDB;
4269 
4270  $result = $ilDB->queryF("SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
4271  array('integer'),
4272  array($this->getTestId())
4273  );
4274  $row = $ilDB->fetchAssoc($result);
4275  return $row["total"];
4276  }
4277 
4284  function getCompleteWorkingTime($user_id)
4285  {
4286  global $ilDB;
4287 
4288  $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",
4289  array('integer','integer'),
4290  array($this->getTestId(), $user_id)
4291  );
4292  $time = 0;
4293  while ($row = $ilDB->fetchAssoc($result))
4294  {
4295  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4296  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4297  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4298  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4299  $time += ($epoch_2 - $epoch_1);
4300  }
4301  return $time;
4302  }
4303 
4311  {
4312  return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4313  }
4314 
4323  {
4324  global $ilDB;
4325 
4326  $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",
4327  array('integer'),
4328  array($test_id)
4329  );
4330  $time = 0;
4331  $times = array();
4332  while ($row = $ilDB->fetchAssoc($result))
4333  {
4334  if (!array_key_exists($row["active_fi"], $times))
4335  {
4336  $times[$row["active_fi"]] = 0;
4337  }
4338  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4339  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4340  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4341  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4342  $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4343  }
4344  return $times;
4345  }
4346 
4354  {
4355  global $ilDB;
4356 
4357  $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",
4358  array('integer','integer'),
4359  array($this->getTestId(), $active_id)
4360  );
4361  $time = 0;
4362  while ($row = $ilDB->fetchAssoc($result))
4363  {
4364  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4365  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4366  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4367  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4368  $time += ($epoch_2 - $epoch_1);
4369  }
4370  return $time;
4371  }
4372 
4380  {
4381  global $ilDB;
4382 
4383  $result = $ilDB->queryF("SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4384  array('integer','integer'),
4385  array($active_id, $pass)
4386  );
4387  $time = 0;
4388  while ($row = $ilDB->fetchAssoc($result))
4389  {
4390  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4391  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4392  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4393  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4394  $time += ($epoch_2 - $epoch_1);
4395  }
4396  return $time;
4397  }
4398 
4406  function getVisitTimeOfParticipant($active_id)
4407  {
4408  return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4409  }
4410 
4419  function _getVisitTimeOfParticipant($test_id, $active_id)
4420  {
4421  global $ilDB;
4422 
4423  $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",
4424  array('integer','integer'),
4425  array($test_id, $active_id)
4426  );
4427  $firstvisit = 0;
4428  $lastvisit = 0;
4429  while ($row = $ilDB->fetchAssoc($result))
4430  {
4431  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4432  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4433  if ($firstvisit == 0 || $epoch_1 < $firstvisit) $firstvisit = $epoch_1;
4434  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4435  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4436  if ($epoch_2 > $lastvisit) $lastvisit = $epoch_2;
4437  }
4438  return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4439  }
4440 
4447  function &evalStatistical($active_id)
4448  {
4449  global $ilDB;
4450 // global $ilBench;
4451  $pass = ilObjTest::_getResultPass($active_id);
4452  $test_result =& $this->getTestResult($active_id, $pass);
4453  $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",
4454  array('integer'),
4455  array($active_id)
4456  );
4457  $times = array();
4458  $first_visit = 0;
4459  $last_visit = 0;
4460  while ($row = $ilDB->fetchObject($result))
4461  {
4462  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4463  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4464  if (!$first_visit) {
4465  $first_visit = $epoch_1;
4466  }
4467  if ($epoch_1 < $first_visit) {
4468  $first_visit = $epoch_1;
4469  }
4470  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4471  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4472  if (!$last_visit) {
4473  $last_visit = $epoch_2;
4474  }
4475  if ($epoch_2 > $last_visit) {
4476  $last_visit = $epoch_2;
4477  }
4478  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4479  }
4480  $max_time = 0;
4481  foreach ($times as $key => $value) {
4482  $max_time += $value;
4483  }
4484  if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"]))
4485  {
4486  $percentage = 0.0;
4487  }
4488  else
4489  {
4490  $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4491  if ($percentage < 0) $percentage = 0.0;
4492  }
4493  $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4494  $first_date = getdate($first_visit);
4495  $last_date = getdate($last_visit);
4496  $qworkedthrough = 0;
4497  foreach ($test_result as $key => $value)
4498  {
4499  if (preg_match("/\d+/", $key))
4500  {
4501  $qworkedthrough += $value["workedthrough"];
4502  }
4503  }
4504  if (!$qworkedthrough)
4505  {
4506  $atimeofwork = 0;
4507  }
4508  else
4509  {
4510  $atimeofwork = $max_time / $qworkedthrough;
4511  }
4512 
4513  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4514 
4515  $result_mark = "";
4516  $passed = "";
4517 
4518  if ($mark_obj)
4519  {
4520  $result_mark = $mark_obj->getShortName();
4521 
4522  if( $mark_obj->getPassed() && $obligationsAnswered )
4523  {
4524  $passed = 1;
4525  }
4526  else
4527  {
4528  $passed = 0;
4529  }
4530  }
4531  $percent_worked_through = 0;
4532  if (count($this->questions))
4533  {
4534  $percent_worked_through = $qworkedthrough / count($this->questions);
4535  }
4536  $result_array = array(
4537  "qworkedthrough" => $qworkedthrough,
4538  "qmax" => count($this->questions),
4539  "pworkedthrough" => $percent_worked_through,
4540  "timeofwork" => $max_time,
4541  "atimeofwork" => $atimeofwork,
4542  "firstvisit" => $first_date,
4543  "lastvisit" => $last_date,
4544  "resultspoints" => $test_result["test"]["total_reached_points"],
4545  "maxpoints" => $test_result["test"]["total_max_points"],
4546  "resultsmarks" => $result_mark,
4547  "passed" => $passed,
4548  "distancemedian" => "0"
4549  );
4550  foreach ($test_result as $key => $value)
4551  {
4552  if (preg_match("/\d+/", $key))
4553  {
4554  $result_array[$key] = $value;
4555  }
4556  }
4557  return $result_array;
4558  }
4559 
4568  {
4569  $totalpoints_array = array();
4570  $all_users =& $this->evalTotalParticipantsArray();
4571  foreach ($all_users as $active_id => $user_name)
4572  {
4573  $test_result =& $this->getTestResult($active_id);
4574  $reached = $test_result["test"]["total_reached_points"];
4575  $total = $test_result["test"]["total_max_points"];
4576  $percentage = $total != 0 ? $reached/$total : 0;
4577  $mark = $this->mark_schema->getMatchingMark($percentage*100.0);
4578 
4579  $obligationsAnswered = $test_result["test"]["obligations_answered"];
4580 
4581  if ($mark)
4582  {
4583  if( $mark->getPassed() && $obligationsAnswered )
4584  {
4585  array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4586  }
4587  }
4588  }
4589  return $totalpoints_array;
4590  }
4591 
4597  public function &getParticipants()
4598  {
4599  global $ilDB;
4600  $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",
4601  array('integer'),
4602  array($this->getTestId())
4603  );
4604  $persons_array = array();
4605  while ($row = $ilDB->fetchAssoc($result))
4606  {
4607  $name = $this->lng->txt("unknown");
4608  $fullname = $this->lng->txt("unknown");
4609  $login = "";
4610  if (!$this->getAnonymity())
4611  {
4612  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4613  {
4614  $name = $this->lng->txt("deleted_user");
4615  $fullname = $this->lng->txt("deleted_user");
4616  $login = $this->lng->txt("unknown");
4617  }
4618  else
4619  {
4620  $login = $row["login"];
4621  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4622  {
4623  $name = $this->lng->txt("unknown");
4624  $fullname = $this->lng->txt("unknown");
4625  }
4626  else
4627  {
4628  $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4629  $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4630  }
4631  }
4632  }
4633  $persons_array[$row["active_id"]] = array(
4634  "name" => $name,
4635  "fullname" => $fullname,
4636  "login" => $login
4637  );
4638  }
4639  return $persons_array;
4640  }
4641 
4648  function &evalTotalPersonsArray($name_sort_order = "asc")
4649  {
4650  global $ilDB;
4651  $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),
4652  array('integer'),
4653  array($this->getTestId())
4654  );
4655  $persons_array = array();
4656  while ($row = $ilDB->fetchAssoc($result))
4657  {
4658  if ($this->getAnonymity())
4659  {
4660  $persons_array[$row["active_id"]] = $this->lng->txt("unknown");
4661  }
4662  else
4663  {
4664  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4665  {
4666  $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4667  }
4668  else
4669  {
4670  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4671  {
4672  $persons_array[$row["active_id"]] = $row["lastname"];
4673  }
4674  else
4675  {
4676  $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4677  }
4678  }
4679  }
4680  }
4681  return $persons_array;
4682  }
4683 
4690  function &evalTotalParticipantsArray($name_sort_order = "asc")
4691  {
4692  global $ilDB;
4693  $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),
4694  array('integer'),
4695  array($this->getTestId())
4696  );
4697  $persons_array = array();
4698  while ($row = $ilDB->fetchAssoc($result))
4699  {
4700  if ($this->getAnonymity())
4701  {
4702  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("unknown"));
4703  }
4704  else
4705  {
4706  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4707  {
4708  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4709  }
4710  else
4711  {
4712  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4713  {
4714  $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4715  }
4716  else
4717  {
4718  $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4719  }
4720  }
4721  }
4722  }
4723  return $persons_array;
4724  }
4725 
4733  {
4734  global $ilDB;
4735 
4736  $result = $ilDB->queryF("SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s AND submitted = %s",
4737  array('integer', 'integer'),
4738  array($this->getTestId(), 1)
4739  );
4740  $row = $ilDB->fetchAssoc($result);
4741  return $row["total"];
4742  }
4743 
4750  function &getQuestionsOfTest($active_id)
4751  {
4752  global $ilDB;
4753  if ($this->isRandomTest())
4754  {
4755  $ilDB->setLimit($this->getQuestionCount(), 0);
4756  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4757  "tst_test_rnd_qst.pass, qpl_questions.points " .
4758  "FROM tst_test_rnd_qst, qpl_questions " .
4759  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4760  "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4761  array('integer'),
4762  array($active_id)
4763  );
4764  }
4765  else
4766  {
4767  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4768  "qpl_questions.points " .
4769  "FROM tst_test_question, tst_active, qpl_questions " .
4770  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4771  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4772  array('integer'),
4773  array($active_id)
4774  );
4775  }
4776  $qtest = array();
4777  if ($result->numRows())
4778  {
4779  while ($row = $ilDB->fetchAssoc($result))
4780  {
4781  array_push($qtest, $row);
4782  }
4783  }
4784  return $qtest;
4785  }
4786 
4793  function &getQuestionsOfPass($active_id, $pass)
4794  {
4795  global $ilDB;
4796  if ($this->isRandomTest())
4797  {
4798  $ilDB->setLimit($this->getQuestionCount(), 0);
4799  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
4800  "qpl_questions.points " .
4801  "FROM tst_test_rnd_qst, qpl_questions " .
4802  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4803  "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
4804  "ORDER BY tst_test_rnd_qst.sequence",
4805  array('integer', 'integer'),
4806  array($active_id, $pass)
4807  );
4808  }
4809  else
4810  {
4811  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4812  "qpl_questions.points " .
4813  "FROM tst_test_question, tst_active, qpl_questions " .
4814  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4815  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4816  array('integer'),
4817  array($active_id)
4818  );
4819  }
4820  $qpass = array();
4821  if ($result->numRows())
4822  {
4823  while ($row = $ilDB->fetchAssoc($result))
4824  {
4825  array_push($qpass, $row);
4826  }
4827  }
4828  return $qpass;
4829  }
4830 
4832  {
4833  global $ilDB;
4834 
4835  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
4836  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
4837  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
4838 
4839  $data = new ilTestEvaluationData($this);
4840 
4841  $query = "
4842  SELECT tst_test_result.*,
4843  qpl_questions.original_id,
4844  qpl_questions.title questiontitle,
4845  qpl_questions.points maxpoints
4846 
4847  FROM tst_test_result, qpl_questions, tst_active
4848 
4849  WHERE tst_active.active_id = tst_test_result.active_fi
4850  AND qpl_questions.question_id = tst_test_result.question_fi
4851  AND tst_active.test_fi = %s
4852 
4853  ORDER BY tst_active.active_id ASC, tst_test_result.pass ASC, tst_test_result.tstamp DESC
4854  ";
4855 
4856  $result = $ilDB->queryF(
4857  $query, array('integer'), array($this->getTestId())
4858  );
4859 
4860  $pass = NULL;
4861  $checked = array();
4862  $datasets = 0;
4863 
4864  while( $row = $ilDB->fetchAssoc($result) )
4865  {
4866  $participantObject = $data->getParticipant($row["active_fi"]);
4867 
4868  if( !($participantObject instanceof ilTestEvaluationUserData) )
4869  {
4870  continue;
4871  }
4872 
4873  $passObject = $participantObject->getPass($row["pass"]);
4874 
4875  if( !($passObject instanceof ilTestEvaluationPassData) )
4876  {
4877  continue;
4878  }
4879 
4880  $passObject->addAnsweredQuestion(
4881  $row["question_fi"], $row["maxpoints"], $row["points"], $row['answered'], null, $row['manual']
4882  );
4883  }
4884 
4885  foreach( array_keys($data->getParticipants()) as $active_id )
4886  {
4887  if( $this->isRandomTest() )
4888  {
4889  for( $testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++ )
4890  {
4891  $ilDB->setLimit($this->getQuestionCount(), 0);
4892  $result = $ilDB->queryF("SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, qpl_questions.original_id, " .
4893  "tst_test_rnd_qst.pass, qpl_questions.points, qpl_questions.title " .
4894  "FROM tst_test_rnd_qst, qpl_questions " .
4895  "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
4896  "AND tst_test_rnd_qst.pass = %s " .
4897  "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
4898  array('integer','integer'),
4899  array($testpass, $active_id)
4900  );
4901  if ($result->numRows())
4902  {
4903  while ($row = $ilDB->fetchAssoc($result))
4904  {
4905  $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
4906  $data->getParticipant($active_id)->addQuestion($row["original_id"], $row["question_fi"], $row["points"], $row["sequence"], $tpass);
4907  $data->addQuestionTitle($row["question_fi"], $row["title"]);
4908  }
4909  }
4910  }
4911  }
4912  else
4913  {
4914  $result = $ilDB->queryF("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4915  "qpl_questions.points, qpl_questions.title, qpl_questions.original_id " .
4916  "FROM tst_test_question, tst_active, qpl_questions " .
4917  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4918  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi ORDER BY tst_test_question.sequence",
4919  array('integer'),
4920  array($active_id)
4921  );
4922  if ($result->numRows())
4923  {
4924  $questionsbysequence = array();
4925 
4926  while ($row = $ilDB->fetchAssoc($result))
4927  {
4928  $questionsbysequence[$row["sequence"]] = $row;
4929  }
4930 
4931  $seqresult = $ilDB->queryF("SELECT * FROM tst_sequence WHERE active_fi = %s",
4932  array('integer'),
4933  array($active_id)
4934  );
4935 
4936  while ($seqrow = $ilDB->fetchAssoc($seqresult))
4937  {
4938  $questionsequence = unserialize($seqrow["sequence"]);
4939  foreach ($questionsequence as $sidx => $seq)
4940  {
4941  $data->getParticipant($active_id)->addQuestion($questionsbysequence[$seq]["original_id"], $questionsbysequence[$seq]["question_fi"], $questionsbysequence[$seq]["points"], $sidx + 1, $seqrow["pass"]);
4942  $data->addQuestionTitle($questionsbysequence[$seq]["question_fi"], $questionsbysequence[$seq]["title"]);
4943  }
4944  }
4945  }
4946  }
4947  }
4948 
4949  if ($this->ects_output)
4950  {
4951  $passed_array =& $this->getTotalPointsPassedArray();
4952  }
4953 
4954  foreach( array_keys($data->getParticipants()) as $active_id )
4955  {
4956  $tstUserData = $data->getParticipant($active_id);
4957 
4958  $percentage = $tstUserData->getReachedPointsInPercent();
4959 
4960  $obligationsAnswered = $tstUserData->areObligationsAnswered();
4961 
4962  $mark = $this->mark_schema->getMatchingMark($percentage);
4963 
4964  if (is_object($mark))
4965  {
4966  $tstUserData->setMark($mark->getShortName());
4967  $tstUserData->setMarkOfficial($mark->getOfficialName());
4968 
4969  $tstUserData->setPassed(
4970  $mark->getPassed() && $tstUserData->areObligationsAnswered()
4971  );
4972  }
4973 
4974  if ($this->ects_output)
4975  {
4976  $ects_mark = $this->getECTSGrade(
4977  $passed_array, $tstUserData->getReached(), $tstUserData->getMaxPoints()
4978  );
4979 
4980  $tstUserData->setECTSMark($ects_mark);
4981  }
4982 
4983  $visitingTime =& $this->getVisitTimeOfParticipant($active_id);
4984 
4985  $tstUserData->setFirstVisit($visitingTime["firstvisit"]);
4986  $tstUserData->setLastVisit($visitingTime["lastvisit"]);
4987  }
4988 
4989  return $data;
4990  }
4991 
4993  {
4994  global $ilDB;
4995 
4997 
4998  switch( $questionSetType )
4999  {
5001 
5002  $res = $ilDB->queryF("
5003  SELECT COUNT(qpl_questions.question_id) qcount,
5004  SUM(qpl_questions.points) qsum
5005  FROM tst_active
5006  INNER JOIN tst_tests
5007  ON tst_tests.test_id = tst_active.test_fi
5008  INNER JOIN tst_dyn_quest_set_cfg
5009  ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
5010  INNER JOIN qpl_questions
5011  ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
5012  AND qpl_questions.original_id IS NULL
5013  AND qpl_questions.complete = %s
5014  WHERE tst_active.active_id = %s
5015  ",
5016  array('integer', 'integer'),
5017  array(1, $active_id)
5018  );
5019 
5020  break;
5021 
5023 
5024  $res = $ilDB->queryF("
5025  SELECT tst_test_rnd_qst.pass,
5026  COUNT(tst_test_rnd_qst.question_fi) qcount,
5027  SUM(qpl_questions.points) qsum
5028 
5029  FROM tst_test_rnd_qst,
5030  qpl_questions
5031 
5032  WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
5033  AND tst_test_rnd_qst.active_fi = %s
5034  AND pass = %s
5035 
5036  GROUP BY tst_test_rnd_qst.active_fi,
5037  tst_test_rnd_qst.pass
5038  ",
5039  array('integer', 'integer'),
5040  array($active_id, $pass)
5041  );
5042 
5043  break;
5044 
5046 
5047  $res = $ilDB->queryF("
5048  SELECT COUNT(tst_test_question.question_fi) qcount,
5049  SUM(qpl_questions.points) qsum
5050 
5051  FROM tst_test_question,
5052  qpl_questions,
5053  tst_active
5054 
5055  WHERE tst_test_question.question_fi = qpl_questions.question_id
5056  AND tst_test_question.test_fi = tst_active.test_fi
5057  AND tst_active.active_id = %s
5058 
5059  GROUP BY tst_test_question.test_fi
5060  ",
5061  array('integer'),
5062  array($active_id)
5063  );
5064 
5065  break;
5066 
5067  default:
5068 
5069  throw new ilTestException("not supported question set type: $questionSetType");
5070  }
5071 
5072  $row = $ilDB->fetchAssoc($res);
5073 
5074  if( is_array($row) )
5075  {
5076  return array("count" => $row["qcount"], "points" => $row["qsum"]);
5077  }
5078 
5079  return array("count" => 0, "points" => 0);
5080  }
5081 
5082  function &getCompleteEvaluationData($withStatistics = TRUE, $filterby = "", $filtertext = "")
5083  {
5084  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5085  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5086  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5087  $data = $this->getUnfilteredEvaluationData();
5088  if ($withStatistics)
5089  {
5090  $data->calculateStatistics();
5091  }
5092  $data->setFilter($filterby, $filtertext);
5093  return $data;
5094  }
5095 
5103  {
5104  return $this->_evalResultsOverview($this->getTestId());
5105  }
5106 
5114  {
5115  global $ilDB;
5116 
5117  $result = $ilDB->queryF("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5118  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5119  "qpl_questions.points maxpoints " .
5120  "FROM tst_test_result, qpl_questions, tst_active " .
5121  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5122  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5123  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5124  "AND tst_active.test_fi = %s " .
5125  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5126  array('integer'),
5127  array($test_id)
5128  );
5129  $overview = array();
5130  while ($row = $ilDB->fetchAssoc($result))
5131  {
5132  if (!array_key_exists($row["active_fi"], $overview))
5133  {
5134  $overview[$row["active_fi"]] = array();
5135  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5136  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5137  $overview[$row["active_fi"]]["title"] = $row["title"];
5138  $overview[$row["active_fi"]]["login"] = $row["login"];
5139  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5140  $overview[$row["active_fi"]]["started"] = $row["started"];
5141  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5142  }
5143  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5144  {
5145  $overview[$row["active_fi"]][$row["pass"]] = array();
5146  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5147  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5148  }
5149  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5150  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5151  }
5152  return $overview;
5153  }
5154 
5162  function &evalResultsOverviewOfParticipant($active_id)
5163  {
5164  global $ilDB;
5165 
5166  $result = $ilDB->queryF("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5167  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
5168  "qpl_questions.points maxpoints " .
5169  "FROM tst_test_result, qpl_questions, tst_active " .
5170  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5171  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5172  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5173  "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5174  "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
5175  array('integer', 'integer'),
5176  array($this->getTestId(), $active_id)
5177  );
5178  $overview = array();
5179  while ($row = $ilDB->fetchAssoc($result))
5180  {
5181  if (!array_key_exists($row["active_fi"], $overview))
5182  {
5183  $overview[$row["active_fi"]] = array();
5184  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5185  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5186  $overview[$row["active_fi"]]["title"] = $row["title"];
5187  $overview[$row["active_fi"]]["login"] = $row["login"];
5188  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5189  $overview[$row["active_fi"]]["started"] = $row["started"];
5190  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5191  }
5192  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5193  {
5194  $overview[$row["active_fi"]][$row["pass"]] = array();
5195  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5196  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5197  }
5198  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5199  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5200  }
5201  return $overview;
5202  }
5203 
5215  function buildName($user_id, $firstname, $lastname, $title)
5216  {
5217  $name = "";
5218  if (strlen($firstname.$lastname.$title) == 0)
5219  {
5220  $name = $this->lng->txt("deleted_user");
5221  }
5222  else
5223  {
5224  if ($user_id == ANONYMOUS_USER_ID)
5225  {
5226  $name = $lastname;
5227  }
5228  else
5229  {
5230  $name = trim($lastname . ", " . $firstname . " " . $title);
5231  }
5232  if ($this->getAnonymity())
5233  {
5234  $name = $this->lng->txt("anonymous");
5235  }
5236  }
5237  return $name;
5238  }
5239 
5252  function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5253  {
5254  global $lng;
5255  $name = "";
5256  if (strlen($firstname.$lastname.$title) == 0)
5257  {
5258  $name = $lng->txt("deleted_user");
5259  }
5260  else
5261  {
5262  if ($user_id == ANONYMOUS_USER_ID)
5263  {
5264  $name = $lastname;
5265  }
5266  else
5267  {
5268  $name = trim($lastname . ", " . $firstname . " " . $title);
5269  }
5270  if ($is_anonymous)
5271  {
5272  $name = $lng->txt("anonymous");
5273  }
5274  }
5275  return $name;
5276  }
5277 
5285  {
5286  global $ilDB;
5287 
5288  $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",
5289  array('integer'),
5290  array($this->getTestId())
5291  );
5292  $times = array();
5293  while ($row = $ilDB->fetchObject($result))
5294  {
5295  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5296  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5297  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5298  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5299  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5300  }
5301  $max_time = 0;
5302  $counter = 0;
5303  foreach ($times as $key => $value)
5304  {
5305  $max_time += $value;
5306  $counter++;
5307  }
5308  if ($counter)
5309  {
5310  $average_time = round($max_time / $counter);
5311  }
5312  else
5313  {
5314  $average_time = 0;
5315  }
5316  return $average_time;
5317  }
5318 
5325  function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = FALSE, $with_questioncount = FALSE, $permission = "read")
5326  {
5327  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5328  return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5329  }
5330 
5338  {
5339  $time_in_seconds = 0;
5340  foreach ($this->questions as $question_id)
5341  {
5342  $question =& ilObjTest::_instanciateQuestion($question_id);
5343  $est_time = $question->getEstimatedWorkingTime();
5344  $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5345  }
5346  $hours = (int)($time_in_seconds / 3600) ;
5347  $time_in_seconds = $time_in_seconds - ($hours * 3600);
5348  $minutes = (int)($time_in_seconds / 60);
5349  $time_in_seconds = $time_in_seconds - ($minutes * 60);
5350  $result = array("hh" => $hours, "mm" => $minutes, "ss" => $time_in_seconds);
5351  return $result;
5352  }
5353 
5360  function getImagePath()
5361  {
5362  return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5363  }
5364 
5371  function getImagePathWeb()
5372  {
5373  include_once "./Services/Utilities/classes/class.ilUtil.php";
5374  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
5376  }
5377 
5386  function &createQuestionGUI($question_type, $question_id = -1)
5387  {
5388  if ((!$question_type) and ($question_id > 0))
5389  {
5390  $question_type = $this->getQuestionType($question_id);
5391  }
5392 
5393  if (!strlen($question_type)) return null;
5394 
5395  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5396  assQuestion::_includeClass($question_type, 1);
5397 
5398  $question_type_gui = assQuestion::getGuiClassNameByQuestionType($question_type);
5399  $question = new $question_type_gui();
5400 
5401  $question->object->setObligationsToBeConsidered( $this->areObligationsEnabled() );
5402 
5403  if ($question_id > 0)
5404  {
5405  $question->object->loadFromDb($question_id);
5406 
5407  global $ilCtrl, $ilDB, $ilUser, $lng;
5408 
5409  $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
5410  $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
5411 
5412  $assSettings = new ilSetting('assessment');
5413  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
5414  $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
5415  $processLockerFactory->setQuestionId($question->object->getId());
5416  $processLockerFactory->setUserId($ilUser->getId());
5417  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
5418  $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
5419  $question->object->setProcessLocker($processLockerFactory->getLocker());
5420  }
5421 
5422  return $question;
5423  }
5424 
5434  function &_instanciateQuestion($question_id)
5435  {
5436  if (strcmp($question_id, "") != 0)
5437  {
5438  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5439  return assQuestion::_instanciateQuestion($question_id);
5440  }
5441  }
5442 
5451  function moveQuestions($move_questions, $target_index, $insert_mode)
5452  {
5453  $this->questions = array_values($this->questions);
5454  $array_pos = array_search($target_index, $this->questions);
5455  if ($insert_mode == 0)
5456  {
5457  $part1 = array_slice($this->questions, 0, $array_pos);
5458  $part2 = array_slice($this->questions, $array_pos);
5459  }
5460  else if ($insert_mode == 1)
5461  {
5462  $part1 = array_slice($this->questions, 0, $array_pos + 1);
5463  $part2 = array_slice($this->questions, $array_pos + 1);
5464  }
5465  foreach ($move_questions as $question_id)
5466  {
5467  if (!(array_search($question_id, $part1) === FALSE))
5468  {
5469  unset($part1[array_search($question_id, $part1)]);
5470  }
5471  if (!(array_search($question_id, $part2) === FALSE))
5472  {
5473  unset($part2[array_search($question_id, $part2)]);
5474  }
5475  }
5476  $part1 = array_values($part1);
5477  $part2 = array_values($part2);
5478  $new_array = array_values(array_merge($part1, $move_questions, $part2));
5479  $this->questions = array();
5480  $counter = 1;
5481  foreach ($new_array as $question_id)
5482  {
5483  $this->questions[$counter] = $question_id;
5484  $counter++;
5485  }
5486  $this->saveQuestionsToDb();
5487  }
5488 
5489 
5498  {
5499  if ($this->getStartingTime())
5500  {
5501  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getStartingTime(), $matches))
5502  {
5503  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5504  $now = mktime();
5505  if ($now < $epoch_time)
5506  {
5507  // starting time not reached
5508  return false;
5509  }
5510  }
5511  }
5512  return true;
5513  }
5514 
5523  {
5524  if ($this->getEndingTime())
5525  {
5526  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndingTime(), $matches))
5527  {
5528  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5529  $now = mktime();
5530  if ($now > $epoch_time)
5531  {
5532  // ending time reached
5533  return true;
5534  }
5535  }
5536  }
5537  return false;
5538  }
5539 
5545  function getAvailableQuestions($arrFilter, $completeonly = 0)
5546  {
5547  global $ilUser;
5548  global $ilDB;
5549 
5550  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5551  $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = TRUE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE));
5552  $available = "";
5553  if (count($available_pools))
5554  {
5555  $available = " AND " . $ilDB->in('qpl_questions.obj_fi', $available_pools, false, 'integer');
5556  }
5557  else
5558  {
5559  return array();
5560  }
5561  if ($completeonly)
5562  {
5563  $available .= " AND qpl_questions.complete = " . $ilDB->quote("1", 'text');
5564  }
5565 
5566  $where = "";
5567  if (is_array($arrFilter))
5568  {
5569  if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title']))
5570  {
5571  $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
5572  }
5573  if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description']))
5574  {
5575  $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
5576  }
5577  if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author']))
5578  {
5579  $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
5580  }
5581  if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type']))
5582  {
5583  $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
5584  }
5585  if (array_key_exists('qpl', $arrFilter) && strlen($arrFilter['qpl']))
5586  {
5587  $where .= " AND " . $ilDB->like('object_data.title', 'text', "%%" . $arrFilter['qpl'] . "%%");
5588  }
5589  }
5590 
5591  $original_ids =& $this->getExistingQuestions();
5592  $original_clause = " qpl_questions.original_id IS NULL";
5593  if (count($original_ids))
5594  {
5595  $original_clause = " qpl_questions.original_id IS NULL AND " . $ilDB->in('qpl_questions.question_id', $original_ids, true, 'integer');
5596  }
5597 
5598  $query_result = $ilDB->query(
5599  "SELECT qpl_questions.*, qpl_questions.tstamp, qpl_qst_type.type_tag, qpl_qst_type.plugin, object_data.title qpl " .
5600  "FROM qpl_questions, qpl_qst_type, object_data WHERE $original_clause $available AND " .
5601  "object_data.obj_id = qpl_questions.obj_fi AND qpl_questions.tstamp > 0 AND " .
5602  "qpl_questions.question_type_fi = qpl_qst_type.question_type_id$where");
5603  $rows = array();
5604  $types = $this->getQuestionTypeTranslations();
5605  if ($query_result->numRows())
5606  {
5607  while ($row = $ilDB->fetchAssoc($query_result))
5608  {
5609  $row['ttype'] = $types[$row['type_tag']];
5610  if ($row["plugin"])
5611  {
5612  if ($this->isPluginActive($row["type_tag"]))
5613  {
5614  array_push($rows, $row);
5615  }
5616  }
5617  else
5618  {
5619  array_push($rows, $row);
5620  }
5621  }
5622  }
5623  return $rows;
5624  }
5625 
5626  public function &getQuestionTypeTranslations()
5627  {
5628  global $ilDB;
5629  global $lng;
5630  global $ilLog;
5631  global $ilPluginAdmin;
5632 
5633  $lng->loadLanguageModule("assessment");
5634  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
5635  $types = array();
5636  while ($row = $ilDB->fetchAssoc($result))
5637  {
5638  if ($row["plugin"] == 0)
5639  {
5640  $types[$row['type_tag']] = $lng->txt($row["type_tag"]);
5641  }
5642  else
5643  {
5644  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
5645  foreach ($pl_names as $pl_name)
5646  {
5647  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
5648  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
5649  {
5650  $types[$row['type_tag']] = $pl->getQuestionTypeTranslation();
5651  }
5652  }
5653  }
5654  }
5655  ksort($types);
5656  return $types;
5657  }
5658 
5663  public function fromXML(ilQTIAssessment $assessment)
5664  {
5665  unset($_SESSION["import_mob_xhtml"]);
5666 
5667  $this->setDescription($assessment->getComment());
5668  $this->setTitle($assessment->getTitle());
5669 
5670  foreach ($assessment->objectives as $objectives)
5671  {
5672  foreach ($objectives->materials as $material)
5673  {
5674  $this->setIntroduction($this->QTIMaterialToString($material));
5675  }
5676  }
5677 
5678  if(
5679  $assessment->getPresentationMaterial() &&
5680  $assessment->getPresentationMaterial()->getFlowMat(0) &&
5681  $assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)
5682  )
5683  {
5684  $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getFlowMat(0)->getMaterial(0)));
5685  }
5686 
5687  foreach ($assessment->assessmentcontrol as $assessmentcontrol)
5688  {
5689  switch ($assessmentcontrol->getSolutionswitch())
5690  {
5691  case "Yes":
5692  $this->setInstantFeedbackSolution(1);
5693  break;
5694  default:
5695  $this->setInstantFeedbackSolution(0);
5696  break;
5697  }
5698  }
5699 
5700  foreach ($assessment->qtimetadata as $metadata)
5701  {
5702  switch ($metadata["label"])
5703  {
5704  case "test_type":
5705  // for old tests with a test type
5706  $type = $metadata["entry"];
5707  switch ($type)
5708  {
5709  case 1:
5710  // assessment
5711  $this->setAnonymity(1);
5712  break;
5713  case 2:
5714  // self assessment
5715  break;
5716  case 4:
5717  // online exam
5718  $this->setFixedParticipants(1);
5719  $this->setListOfQuestionsSettings(7);
5720  $this->setShowSolutionPrintview(1);
5721  break;
5722  case 5:
5723  // varying random test
5724  break;
5725  }
5726  break;
5727  case "sequence_settings":
5728  $this->setSequenceSettings($metadata["entry"]);
5729  break;
5730  case "author":
5731  $this->setAuthor($metadata["entry"]);
5732  break;
5733  case "nr_of_tries":
5734  $this->setNrOfTries($metadata["entry"]);
5735  break;
5736  case "kiosk":
5737  $this->setKiosk($metadata["entry"]);
5738  break;
5739  case "showfinalstatement":
5740  $this->setShowFinalStatement($metadata["entry"]);
5741  break;
5742  case "showinfo":
5743  $this->setShowInfo($metadata["entry"]);
5744  break;
5745  case "forcejs":
5746  $this->setForceJS($metadata["entry"]);
5747  break;
5748  case "customstyle":
5749  $this->setCustomStyle($metadata["entry"]);
5750  break;
5751 
5752  case "highscore_enabled":
5753  $this->setHighscoreEnabled($metadata["entry"]);
5754  break;
5755 
5756  case "highscore_anon":
5757  $this->setHighscoreAnon($metadata["entry"]);
5758  break;
5759 
5760  case "highscore_achieved_ts":
5761  $this->setHighscoreAchievedTS($metadata["entry"]);
5762  break;
5763 
5764  case "highscore_score":
5765  $this->setHighscoreScore($metadata["entry"]);
5766  break;
5767 
5768  case "highscore_percentage":
5769  $this->setHighscorePercentage($metadata["entry"]);
5770  break;
5771 
5772  case "highscore_hints":
5773  $this->setHighscoreHints($metadata["entry"]);
5774  break;
5775 
5776  case "highscore_wtime":
5777  $this->setHighscoreWTime($metadata["entry"]);
5778  break;
5779 
5780  case "highscore_own_table":
5781  $this->setHighscoreOwnTable($metadata["entry"]);
5782  break;
5783 
5784  case "highscore_top_table":
5785  $this->setHighscoreTopTable($metadata["entry"]);
5786  break;
5787 
5788  case "highscore_top_num":
5789  $this->setHighscoreTopNum($metadata["entry"]);
5790  break;
5791 
5792  case "hide_previous_results":
5793  if ($metadata["entry"] == 0)
5794  {
5795  $this->setUsePreviousAnswers(1);
5796  }
5797  else
5798  {
5799  $this->setUsePreviousAnswers(0);
5800  }
5801  break;
5802  case "use_previous_answers":
5803  $this->setUsePreviousAnswers($metadata["entry"]);
5804  break;
5805  case "answer_feedback":
5806  $this->setAnswerFeedback($metadata["entry"]);
5807  break;
5808  case "hide_title_points":
5809  $this->setTitleOutput($metadata["entry"]);
5810  break;
5811  case "title_output":
5812  $this->setTitleOutput($metadata["entry"]);
5813  break;
5814  case "question_set_type":
5815  $this->setQuestionSetType($metadata["entry"]);
5816  break;
5817  case "random_test":
5818  if( $metadata["entry"] )
5819  {
5820  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
5821  }
5822  else
5823  {
5824  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
5825  }
5826  break;
5827  case "results_presentation":
5828  $this->setResultsPresentation($metadata["entry"]);
5829  break;
5830  case "reset_processing_time":
5831  $this->setResetProcessingTime($metadata["entry"]);
5832  break;
5833  case "instant_verification":
5834  $this->setInstantFeedbackSolution($metadata["entry"]);
5835  break;
5836  case "answer_feedback_points":
5837  $this->setAnswerFeedbackPoints($metadata["entry"]);
5838  break;
5839  case "anonymity":
5840  $this->setAnonymity($metadata["entry"]);
5841  break;
5842  case "show_cancel":
5843  $this->setShowCancel($metadata["entry"]);
5844  break;
5845  case "show_marker":
5846  $this->setShowMarker($metadata["entry"]);
5847  break;
5848  case "fixed_participants":
5849  $this->setFixedParticipants($metadata["entry"]);
5850  break;
5851  case "score_reporting":
5852  $this->setScoreReporting($metadata["entry"]);
5853  break;
5854  case "shuffle_questions":
5855  $this->setShuffleQuestions($metadata["entry"]);
5856  break;
5857  case "count_system":
5858  $this->setCountSystem($metadata["entry"]);
5859  break;
5860  case "mc_scoring":
5861  $this->setMCScoring($metadata["entry"]);
5862  break;
5863  case "mailnotification":
5864  $this->setMailNotification($metadata["entry"]);
5865  break;
5866  case "mailnottype":
5867  $this->setMailNotificationType($metadata["entry"]);
5868  break;
5869  case "exportsettings":
5870  $this->setExportSettings($metadata['entry']);
5871  break;
5872  case "score_cutting":
5873  $this->setScoreCutting($metadata["entry"]);
5874  break;
5875  case "password":
5876  $this->setPassword($metadata["entry"]);
5877  break;
5878  case "allowedUsers":
5879  $this->setAllowedUsers($metadata["entry"]);
5880  break;
5881  case "allowedUsersTimeGap":
5882  $this->setAllowedUsersTimeGap($metadata["entry"]);
5883  break;
5884  case "pass_scoring":
5885  $this->setPassScoring($metadata["entry"]);
5886  break;
5887  case "show_summary":
5888  $this->setListOfQuestionsSettings($metadata["entry"]);
5889  break;
5890  case "reporting_date":
5891  $iso8601period = $metadata["entry"];
5892  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
5893  {
5894  $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
5895  }
5896  break;
5897  case 'enable_processing_time':
5898  $this->setEnableProcessingTime($metadata['entry']);
5899  break;
5900  case "processing_time":
5901  $this->setProcessingTime($metadata['entry']);
5902  break;
5903  case "starting_time":
5904  $iso8601period = $metadata["entry"];
5905  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
5906  {
5907  $this->setStartingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
5908  }
5909  break;
5910  case "ending_time":
5911  $iso8601period = $metadata["entry"];
5912  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
5913  {
5914  $this->setEndingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
5915  }
5916  break;
5917  case "enable_examview":
5918  $this->setEnableExamview($metadata["entry"]);
5919  break;
5920  case 'show_examview_html':
5921  $this->setShowExamviewHtml($metadata['entry']);
5922  break;
5923  case 'show_examview_pdf':
5924  $this->setShowExamviewPdf($metadata['entry']);
5925  break;
5926  case 'redirection_mode':
5927  $this->setRedirectionMode($metadata['entry']);
5928  break;
5929  case 'redirection_url':
5930  $this->setRedirectionUrl($metadata['entry']);
5931  break;
5932  case 'examid_in_kiosk':
5933  case 'examid_in_test_pass':
5934  $this->setShowExamIdInTestPassEnabled($metadata['entry']);
5935  break;
5936  case 'show_exam_id':
5937  case 'examid_in_test_res':
5938  $this->setShowExamIdInTestResultsEnabled($metadata['entry']);
5939  break;
5940  case 'enable_archiving':
5941  $this->setEnableArchiving($metadata['entry']);
5942  break;
5943  case 'sign_submission':
5944  $this->setSignSubmission($metadata['entry']);
5945  break;
5946  case 'char_selector_availability':
5947  $this->setCharSelectorAvailability($metadata['entry']);
5948  break;
5949  case 'char_selector_definition':
5950  $this->setCharSelectorDefinition($metadata['entry']);
5951  break;
5952  case 'activation_limited':
5953  $this->setActivationLimited($metadata['entry']);
5954  break;
5955  case 'activation_start_time':
5956  $this->setActivationStartingTime($metadata['entry']);
5957  break;
5958  case 'activation_end_time':
5959  $this->setActivationEndingTime($metadata['entry']);
5960  break;
5961  case 'activation_visibility':
5962  $this->setActivationVisibility($metadata['entry']);
5963  break;
5964  case 'autosave':
5965  $this->setAutosave($metadata['entry']);
5966  break;
5967  case 'autosave_ival':
5968  $this->setAutosaveIval($metadata['entry']);
5969  break;
5970  case 'offer_question_hints':
5971  $this->setOfferingQuestionHintsEnabled($metadata['entry']);
5972  break;
5973  case 'instant_feedback_specific':
5974  $this->setSpecificAnswerFeedback($metadata['entry']);
5975  break;
5976  case 'obligations_enabled':
5977  $this->setObligationsEnabled($metadata['entry']);
5978  break;
5979  }
5980  if (preg_match("/mark_step_\d+/", $metadata["label"]))
5981  {
5982  $xmlmark = $metadata["entry"];
5983  preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
5984  $mark_short = $matches[1];
5985  preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
5986  $mark_official = $matches[1];
5987  preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
5988  $mark_percentage = $matches[1];
5989  preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
5990  $mark_passed = $matches[1];
5991  $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
5992  }
5993  }
5994  // handle the import of media objects in XHTML code
5995  if (is_array($_SESSION["import_mob_xhtml"]))
5996  {
5997  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
5998  include_once "./Services/RTE/classes/class.ilRTE.php";
5999  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
6000  foreach ($_SESSION["import_mob_xhtml"] as $mob)
6001  {
6002  $importfile = ilObjTest::_getImportDirectory() . '/' . $_SESSION["tst_import_subdir"] . '/' . $mob["uri"];
6003  if (file_exists($importfile))
6004  {
6005  $media_object =& ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, FALSE);
6006  ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
6007  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
6008  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
6009  }
6010  else
6011  {
6012  global $ilLog;
6013  $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
6014  }
6015  }
6016  $this->saveToDb();
6017  }
6018  }
6019 
6025  public function toXML()
6026  {
6027  include_once("./Services/Xml/classes/class.ilXmlWriter.php");
6028  $a_xml_writer = new ilXmlWriter;
6029  // set xml header
6030  $a_xml_writer->xmlHeader();
6031  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
6032  $a_xml_writer->xmlStartTag("questestinterop");
6033 
6034  $attrs = array(
6035  "ident" => "il_".IL_INST_ID."_tst_".$this->getTestId(),
6036  "title" => $this->getTitle()
6037  );
6038  $a_xml_writer->xmlStartTag("assessment", $attrs);
6039  // add qti comment
6040  $a_xml_writer->xmlElement("qticomment", NULL, $this->getDescription());
6041 
6042  // add qti duration
6043  if ($this->enable_processing_time)
6044  {
6045  preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
6046  $a_xml_writer->xmlElement("duration", NULL, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
6047  }
6048 
6049  // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
6050  $a_xml_writer->xmlStartTag("qtimetadata");
6051  $a_xml_writer->xmlStartTag("qtimetadatafield");
6052  $a_xml_writer->xmlElement("fieldlabel", NULL, "ILIAS_VERSION");
6053  $a_xml_writer->xmlElement("fieldentry", NULL, $this->ilias->getSetting("ilias_version"));
6054  $a_xml_writer->xmlEndTag("qtimetadatafield");
6055 
6056  // anonymity
6057  $a_xml_writer->xmlStartTag("qtimetadatafield");
6058  $a_xml_writer->xmlElement("fieldlabel", NULL, "anonymity");
6059  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnonymity()));
6060  $a_xml_writer->xmlEndTag("qtimetadatafield");
6061 
6062  // question set type (fixed, random, dynamic, ...)
6063  $a_xml_writer->xmlStartTag("qtimetadatafield");
6064  $a_xml_writer->xmlElement("fieldlabel", NULL, "question_set_type");
6065  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getQuestionSetType());
6066  $a_xml_writer->xmlEndTag("qtimetadatafield");
6067 
6068  // sequence settings
6069  $a_xml_writer->xmlStartTag("qtimetadatafield");
6070  $a_xml_writer->xmlElement("fieldlabel", NULL, "sequence_settings");
6071  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getSequenceSettings());
6072  $a_xml_writer->xmlEndTag("qtimetadatafield");
6073 
6074  // author
6075  $a_xml_writer->xmlStartTag("qtimetadatafield");
6076  $a_xml_writer->xmlElement("fieldlabel", NULL, "author");
6077  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAuthor());
6078  $a_xml_writer->xmlEndTag("qtimetadatafield");
6079 
6080  // reset processing time
6081  $a_xml_writer->xmlStartTag("qtimetadatafield");
6082  $a_xml_writer->xmlElement("fieldlabel", NULL, "reset_processing_time");
6083  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getResetProcessingTime());
6084  $a_xml_writer->xmlEndTag("qtimetadatafield");
6085 
6086  // count system
6087  $a_xml_writer->xmlStartTag("qtimetadatafield");
6088  $a_xml_writer->xmlElement("fieldlabel", NULL, "count_system");
6089  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCountSystem());
6090  $a_xml_writer->xmlEndTag("qtimetadatafield");
6091 
6092  // multiple choice scoring
6093  $a_xml_writer->xmlStartTag("qtimetadatafield");
6094  $a_xml_writer->xmlElement("fieldlabel", NULL, "mc_scoring");
6095  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMCScoring());
6096  $a_xml_writer->xmlEndTag("qtimetadatafield");
6097 
6098  // multiple choice scoring
6099  $a_xml_writer->xmlStartTag("qtimetadatafield");
6100  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_cutting");
6101  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getScoreCutting());
6102  $a_xml_writer->xmlEndTag("qtimetadatafield");
6103 
6104  // multiple choice scoring
6105  $a_xml_writer->xmlStartTag("qtimetadatafield");
6106  $a_xml_writer->xmlElement("fieldlabel", NULL, "password");
6107  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassword());
6108  $a_xml_writer->xmlEndTag("qtimetadatafield");
6109 
6110  // allowed users
6111  $a_xml_writer->xmlStartTag("qtimetadatafield");
6112  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsers");
6113  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsers());
6114  $a_xml_writer->xmlEndTag("qtimetadatafield");
6115 
6116  // allowed users time gap
6117  $a_xml_writer->xmlStartTag("qtimetadatafield");
6118  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsersTimeGap");
6119  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsersTimeGap());
6120  $a_xml_writer->xmlEndTag("qtimetadatafield");
6121 
6122  // pass scoring
6123  $a_xml_writer->xmlStartTag("qtimetadatafield");
6124  $a_xml_writer->xmlElement("fieldlabel", NULL, "pass_scoring");
6125  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassScoring());
6126  $a_xml_writer->xmlEndTag("qtimetadatafield");
6127 
6128  // score reporting date
6129  if ($this->getReportingDate())
6130  {
6131  $a_xml_writer->xmlStartTag("qtimetadatafield");
6132  $a_xml_writer->xmlElement("fieldlabel", NULL, "reporting_date");
6133  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6134  $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]));
6135  $a_xml_writer->xmlEndTag("qtimetadatafield");
6136  }
6137  // number of tries
6138  $a_xml_writer->xmlStartTag("qtimetadatafield");
6139  $a_xml_writer->xmlElement("fieldlabel", NULL, "nr_of_tries");
6140  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getNrOfTries()));
6141  $a_xml_writer->xmlEndTag("qtimetadatafield");
6142 
6143  // kiosk
6144  $a_xml_writer->xmlStartTag("qtimetadatafield");
6145  $a_xml_writer->xmlElement("fieldlabel", NULL, "kiosk");
6146  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getKiosk()));
6147  $a_xml_writer->xmlEndTag("qtimetadatafield");
6148 
6149 
6150  //redirection_mode
6151  $a_xml_writer->xmlStartTag('qtimetadatafield');
6152  $a_xml_writer->xmlElement("fieldlabel", NULL, "redirection_mode");
6153  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getRedirectionMode());
6154  $a_xml_writer->xmlEndTag("qtimetadatafield");
6155 
6156  //redirection_url
6157  $a_xml_writer->xmlStartTag('qtimetadatafield');
6158  $a_xml_writer->xmlElement("fieldlabel", NULL, "redirection_url");
6159  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getRedirectionUrl());
6160  $a_xml_writer->xmlEndTag("qtimetadatafield");
6161 
6162  // use previous answers
6163  $a_xml_writer->xmlStartTag("qtimetadatafield");
6164  $a_xml_writer->xmlElement("fieldlabel", NULL, "use_previous_answers");
6165  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getUsePreviousAnswers());
6166  $a_xml_writer->xmlEndTag("qtimetadatafield");
6167 
6168  // hide title points
6169  $a_xml_writer->xmlStartTag("qtimetadatafield");
6170  $a_xml_writer->xmlElement("fieldlabel", NULL, "title_output");
6171  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getTitleOutput()));
6172  $a_xml_writer->xmlEndTag("qtimetadatafield");
6173 
6174  // results presentation
6175  $a_xml_writer->xmlStartTag("qtimetadatafield");
6176  $a_xml_writer->xmlElement("fieldlabel", NULL, "results_presentation");
6177  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getResultsPresentation()));
6178  $a_xml_writer->xmlEndTag("qtimetadatafield");
6179 
6180  // examid in test pass
6181  $a_xml_writer->xmlStartTag("qtimetadatafield");
6182  $a_xml_writer->xmlElement("fieldlabel", NULL, "examid_in_test_pass");
6183  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->isShowExamIdInTestPassEnabled()));
6184  $a_xml_writer->xmlEndTag("qtimetadatafield");
6185 
6186  // examid in kiosk
6187  $a_xml_writer->xmlStartTag("qtimetadatafield");
6188  $a_xml_writer->xmlElement("fieldlabel", NULL, "examid_in_test_res");
6189  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->isShowExamIdInTestResultsEnabled()));
6190  $a_xml_writer->xmlEndTag("qtimetadatafield");
6191 
6192  // solution details
6193  $a_xml_writer->xmlStartTag("qtimetadatafield");
6194  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_summary");
6195  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getListOfQuestionsSettings()));
6196  $a_xml_writer->xmlEndTag("qtimetadatafield");
6197 
6198  // solution details
6199  $a_xml_writer->xmlStartTag("qtimetadatafield");
6200  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_reporting");
6201  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getScoreReporting()));
6202  $a_xml_writer->xmlEndTag("qtimetadatafield");
6203 
6204  // solution details
6205  $a_xml_writer->xmlStartTag("qtimetadatafield");
6206  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_verification");
6207  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getInstantFeedbackSolution()));
6208  $a_xml_writer->xmlEndTag("qtimetadatafield");
6209 
6210  // answer specific feedback
6211  $a_xml_writer->xmlStartTag("qtimetadatafield");
6212  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback");
6213  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedback()));
6214  $a_xml_writer->xmlEndTag("qtimetadatafield");
6215 
6216  // answer specific feedback of reached points
6217  $a_xml_writer->xmlStartTag("qtimetadatafield");
6218  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback_points");
6219  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedbackPoints()));
6220  $a_xml_writer->xmlEndTag("qtimetadatafield");
6221 
6222  // highscore
6223  $highscore_metadata = array(
6224  'highscore_enabled' => array('value' => $this->getHighscoreEnabled()),
6225  'highscore_anon' => array('value' => $this->getHighscoreAnon()),
6226  'highscore_achieved_ts' => array('value' => $this->getHighscoreAchievedTS()),
6227  'highscore_score' => array('value' => $this->getHighscoreScore()),
6228  'highscore_percentage' => array('value' => $this->getHighscorePercentage()),
6229  'highscore_hints' => array('value' => $this->getHighscoreHints()),
6230  'highscore_wtime' => array('value' => $this->getHighscoreWTime()),
6231  'highscore_own_table' => array('value' => $this->getHighscoreOwnTable()),
6232  'highscore_top_table' => array('value' => $this->getHighscoreTopTable()),
6233  'highscore_top_num' => array('value' => $this->getHighscoreTopNum()),
6234  );
6235  foreach($highscore_metadata as $label => $data)
6236  {
6237  $a_xml_writer->xmlStartTag("qtimetadatafield");
6238  $a_xml_writer->xmlElement("fieldlabel", NULL, $label);
6239  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $data['value']));
6240  $a_xml_writer->xmlEndTag("qtimetadatafield");
6241  }
6242 
6243  // show cancel
6244  $a_xml_writer->xmlStartTag("qtimetadatafield");
6245  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_cancel");
6246  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowCancel()));
6247  $a_xml_writer->xmlEndTag("qtimetadatafield");
6248 
6249  // show marker
6250  $a_xml_writer->xmlStartTag("qtimetadatafield");
6251  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_marker");
6252  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowMarker()));
6253  $a_xml_writer->xmlEndTag("qtimetadatafield");
6254 
6255  // fixed participants
6256  $a_xml_writer->xmlStartTag("qtimetadatafield");
6257  $a_xml_writer->xmlElement("fieldlabel", NULL, "fixed_participants");
6258  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getFixedParticipants()));
6259  $a_xml_writer->xmlEndTag("qtimetadatafield");
6260 
6261  // show final statement
6262  $a_xml_writer->xmlStartTag("qtimetadatafield");
6263  $a_xml_writer->xmlElement("fieldlabel", NULL, "showfinalstatement");
6264  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6265  $a_xml_writer->xmlEndTag("qtimetadatafield");
6266 
6267  // show introduction only
6268  $a_xml_writer->xmlStartTag("qtimetadatafield");
6269  $a_xml_writer->xmlElement("fieldlabel", NULL, "showinfo");
6270  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6271  $a_xml_writer->xmlEndTag("qtimetadatafield");
6272 
6273  // mail notification
6274  $a_xml_writer->xmlStartTag("qtimetadatafield");
6275  $a_xml_writer->xmlElement("fieldlabel", NULL, "mailnotification");
6276  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMailNotification());
6277  $a_xml_writer->xmlEndTag("qtimetadatafield");
6278 
6279  // mail notification type
6280  $a_xml_writer->xmlStartTag("qtimetadatafield");
6281  $a_xml_writer->xmlElement("fieldlabel", NULL, "mailnottype");
6282  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMailNotificationType());
6283  $a_xml_writer->xmlEndTag("qtimetadatafield");
6284 
6285  // export settings
6286  $a_xml_writer->xmlStartTag("qtimetadatafield");
6287  $a_xml_writer->xmlElement("fieldlabel", NULL, "exportsettings");
6288  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getExportSettings());
6289  $a_xml_writer->xmlEndTag("qtimetadatafield");
6290 
6291  // force JavaScript
6292  $a_xml_writer->xmlStartTag("qtimetadatafield");
6293  $a_xml_writer->xmlElement("fieldlabel", NULL, "forcejs");
6294  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6295  $a_xml_writer->xmlEndTag("qtimetadatafield");
6296 
6297  // custom style
6298  $a_xml_writer->xmlStartTag("qtimetadatafield");
6299  $a_xml_writer->xmlElement("fieldlabel", NULL, "customstyle");
6300  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCustomStyle());
6301  $a_xml_writer->xmlEndTag("qtimetadatafield");
6302 
6303  // shuffle questions
6304  $a_xml_writer->xmlStartTag("qtimetadatafield");
6305  $a_xml_writer->xmlElement("fieldlabel", NULL, "shuffle_questions");
6306  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShuffleQuestions()));
6307  $a_xml_writer->xmlEndTag("qtimetadatafield");
6308 
6309  // processing time
6310  $a_xml_writer->xmlStartTag("qtimetadatafield");
6311  $a_xml_writer->xmlElement("fieldlabel", NULL, "processing_time");
6312  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getProcessingTime());
6313  $a_xml_writer->xmlEndTag("qtimetadatafield");
6314 
6315  // enable_examview
6316  $a_xml_writer->xmlStartTag("qtimetadatafield");
6317  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_examview");
6318  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableExamview());
6319  $a_xml_writer->xmlEndTag("qtimetadatafield");
6320 
6321  // show_examview_html
6322  $a_xml_writer->xmlStartTag("qtimetadatafield");
6323  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_examview_html");
6324  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowExamviewHtml());
6325  $a_xml_writer->xmlEndTag("qtimetadatafield");
6326 
6327  // show_examview_pdf
6328  $a_xml_writer->xmlStartTag("qtimetadatafield");
6329  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_examview_pdf");
6330  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getShowExamviewPdf());
6331  $a_xml_writer->xmlEndTag("qtimetadatafield");
6332 
6333  // enable_archiving
6334  $a_xml_writer->xmlStartTag("qtimetadatafield");
6335  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_archiving");
6336  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableArchiving());
6337  $a_xml_writer->xmlEndTag("qtimetadatafield");
6338 
6339  // sign_submission
6340  $a_xml_writer->xmlStartTag("qtimetadatafield");
6341  $a_xml_writer->xmlElement("fieldlabel", NULL, "sign_submission");
6342  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getSignSubmission());
6343  $a_xml_writer->xmlEndTag("qtimetadatafield");
6344 
6345  // char_selector_availability
6346  $a_xml_writer->xmlStartTag("qtimetadatafield");
6347  $a_xml_writer->xmlElement("fieldlabel", NULL, "char_selector_availability");
6348  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getCharSelectorAvailability()));
6349  $a_xml_writer->xmlEndTag("qtimetadatafield");
6350 
6351  // char_selector_definition
6352  $a_xml_writer->xmlStartTag("qtimetadatafield");
6353  $a_xml_writer->xmlElement("fieldlabel", NULL, "char_selector_definition");
6354  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCharSelectorDefinition());
6355  $a_xml_writer->xmlEndTag("qtimetadatafield");
6356 
6357 
6358  // starting time
6359  if ($this->getStartingTime())
6360  {
6361  $a_xml_writer->xmlStartTag("qtimetadatafield");
6362  $a_xml_writer->xmlElement("fieldlabel", NULL, "starting_time");
6363  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->starting_time, $matches);
6364  $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]));
6365  $a_xml_writer->xmlEndTag("qtimetadatafield");
6366  }
6367  // ending time
6368  if ($this->getEndingTime())
6369  {
6370  $a_xml_writer->xmlStartTag("qtimetadatafield");
6371  $a_xml_writer->xmlElement("fieldlabel", NULL, "ending_time");
6372  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->ending_time, $matches);
6373  $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]));
6374  $a_xml_writer->xmlEndTag("qtimetadatafield");
6375  }
6376 
6377 
6378  //activation_limited
6379  $a_xml_writer->xmlStartTag("qtimetadatafield");
6380  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_limited");
6381  $a_xml_writer->xmlElement("fieldentry", NULL,(int)$this->isActivationLimited());
6382  $a_xml_writer->xmlEndTag("qtimetadatafield");
6383 
6384  //activation_start_time
6385  $a_xml_writer->xmlStartTag("qtimetadatafield");
6386  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_start_time");
6387  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationStartingTime());
6388  $a_xml_writer->xmlEndTag("qtimetadatafield");
6389 
6390  //activation_end_time
6391  $a_xml_writer->xmlStartTag("qtimetadatafield");
6392  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_end_time");
6393  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationEndingTime());
6394  $a_xml_writer->xmlEndTag("qtimetadatafield");
6395 
6396  //activation_visibility
6397  $a_xml_writer->xmlStartTag("qtimetadatafield");
6398  $a_xml_writer->xmlElement("fieldlabel", NULL, "activation_visibility");
6399  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getActivationVisibility());
6400  $a_xml_writer->xmlEndTag("qtimetadatafield");
6401 
6402  // autosave
6403  $a_xml_writer->xmlStartTag("qtimetadatafield");
6404  $a_xml_writer->xmlElement("fieldlabel", NULL, "autosave");
6405  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getAutosave());
6406  $a_xml_writer->xmlEndTag("qtimetadatafield");
6407 
6408  // autosave_ival
6409  $a_xml_writer->xmlStartTag("qtimetadatafield");
6410  $a_xml_writer->xmlElement("fieldlabel", NULL, "autosave_ival");
6411  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getAutosaveIval());
6412  $a_xml_writer->xmlEndTag("qtimetadatafield");
6413 
6414  //offer_question_hints
6415  $a_xml_writer->xmlStartTag("qtimetadatafield");
6416  $a_xml_writer->xmlElement("fieldlabel", NULL, "offer_question_hints");
6417  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->isOfferingQuestionHintsEnabled());
6418  $a_xml_writer->xmlEndTag("qtimetadatafield");
6419 
6420  //instant_feedback_specific
6421  $a_xml_writer->xmlStartTag("qtimetadatafield");
6422  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_feedback_specific");
6423  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getSpecificAnswerFeedback());
6424  $a_xml_writer->xmlEndTag("qtimetadatafield");
6425 
6426  //obligations_enabled
6427  $a_xml_writer->xmlStartTag("qtimetadatafield");
6428  $a_xml_writer->xmlElement("fieldlabel", NULL, "obligations_enabled");
6429  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->areObligationsEnabled());
6430  $a_xml_writer->xmlEndTag("qtimetadatafield");
6431 
6432  //enable_processing_time
6433  $a_xml_writer->xmlStartTag("qtimetadatafield");
6434  $a_xml_writer->xmlElement("fieldlabel", NULL, "enable_processing_time");
6435  $a_xml_writer->xmlElement("fieldentry", NULL, (int)$this->getEnableProcessingTime());
6436  $a_xml_writer->xmlEndTag("qtimetadatafield");
6437 
6438  foreach ($this->mark_schema->mark_steps as $index => $mark)
6439  {
6440  // mark steps
6441  $a_xml_writer->xmlStartTag("qtimetadatafield");
6442  $a_xml_writer->xmlElement("fieldlabel", NULL, "mark_step_$index");
6443  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf(
6444  "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
6445  $mark->getShortName(), $mark->getOfficialName(), $mark->getMinimumLevel(), $mark->getPassed()
6446  ));
6447  $a_xml_writer->xmlEndTag("qtimetadatafield");
6448  }
6449  $a_xml_writer->xmlEndTag("qtimetadata");
6450 
6451  // add qti objectives
6452  $a_xml_writer->xmlStartTag("objectives");
6453  $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6454  $a_xml_writer->xmlEndTag("objectives");
6455 
6456  // add qti assessmentcontrol
6457  if ($this->getInstantFeedbackSolution() == 1)
6458  {
6459  $attrs = array(
6460  "solutionswitch" => "Yes"
6461  );
6462  }
6463  else
6464  {
6465  $attrs = NULL;
6466  }
6467  $a_xml_writer->xmlElement("assessmentcontrol", $attrs, NULL);
6468 
6469  if (strlen($this->getFinalStatement()))
6470  {
6471  // add qti presentation_material
6472  $a_xml_writer->xmlStartTag("presentation_material");
6473  $a_xml_writer->xmlStartTag("flow_mat");
6474  $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6475  $a_xml_writer->xmlEndTag("flow_mat");
6476  $a_xml_writer->xmlEndTag("presentation_material");
6477  }
6478 
6479  $attrs = array(
6480  "ident" => "1"
6481  );
6482  $a_xml_writer->xmlElement("section", $attrs, NULL);
6483  $a_xml_writer->xmlEndTag("assessment");
6484  $a_xml_writer->xmlEndTag("questestinterop");
6485 
6486  $xml = $a_xml_writer->xmlDumpMem(FALSE);
6487 
6488  foreach ($this->questions as $question_id)
6489  {
6490  $question =& ilObjTest::_instanciateQuestion($question_id);
6491  $qti_question = $question->toXML(false);
6492  $qti_question = preg_replace("/<questestinterop>/", "", $qti_question);
6493  $qti_question = preg_replace("/<\/questestinterop>/", "", $qti_question);
6494  if (strpos($xml, "</section>") !== false)
6495  {
6496  $xml = str_replace("</section>", "$qti_question</section>", $xml);
6497  }
6498  else
6499  {
6500  $xml = str_replace("<section ident=\"1\"/>", "<section ident=\"1\">\n$qti_question</section>", $xml);
6501  }
6502  }
6503  return $xml;
6504  }
6505 
6512  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6513  {
6514  global $ilBench;
6515 
6516  $this->mob_ids = array();
6517  $this->file_ids = array();
6518 
6519  $attrs = array();
6520  $attrs["Type"] = "Test";
6521  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
6522 
6523  // MetaData
6524  $this->exportXMLMetaData($a_xml_writer);
6525 
6526  // PageObjects
6527  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
6528  $ilBench->start("ContentObjectExport", "exportPageObjects");
6529  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6530  $ilBench->stop("ContentObjectExport", "exportPageObjects");
6531  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
6532 
6533  // MediaObjects
6534  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
6535  $ilBench->start("ContentObjectExport", "exportMediaObjects");
6536  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6537  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6538  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
6539 
6540  // FileItems
6541  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
6542  $ilBench->start("ContentObjectExport", "exportFileItems");
6543  $this->exportFileItems($a_target_dir, $expLog);
6544  $ilBench->stop("ContentObjectExport", "exportFileItems");
6545  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
6546 
6547  $a_xml_writer->xmlEndTag("ContentObject");
6548  }
6549 
6556  function exportXMLMetaData(&$a_xml_writer)
6557  {
6558  include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6559  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6560  $md2xml->setExportMode(true);
6561  $md2xml->startExport();
6562  $a_xml_writer->appendXML($md2xml->getXML());
6563  }
6564 
6570  function modifyExportIdentifier($a_tag, $a_param, $a_value)
6571  {
6572  if ($a_tag == "Identifier" && $a_param == "Entry")
6573  {
6574  include_once "./Services/Utilities/classes/class.ilUtil.php";
6575  $a_value = ilUtil::insertInstIntoID($a_value);
6576  }
6577 
6578  return $a_value;
6579  }
6580 
6581 
6588  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6589  {
6590  global $ilBench;
6591 
6592  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6593 
6594  foreach ($this->questions as $question_id)
6595  {
6596  $ilBench->start("ContentObjectExport", "exportPageObject");
6597  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
6598 
6599  $attrs = array();
6600  $a_xml_writer->xmlStartTag("PageObject", $attrs);
6601 
6602 
6603  // export xml to writer object
6604  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6605  include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
6606  $page_object = new ilAssQuestionPage($question_id);
6607  $page_object->buildDom();
6608  $page_object->insertInstIntoIDs($a_inst);
6609  $mob_ids = $page_object->collectMediaObjects(false);
6610  require_once 'Services/COPage/classes/class.ilPCFileList.php';
6611  $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
6612  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6613  $xml = str_replace("&","&amp;", $xml);
6614  $a_xml_writer->appendXML($xml);
6615  $page_object->freeDom();
6616  unset ($page_object);
6617 
6618  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6619 
6620  // collect media objects
6621  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6622  //$mob_ids = $page_obj->getMediaObjectIDs();
6623  foreach($mob_ids as $mob_id)
6624  {
6625  $this->mob_ids[$mob_id] = $mob_id;
6626  }
6627  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6628 
6629  // collect all file items
6630  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6631  //$file_ids = $page_obj->getFileItemIds();
6632  foreach($file_ids as $file_id)
6633  {
6634  $this->file_ids[$file_id] = $file_id;
6635  }
6636  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6637 
6638  $a_xml_writer->xmlEndTag("PageObject");
6639  //unset($page_obj);
6640 
6641  $ilBench->stop("ContentObjectExport", "exportPageObject");
6642 
6643 
6644  }
6645  }
6646 
6653  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6654  {
6655  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6656 
6657  foreach ($this->mob_ids as $mob_id)
6658  {
6659  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
6660  if (ilObjMediaObject::_exists($mob_id))
6661  {
6662  $media_obj = new ilObjMediaObject($mob_id);
6663  $media_obj->exportXML($a_xml_writer, $a_inst);
6664  $media_obj->exportFiles($a_target_dir);
6665  unset($media_obj);
6666  }
6667  }
6668  }
6669 
6674  function exportFileItems($a_target_dir, &$expLog)
6675  {
6676  include_once "./Modules/File/classes/class.ilObjFile.php";
6677 
6678  foreach ($this->file_ids as $file_id)
6679  {
6680  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
6681  $file_obj = new ilObjFile($file_id, false);
6682  $file_obj->export($a_target_dir);
6683  unset($file_obj);
6684  }
6685  }
6686 
6691  function getImportMapping()
6692  {
6693  if (!is_array($this->import_mapping))
6694  {
6695  return array();
6696  }
6697  else
6698  {
6699  return $this->import_mapping;
6700  }
6701  }
6702 
6712  function getECTSGrade($passed_array, $reached_points, $max_points)
6713  {
6714  return ilObjTest::_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);
6715  }
6716 
6725  function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6726  {
6727  include_once "./Modules/Test/classes/class.ilStatistics.php";
6728  // calculate the median
6729  $passed_statistics = new ilStatistics();
6730  $passed_statistics->setData($points_passed);
6731  $ects_percentiles = array
6732  (
6733  "A" => $passed_statistics->quantile($a),
6734  "B" => $passed_statistics->quantile($b),
6735  "C" => $passed_statistics->quantile($c),
6736  "D" => $passed_statistics->quantile($d),
6737  "E" => $passed_statistics->quantile($e)
6738  );
6739  if (count($points_passed) && ($reached_points >= $ects_percentiles["A"]))
6740  {
6741  return "A";
6742  }
6743  else if (count($points_passed) && ($reached_points >= $ects_percentiles["B"]))
6744  {
6745  return "B";
6746  }
6747  else if (count($points_passed) && ($reached_points >= $ects_percentiles["C"]))
6748  {
6749  return "C";
6750  }
6751  else if (count($points_passed) && ($reached_points >= $ects_percentiles["D"]))
6752  {
6753  return "D";
6754  }
6755  else if (count($points_passed) && ($reached_points >= $ects_percentiles["E"]))
6756  {
6757  return "E";
6758  }
6759  else if (strcmp($fx, "") != 0)
6760  {
6761  if ($max_points > 0)
6762  {
6763  $percentage = ($reached_points / $max_points) * 100.0;
6764  if ($percentage < 0) $percentage = 0.0;
6765  }
6766  else
6767  {
6768  $percentage = 0.0;
6769  }
6770  if ($percentage >= $fx)
6771  {
6772  return "FX";
6773  }
6774  else
6775  {
6776  return "F";
6777  }
6778  }
6779  else
6780  {
6781  return "F";
6782  }
6783  }
6784 
6785  function checkMarks()
6786  {
6787  return $this->mark_schema->checkMarks();
6788  }
6789 
6790  function getMarkSchema()
6791  {
6792  return $this->mark_schema;
6793  }
6794 
6802  function setAuthor($author = "")
6803  {
6804  $this->author = $author;
6805  }
6806 
6816  function saveAuthorToMetadata($a_author = "")
6817  {
6818  $md =& new ilMD($this->getId(), 0, $this->getType());
6819  $md_life =& $md->getLifecycle();
6820  if (!$md_life)
6821  {
6822  if (strlen($a_author) == 0)
6823  {
6824  global $ilUser;
6825  $a_author = $ilUser->getFullname();
6826  }
6827 
6828  $md_life =& $md->addLifecycle();
6829  $md_life->save();
6830  $con =& $md_life->addContribute();
6831  $con->setRole("Author");
6832  $con->save();
6833  $ent =& $con->addEntity();
6834  $ent->setEntity($a_author);
6835  $ent->save();
6836  }
6837  }
6838 
6844  function createMetaData()
6845  {
6847  $this->saveAuthorToMetadata();
6848  }
6849 
6857  function getAuthor()
6858  {
6859  $author = array();
6860  include_once "./Services/MetaData/classes/class.ilMD.php";
6861  $md =& new ilMD($this->getId(), 0, $this->getType());
6862  $md_life =& $md->getLifecycle();
6863  if ($md_life)
6864  {
6865  $ids =& $md_life->getContributeIds();
6866  foreach ($ids as $id)
6867  {
6868  $md_cont =& $md_life->getContribute($id);
6869  if (strcmp($md_cont->getRole(), "Author") == 0)
6870  {
6871  $entids =& $md_cont->getEntityIds();
6872  foreach ($entids as $entid)
6873  {
6874  $md_ent =& $md_cont->getEntity($entid);
6875  array_push($author, $md_ent->getEntity());
6876  }
6877  }
6878  }
6879  }
6880  return join($author, ",");
6881  }
6882 
6890  function _lookupAuthor($obj_id)
6891  {
6892  $author = array();
6893  include_once "./Services/MetaData/classes/class.ilMD.php";
6894  $md =& new ilMD($obj_id, 0, "tst");
6895  $md_life =& $md->getLifecycle();
6896  if ($md_life)
6897  {
6898  $ids =& $md_life->getContributeIds();
6899  foreach ($ids as $id)
6900  {
6901  $md_cont =& $md_life->getContribute($id);
6902  if (strcmp($md_cont->getRole(), "Author") == 0)
6903  {
6904  $entids =& $md_cont->getEntityIds();
6905  foreach ($entids as $entid)
6906  {
6907  $md_ent =& $md_cont->getEntity($entid);
6908  array_push($author, $md_ent->getEntity());
6909  }
6910  }
6911  }
6912  }
6913  return join($author, ",");
6914  }
6915 
6922  function &_getAvailableTests($use_object_id = FALSE)
6923  {
6924  global $ilUser;
6925  global $ilDB;
6926 
6927  $result_array = array();
6928  $tests = ilUtil::_getObjectsByOperations("tst","write", $ilUser->getId(), -1);
6929  if (count($tests))
6930  {
6931  $titles = ilObject::_prepareCloneSelection($tests, "tst");
6932  foreach ($tests as $ref_id)
6933  {
6934  if ($use_object_id)
6935  {
6936  $obj_id = ilObject::_lookupObjId($ref_id);
6937  $result_array[$obj_id] = $titles[$ref_id];
6938  }
6939  else
6940  {
6941  $result_array[$ref_id] = $titles[$ref_id];
6942  }
6943  }
6944  }
6945  return $result_array;
6946  }
6947 
6956  public function cloneObject($a_target_id,$a_copy_id = 0)
6957  {
6958  global $ilLog, $tree, $ilDB, $ilPluginAdmin;
6959 
6960  $this->loadFromDb();
6961 
6962  // Copy settings
6964  $newObj = parent::cloneObject($a_target_id,$a_copy_id);
6965  $this->cloneMetaData($newObj);
6966  $newObj->setAnonymity($this->getAnonymity());
6967  $newObj->setAnswerFeedback($this->getAnswerFeedback());
6968  $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
6969  $newObj->setAuthor($this->getAuthor());
6970  $newObj->setAllowedUsers($this->getAllowedUsers());
6971  $newObj->setAllowedUsersTimeGap($this->getAllowedUsersTimeGap());
6972  $newObj->setCountSystem($this->getCountSystem());
6973  $newObj->setECTSFX($this->getECTSFX());
6974  $newObj->setECTSGrades($this->getECTSGrades());
6975  $newObj->setECTSOutput($this->getECTSOutput());
6976  $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
6977  $newObj->setEndingTime($this->getEndingTime());
6978  $newObj->setFixedParticipants($this->getFixedParticipants());
6979  $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
6980  $newObj->setIntroduction($this->getIntroduction());
6981  $newObj->setFinalStatement($this->getFinalStatement());
6982  $newObj->setShowInfo($this->getShowInfo());
6983  $newObj->setForceJS($this->getForceJS());
6984  $newObj->setCustomStyle($this->getCustomStyle());
6985  $newObj->setKiosk($this->getKiosk());
6986  $newObj->setShowFinalStatement($this->getShowFinalStatement());
6987  $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
6988  $newObj->setMCScoring($this->getMCScoring());
6989  $newObj->setMailNotification($this->getMailNotification());
6990  $newObj->setMailNotificationType($this->getMailNotificationType());
6991  $newObj->setNrOfTries($this->getNrOfTries());
6992  $newObj->setPassScoring($this->getPassScoring());
6993  $newObj->setPassword($this->getPassword());
6994  $newObj->setProcessingTime($this->getProcessingTime());
6995  $newObj->setQuestionSetType($this->getQuestionSetType());
6996  $newObj->setReportingDate($this->getReportingDate());
6997  $newObj->setResetProcessingTime($this->getResetProcessingTime());
6998  $newObj->setResultsPresentation($this->getResultsPresentation());
6999  $newObj->setScoreCutting($this->getScoreCutting());
7000  $newObj->setScoreReporting($this->getScoreReporting());
7001  $newObj->setSequenceSettings($this->getSequenceSettings());
7002  $newObj->setShowCancel($this->getShowCancel());
7003  $newObj->setShowMarker($this->getShowMarker());
7004  $newObj->setShuffleQuestions($this->getShuffleQuestions());
7005  $newObj->setStartingTime($this->getStartingTime());
7006  $newObj->setTitleOutput($this->getTitleOutput());
7007  $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
7008  $newObj->setRedirectionMode($this->getRedirectionMode());
7009  $newObj->setRedirectionUrl($this->getRedirectionUrl());
7010  $newObj->setCertificateVisibility($this->getCertificateVisibility());
7011  $newObj->mark_schema = clone $this->mark_schema;
7012  $newObj->setEnabledViewMode($this->getEnabledViewMode());
7013  $newObj->setTemplate($this->getTemplate());
7014  $newObj->setPoolUsage($this->getPoolUsage());
7015  $newObj->setPrintBestSolutionWithResult($this->isBestSolutionPrintedWithResult());
7016  $newObj->setShowExamIdInTestPassEnabled($this->isShowExamIdInTestPassEnabled());
7017  $newObj->setShowExamIdInTestResultsEnabled($this->isShowExamIdInTestResultsEnabled());
7018  $newObj->setEnableExamView($this->getEnableExamview());
7019  $newObj->setShowExamViewHtml($this->getShowExamviewHtml());
7020  $newObj->setShowExamViewPdf($this->getShowExamviewPdf());
7021  $newObj->setEnableArchiving($this->getEnableArchiving());
7022  $newObj->setSignSubmission($this->getSignSubmission());
7023  $newObj->setCharSelectorAvailability((int)$this->getCharSelectorAvailability());
7024  $newObj->setCharSelectorDefinition($this->getCharSelectorDefinition());
7025  $newObj->saveToDb();
7026 
7027  // clone certificate
7028  include_once "./Services/Certificate/classes/class.ilCertificate.php";
7029  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
7030  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
7031  $newcert = new ilCertificate(new ilTestCertificateAdapter($newObj));
7032  $cert->cloneCertificate($newcert);
7033 
7034  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
7035  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory($tree, $ilDB, $ilPluginAdmin, $this);
7036  $testQuestionSetConfigFactory->getQuestionSetConfig()->cloneQuestionSetRelatedData($newObj);
7037 
7038  $newObj->saveToDb();
7039  $newObj->updateMetaData();// #14467
7040  return $newObj;
7041  }
7042 
7049  function getQuestionCount()
7050  {
7051  $num = 0;
7052 
7053  if( $this->isRandomTest() )
7054  {
7055  global $tree, $ilDB, $ilPluginAdmin;
7056 
7057  $questionSetConfig = new ilTestRandomQuestionSetConfig(
7058  $tree, $ilDB, $ilPluginAdmin, $this
7059  );
7060 
7061  $questionSetConfig->loadFromDb();
7062 
7063  if( $questionSetConfig->isQuestionAmountConfigurationModePerPool() )
7064  {
7065  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php';
7066  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetBuilderWithAmountPerPool.php';
7067  require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php';
7068 
7069  $srcPoolDefFactory = new ilTestRandomQuestionSetSourcePoolDefinitionFactory($ilDB, $this);
7070  $srcPoolDefList = new ilTestRandomQuestionSetSourcePoolDefinitionList($ilDB, $this, $srcPoolDefFactory);
7071  $srcPoolDefList->loadDefinitions();
7072  $num = ilTestRandomQuestionSetBuilderWithAmountPerPool::getRequiredQuestionAmountForDefinitionList($srcPoolDefList);
7073  }
7074  else
7075  {
7076  $num = $questionSetConfig->getQuestionAmountPerTest();
7077  }
7078  }
7079  else
7080  {
7081  $num = count($this->questions);
7082  }
7083 
7084  return $num;
7085  }
7086 
7094  function logAction($logtext = "", $question_id = "")
7095  {
7096  global $ilUser;
7097 
7098  $original_id = "";
7099  if (strcmp($question_id, "") != 0)
7100  {
7101  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7102  $original_id = assQuestion::_getOriginalId($question_id);
7103  }
7104  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7105  ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, TRUE, $this->getRefId());
7106  }
7107 
7116  {
7117  global $ilDB;
7118  $object_id = FALSE;
7119  $result = $ilDB->queryF("SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7120  array('integer'),
7121  array($test_id)
7122  );
7123  if ($result->numRows())
7124  {
7125  $row = $ilDB->fetchAssoc($result);
7126  $object_id = $row["obj_fi"];
7127  }
7128  return $object_id;
7129  }
7130 
7138  function _getObjectIDFromActiveID($active_id)
7139  {
7140  global $ilDB;
7141  $object_id = FALSE;
7142  $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",
7143  array('integer'),
7144  array($active_id)
7145  );
7146  if ($result->numRows())
7147  {
7148  $row = $ilDB->fetchAssoc($result);
7149  $object_id = $row["obj_fi"];
7150  }
7151  return $object_id;
7152  }
7153 
7161  function _getTestIDFromObjectID($object_id)
7162  {
7163  global $ilDB;
7164  $test_id = FALSE;
7165  $result = $ilDB->queryF("SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7166  array('integer'),
7167  array($object_id)
7168  );
7169  if ($result->numRows())
7170  {
7171  $row = $ilDB->fetchAssoc($result);
7172  $test_id = $row["test_id"];
7173  }
7174  return $test_id;
7175  }
7176 
7185  function getTextAnswer($active_id, $question_id, $pass = NULL)
7186  {
7187  global $ilDB;
7188 
7189  $res = "";
7190  if (($active_id) && ($question_id))
7191  {
7192  if (is_null($pass))
7193  {
7194  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7195  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7196  }
7197  $result = $ilDB->queryF("SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7198  array('integer', 'integer', 'integer'),
7199  array($active_id, $question_id, $pass)
7200  );
7201  if ($result->numRows() == 1)
7202  {
7203  $row = $ilDB->fetchAssoc($result);
7204  $res = $row["value1"];
7205  }
7206  }
7207  return $res;
7208  }
7209 
7217  function getQuestiontext($question_id)
7218  {
7219  global $ilDB;
7220 
7221  $res = "";
7222  if ($question_id)
7223  {
7224  $result = $ilDB->queryF("SELECT question_text FROM qpl_questions WHERE question_id = %s",
7225  array('integer'),
7226  array($question_id)
7227  );
7228  if ($result->numRows() == 1)
7229  {
7230  $row = $ilDB->fetchAssoc($result);
7231  $res = $row["question_text"];
7232  }
7233  }
7234  return $res;
7235  }
7236 
7243  function &getInvitedUsers($user_id="", $order="login, lastname, firstname")
7244  {
7245  global $ilDB;
7246 
7247  $result_array = array();
7248 
7249  if ($this->getAnonymity())
7250  {
7251  if (is_numeric($user_id))
7252  {
7253  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7254  "tst_active.submitted test_finished, matriculation FROM usr_data, tst_invited_user " .
7255  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7256  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7257  "ORDER BY $order",
7258  array('text', 'text', 'text', 'integer', 'integer'),
7259  array("", $this->lng->txt("unknown"), "", $this->getTestId(), $user_id)
7260  );
7261  }
7262  else
7263  {
7264  $result = $ilDB->queryF("SELECT tst_active.active_id, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
7265  "tst_active.submitted test_finished, matriculation FROM usr_data, tst_invited_user " .
7266  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7267  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7268  "ORDER BY $order",
7269  array('text', 'text', 'text', 'integer'),
7270  array("", $this->lng->txt("unknown"), "", $this->getTestId())
7271  );
7272  }
7273  }
7274  else
7275  {
7276  if (is_numeric($user_id))
7277  {
7278  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7279  "tst_active.submitted test_finished, matriculation FROM usr_data, tst_invited_user " .
7280  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7281  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7282  "ORDER BY $order",
7283  array('integer', 'integer'),
7284  array($this->getTestId(), $user_id)
7285  );
7286  }
7287  else
7288  {
7289  $result = $ilDB->queryF("SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7290  "tst_active.submitted test_finished, matriculation FROM usr_data, tst_invited_user " .
7291  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7292  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7293  "ORDER BY $order",
7294  array('integer'),
7295  array($this->getTestId())
7296  );
7297  }
7298  }
7299  $result_array = array();
7300  while ($row = $ilDB->fetchAssoc($result))
7301  {
7302  $result_array[$row['usr_id']]= $row;
7303  }
7304  return $result_array;
7305  }
7306 
7314  {
7315  global $ilDB;
7316 
7317  if ($this->getAnonymity())
7318  {
7319  $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 ".
7320  "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),
7321  array('text', 'text', 'text', 'integer'),
7322  array("", $this->lng->txt("unknown"), "", $this->getTestId())
7323  );
7324  }
7325  else
7326  {
7327  $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 ".
7328  "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),
7329  array('integer'),
7330  array($this->getTestId())
7331  );
7332  }
7333  $data = array();
7334  while ($row = $ilDB->fetchAssoc($result))
7335  {
7336  $data[$row['active_id']] = $row;
7337  }
7338  foreach ($data as $index => $participant)
7339  {
7340  if (strlen(trim($participant["firstname"].$participant["lastname"])) == 0)
7341  {
7342  $data[$index]["lastname"] = $this->lng->txt("deleted_user");
7343  }
7344  }
7345  return $data;
7346  }
7347 
7348  public function getTestParticipantsForManualScoring($filter = NULL)
7349  {
7350  global $ilDB;
7351 
7352  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7354  if (count($scoring) == 0) return array();
7355 
7356  $participants =& $this->getTestParticipants();
7357  $filtered_participants = array();
7358  foreach ($participants as $active_id => $participant)
7359  {
7360  $qstType_IN_manScoreableQstTypes = $ilDB->in('qpl_questions.question_type_fi', $scoring, false, 'integer');
7361 
7362  $queryString = "
7363  SELECT tst_test_result.manual
7364 
7365  FROM tst_test_result
7366 
7367  INNER JOIN qpl_questions
7368  ON tst_test_result.question_fi = qpl_questions.question_id
7369 
7370  WHERE tst_test_result.active_fi = %s
7371  AND $qstType_IN_manScoreableQstTypes
7372  ";
7373 
7374  $result = $ilDB->queryF(
7375  $queryString, array("integer"), array($active_id)
7376  );
7377 
7378  $count = $result->numRows();
7379 
7380  if ($count > 0)
7381  {
7382  switch ($filter)
7383  {
7384  case 1: // only active users
7385  if ($participant->active) $filtered_participants[$active_id] = $participant;
7386  break;
7387  case 2: // only inactive users
7388  if (!$participant->active) $filtered_participants[$active_id] = $participant;
7389  break;
7390  case 3: // all users
7391  $filtered_participants[$active_id] = $participant;
7392  break;
7393  case 4:
7394  // already scored participants
7395  //$found = 0;
7396  //while ($row = $ilDB->fetchAssoc($result))
7397  //{
7398  // if ($row["manual"]) $found++;
7399  //}
7400  //if ($found == $count)
7401  //{
7402  //$filtered_participants[$active_id] = $participant;
7403  //}
7404  //else
7405  //{
7406  $assessmentSetting = new ilSetting("assessment");
7407  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7408  if ($manscoring_done) $filtered_participants[$active_id] = $participant;
7409  //}
7410  break;
7411  case 5:
7412  // unscored participants
7413  //$found = 0;
7414  //while ($row = $ilDB->fetchAssoc($result))
7415  //{
7416  // if ($row["manual"]) $found++;
7417  //}
7418  //if ($found == 0)
7419  //{
7420  $assessmentSetting = new ilSetting("assessment");
7421  $manscoring_done = $assessmentSetting->get("manscoring_done_" . $active_id);
7422  if (!$manscoring_done) $filtered_participants[$active_id] = $participant;
7423  //}
7424  break;
7425  case 6:
7426  // partially scored participants
7427  $found = 0;
7428  while ($row = $ilDB->fetchAssoc($result))
7429  {
7430  if ($row["manual"]) $found++;
7431  }
7432  if (($found > 0) && ($found < $count)) $filtered_participants[$active_id] = $participant;
7433  break;
7434  default:
7435  $filtered_participants[$active_id] = $participant;
7436  break;
7437  }
7438  }
7439  }
7440  return $filtered_participants;
7441  }
7442 
7450  function &getUserData($ids)
7451  {
7452  global $ilDB;
7453 
7454  if (!is_array($ids) || count($ids) ==0) return array();
7455 
7456  if ($this->getAnonymity())
7457  {
7458  $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",
7459  array('text', 'text', 'text'),
7460  array("", $this->lng->txt("unknown"), "")
7461  );
7462  }
7463  else
7464  {
7465  $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");
7466  }
7467 
7468  $result_array = array();
7469  while ($row = $ilDB->fetchAssoc($result))
7470  {
7471  $result_array[$row["usr_id"]]= $row;
7472  }
7473  return $result_array;
7474  }
7475 
7476  function &getGroupData($ids)
7477  {
7478  if (!is_array($ids) || count($ids) ==0) return array();
7479  $result = array();
7480  foreach ($ids as $ref_id)
7481  {
7482  $obj_id = ilObject::_lookupObjId($ref_id);
7483  $result[$ref_id] = array("ref_id" => $ref_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7484  }
7485  return $result;
7486  }
7487 
7488  function &getRoleData($ids)
7489  {
7490  if (!is_array($ids) || count($ids) ==0) return array();
7491  $result = array();
7492  foreach ($ids as $obj_id)
7493  {
7494  $result[$obj_id] = array("obj_id" => $obj_id, "title" => ilObject::_lookupTitle($obj_id), "description" => ilObject::_lookupDescription($obj_id));
7495  }
7496  return $result;
7497  }
7498 
7499 
7506  function inviteGroup($group_id)
7507  {
7508  include_once "./Modules/Group/classes/class.ilObjGroup.php";
7509  $group = new ilObjGroup($group_id);
7510  $members = $group->getGroupMemberIds();
7511  include_once './Services/User/classes/class.ilObjUser.php';
7512  foreach ($members as $user_id)
7513  {
7514  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7515  }
7516  }
7517 
7524  function inviteRole($role_id)
7525  {
7526  global $rbacreview;
7527  $members = $rbacreview->assignedUsers($role_id,"usr_id");
7528  include_once './Services/User/classes/class.ilObjUser.php';
7529  foreach ($members as $user_id)
7530  {
7531  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7532  }
7533  }
7534 
7535 
7536 
7543  function disinviteUser($user_id)
7544  {
7545  global $ilDB;
7546 
7547  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7548  array('integer', 'integer'),
7549  array($this->getTestId(), $user_id)
7550  );
7551  }
7552 
7559  function inviteUser($user_id, $client_ip="")
7560  {
7561  global $ilDB;
7562 
7563  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7564  array('integer', 'integer'),
7565  array($this->getTestId(), $user_id)
7566  );
7567  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
7568  array('integer', 'integer', 'text', 'integer'),
7569  array($this->getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : NULL, time())
7570  );
7571  }
7572 
7573 
7574  function setClientIP($user_id, $client_ip)
7575  {
7576  global $ilDB;
7577 
7578  $affectedRows = $ilDB->manipulateF("UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
7579  array('text', 'integer', 'integer', 'integer'),
7580  array((strlen($client_ip)) ? $client_ip : NULL, time(), $this->getTestId(), $user_id)
7581  );
7582  }
7583 
7589  function _getSolvedQuestions($active_id, $question_fi = null)
7590  {
7591  global $ilDB;
7592  if (is_numeric($question_fi))
7593  {
7594  $result = $ilDB->queryF("SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
7595  array('integer', 'integer'),
7596  array($active_id, $question_fi)
7597  );
7598  }
7599  else
7600  {
7601  $result = $ilDB->queryF("SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
7602  array('integer'),
7603  array($active_id)
7604  );
7605  }
7606  $result_array = array();
7607  while ($row = $ilDB->fetchAssoc($result))
7608  {
7609  $result_array[$row["question_fi"]]= $row;
7610  }
7611  return $result_array;
7612  }
7613 
7614 
7618  function setQuestionSetSolved($value, $question_id, $user_id)
7619  {
7620  global $ilDB;
7621 
7622  $active_id = $this->getActiveIdOfUser($user_id);
7623  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
7624  array('integer', 'integer'),
7625  array($active_id, $question_id)
7626  );
7627  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
7628  array('integer', 'integer', 'integer'),
7629  array($value, $question_id, $active_id)
7630  );
7631  }
7632 
7636  function isTestFinished($active_id)
7637  {
7638  global $ilDB;
7639 
7640  $result = $ilDB->queryF("SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
7641  array('integer', 'integer'),
7642  array($active_id, 1)
7643  );
7644  return $result->numRows() == 1;
7645  }
7646 
7650  function isActiveTestSubmitted($user_id = null)
7651  {
7652  global $ilUser;
7653  global $ilDB;
7654 
7655  if (!is_numeric($user_id))
7656  $user_id = $ilUser->getId();
7657 
7658  $result = $ilDB->queryF("SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
7659  array('integer', 'integer', 'integer'),
7660  array($this->getTestId(), $user_id, 1)
7661  );
7662  return $result->numRows() == 1;
7663  }
7664 
7669  {
7670  return $this->getNrOfTries() != 0;
7671  }
7672 
7673 
7679  function isNrOfTriesReached($tries)
7680  {
7681  return $tries >= (int) $this->getNrOfTries();
7682  }
7683 
7684 
7693  function getAllTestResults($participants, $prepareForCSV = true)
7694  {
7695  $results = array();
7696  $row = array(
7697  "user_id" => $this->lng->txt("user_id"),
7698  "matriculation" => $this->lng->txt("matriculation"),
7699  "lastname" => $this->lng->txt("lastname"),
7700  "firstname" => $this->lng->txt("firstname"),
7701  "login" =>$this->lng->txt("login"),
7702  "reached_points" => $this->lng->txt("tst_reached_points"),
7703  "max_points" => $this->lng->txt("tst_maximum_points"),
7704  "percent_value" => $this->lng->txt("tst_percent_solved"),
7705  "mark" => $this->lng->txt("tst_mark"),
7706  "ects" => $this->lng->txt("ects_grade")
7707  );
7708  $results[] = $row;
7709  if (count($participants))
7710  {
7711  if ($this->ects_output)
7712  {
7713  $passed_array =& $this->getTotalPointsPassedArray();
7714  }
7715  foreach ($participants as $active_id => $user_rec)
7716  {
7717  $row = array();
7718  $reached_points = 0;
7719  $max_points = 0;
7720  foreach ($this->questions as $value)
7721  {
7722  $question =& ilObjTest::_instanciateQuestion($value);
7723  if (is_object($question))
7724  {
7725  $max_points += $question->getMaximumPoints();
7726  $reached_points += $question->getReachedPoints($active_id);
7727  }
7728  }
7729  if ($max_points > 0)
7730  {
7731  $percentvalue = $reached_points / $max_points;
7732  if ($percentvalue < 0) $percentvalue = 0.0;
7733  }
7734  else
7735  {
7736  $percentvalue = 0;
7737  }
7738  $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
7739  $passed = "";
7740  if ($mark_obj)
7741  {
7742  $mark = $mark_obj->getOfficialName();
7743  $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
7744  }
7745  if ($this->getAnonymity())
7746  {
7747  $user_rec['firstname'] = "";
7748  $user_rec['lastname'] = $this->lng->txt("unknown");
7749  }
7750  $row = array(
7751  "user_id"=>$user_rec['usr_id'],
7752  "matriculation" => $user_rec['matriculation'],
7753  "lastname" => $user_rec['lastname'],
7754  "firstname" => $user_rec['firstname'],
7755  "login"=>$user_rec['login'],
7756  "reached_points" => $reached_points,
7757  "max_points" => $max_points,
7758  "percent_value" => $percentvalue,
7759  "mark" => $mark,
7760  "ects" => $ects_mark
7761  );
7762  $results[] = $prepareForCSV ? $this->processCSVRow ($row, true) : $row;
7763  }
7764  }
7765  return $results;
7766  }
7767 
7778  function &processCSVRow($row, $quoteAll = FALSE, $separator = ";")
7779  {
7780  $resultarray = array();
7781  foreach ($row as $rowindex => $entry)
7782  {
7783  $surround = FALSE;
7784  if ($quoteAll)
7785  {
7786  $surround = TRUE;
7787  }
7788  if (strpos($entry, "\"") !== FALSE)
7789  {
7790  $entry = str_replace("\"", "\"\"", $entry);
7791  $surround = TRUE;
7792  }
7793  if (strpos($entry, $separator) !== FALSE)
7794  {
7795  $surround = TRUE;
7796  }
7797  // replace all CR LF with LF (for Excel for Windows compatibility
7798  $entry = str_replace(chr(13).chr(10), chr(10), $entry);
7799 
7800  if ($surround)
7801  {
7802  $entry = "\"" . $entry . "\"";
7803  }
7804 
7805  $resultarray[$rowindex] = $entry;
7806  }
7807  return $resultarray;
7808  }
7809 
7818  function _getPass($active_id)
7819  {
7820  global $ilDB;
7821  $result = $ilDB->queryF("SELECT tries FROM tst_active WHERE active_id = %s",
7822  array('integer'),
7823  array($active_id)
7824  );
7825  if ($result->numRows())
7826  {
7827  $row = $ilDB->fetchAssoc($result);
7828  return $row["tries"];
7829  }
7830  else
7831  {
7832  return 0;
7833  }
7834  }
7835 
7845  function _getMaxPass($active_id)
7846  {
7847  global $ilDB;
7848  $result = $ilDB->queryF("SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s",
7849  array('integer'),
7850  array($active_id)
7851  );
7852  if ($result->numRows())
7853  {
7854  $row = $ilDB->fetchAssoc($result);
7855  $max = $row["maxpass"];
7856  }
7857  else
7858  {
7859  $max = NULL;
7860  }
7861  return $max;
7862  }
7863 
7874  function _getBestPass($active_id)
7875  {
7876  global $ilDB;
7877 
7878  $result = $ilDB->queryF("SELECT * FROM tst_pass_result WHERE active_fi = %s",
7879  array('integer'),
7880  array($active_id)
7881  );
7882  if ($result->numRows())
7883  {
7884  $bestrow = null;
7885  $bestfactor = 0;
7886  while ($row = $ilDB->fetchAssoc($result))
7887  {
7888  if($row["maxpoints"] > 0)
7889  {
7890  $factor = $row["points"] / $row["maxpoints"];
7891  }
7892  else
7893  {
7894  $factor = 0;
7895  }
7896 
7897  if($factor > $bestfactor)
7898  {
7899  $bestrow = $row;
7900  $bestfactor = $factor;
7901  }
7902  }
7903  if (is_array($bestrow))
7904  {
7905  return $bestrow["pass"];
7906  }
7907  else
7908  {
7909  return 0;
7910  }
7911  }
7912  else
7913  {
7914  return 0;
7915  }
7916  }
7917 
7926  function _getResultPass($active_id)
7927  {
7928  $counted_pass = NULL;
7929  if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS)
7930  {
7931  $counted_pass = ilObjTest::_getBestPass($active_id);
7932  }
7933  else
7934  {
7935  $counted_pass = ilObjTest::_getMaxPass($active_id);
7936  }
7937  return $counted_pass;
7938  }
7939 
7949  function getAnsweredQuestionCount($active_id, $pass = NULL)
7950  {
7951  if( $this->isDynamicTest() )
7952  {
7953  global $tree, $ilDB, $lng, $ilPluginAdmin;
7954 
7955  require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
7956  $testSessionFactory = new ilTestSessionFactory($this);
7957  $testSession = $testSessionFactory->getSession($active_id);
7958 
7959  require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
7960  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this);
7961  $testSequence = $testSequenceFactory->getSequence($testSession);
7962 
7963  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
7964  $dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this);
7965  $dynamicQuestionSetConfig->loadFromDb();
7966 
7967  $testSequence->loadFromDb($dynamicQuestionSetConfig);
7968  $testSequence->loadQuestions($dynamicQuestionSetConfig, new ilTestDynamicQuestionSetFilterSelection());
7969 
7970  return $testSequence->getTrackedQuestionCount();
7971  }
7972 
7973  if ($this->isRandomTest())
7974  {
7975  $this->loadQuestions($active_id, $pass);
7976  }
7977  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7978  $workedthrough = 0;
7979  foreach ($this->questions as $value)
7980  {
7981  if (assQuestion::_isWorkedThrough($active_id, $value, $pass))
7982  {
7983  $workedthrough += 1;
7984  }
7985  }
7986  return $workedthrough;
7987  }
7988 
7998  function getPassFinishDate($active_id, $pass)
7999  {
8000  global $ilDB;
8001  if (is_null($pass)) $pass = 0;
8002  $result = $ilDB->queryF("SELECT tst_test_result.tstamp FROM tst_test_result WHERE active_fi = %s AND pass = %s ORDER BY tst_test_result.tstamp DESC",
8003  array('integer', 'integer'),
8004  array($active_id, $pass)
8005  );
8006  if ($result->numRows())
8007  {
8008  $row = $ilDB->fetchAssoc($result);
8009  return $row["tstamp"];
8010  }
8011  else
8012  {
8013  return 0;
8014  }
8015  }
8016 
8025  function isExecutable($testSession, $user_id, $allowPassIncrease = FALSE)
8026  {
8027  $result = array(
8028  "executable" => true,
8029  "errormessage" => ""
8030  );
8031  if (!$this->startingTimeReached())
8032  {
8033  $result["executable"] = false;
8034  $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilFormat::ftimestamp2datetimeDB($this->getStartingTime()));
8035  return $result;
8036  }
8037  if ($this->endingTimeReached())
8038  {
8039  $result["executable"] = false;
8040  $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilFormat::ftimestamp2datetimeDB($this->getEndingTime()));
8041  return $result;
8042  }
8043 
8044  $active_id = $this->getActiveIdOfUser($user_id);
8045 
8046  if ($this->getEnableProcessingTime())
8047  {
8048  if ($active_id > 0)
8049  {
8050  $starting_time = $this->getStartingTimeOfUser($active_id);
8051  if ($starting_time !== FALSE)
8052  {
8053  if ($this->isMaxProcessingTimeReached($starting_time, $active_id))
8054  {
8055  if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > ($this->_getPass($active_id)+1))))
8056  {
8057  // a test pass was quitted because the maximum processing time was reached, but the time
8058  // will be resetted for future passes, so if there are more passes allowed, the participant may
8059  // start the test again.
8060  // This code block is only called when $allowPassIncrease is TRUE which only happens when
8061  // the test info page is opened. Otherwise this will lead to unexpected results!
8062  $testSession->increasePass();
8063  $testSession->setLastSequence(0);
8064  $testSession->saveToDb();
8065  }
8066  else
8067  {
8068  $result["executable"] = false;
8069  $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8070  }
8071  return $result;
8072  }
8073  }
8074  }
8075  }
8076 
8077  if ($this->hasNrOfTriesRestriction() && ($active_id > 0))
8078  {
8079  require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
8080  $testPassesSelector = new ilTestPassesSelector($GLOBALS['ilDB'], $this);
8081  $testPassesSelector->setActiveId($active_id);
8082  $testPassesSelector->setLastFinishedPass($testSession->getLastFinishedPass());
8083 
8084  $closedPasses = $testPassesSelector->getClosedPasses();
8085 
8086  if( count($closedPasses) >= $this->getNrOfTries() )
8087  {
8088  $result["executable"] = false;
8089  $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8090  return $result;
8091  }
8092  }
8093 
8094  return $result;
8095  }
8096 
8103  function canViewResults()
8104  {
8105  $result = true;
8106  if ($this->getScoreReporting() == 4) return false;
8107  if ($this->getReportingDate())
8108  {
8109  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
8110  {
8111  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8112  $now = mktime();
8113  if ($now < $epoch_time)
8114  {
8115  $result = false;
8116  }
8117  }
8118  }
8119  return $result;
8120  }
8121 
8122  function canShowTestResults($testSession, $user_id)
8123  {
8124  $active_id = $this->getActiveIdOfUser($user_id);
8125  if ($active_id > 0)
8126  {
8127  $starting_time = $this->getStartingTimeOfUser($active_id);
8128  }
8129  $notimeleft = FALSE;
8130  if ($starting_time !== FALSE)
8131  {
8132  if ($this->isMaxProcessingTimeReached($starting_time, $active_id))
8133  {
8134  $notimeleft = TRUE;
8135  }
8136  }
8137  $result = TRUE;
8138  if (!$this->isTestFinishedToViewResults($active_id, $testSession->getPass()) && ($this->getScoreReporting() == REPORT_AFTER_TEST))
8139  {
8140  $result = FALSE;
8141  }
8142  if (($this->endingTimeReached()) || $notimeleft) $result = TRUE;
8143  $result = $result & $this->canViewResults();
8144  return $result;
8145  }
8146 
8147  function canEditMarks()
8148  {
8149  $total = $this->evalTotalPersons();
8150  if ($total > 0)
8151  {
8152  if ($this->getReportingDate())
8153  {
8154  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
8155  {
8156  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8157  $now = mktime();
8158  if ($now < $epoch_time)
8159  {
8160  return true;
8161  }
8162  }
8163  }
8164  return false;
8165  }
8166  else
8167  {
8168  return true;
8169  }
8170  }
8171 
8179  function getStartingTimeOfUser($active_id, $pass = null)
8180  {
8181  global $ilDB;
8182 
8183  if ($active_id < 1) return FALSE;
8184  if($pass === null)
8185  {
8186  $pass = ($this->getResetProcessingTime()) ? $this->_getPass($active_id) : 0;
8187  }
8188  $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",
8189  array('integer', 'integer'),
8190  array($active_id, $pass)
8191  );
8192  if ($result->numRows())
8193  {
8194  $row = $ilDB->fetchAssoc($result);
8195  if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches))
8196  {
8197  return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8198  }
8199  else
8200  {
8201  return mktime();
8202  }
8203  }
8204  else
8205  {
8206  return mktime();
8207  }
8208  }
8209 
8219  {
8220  if ($this->getEnableProcessingTime())
8221  {
8222  $processing_time = $this->getProcessingTimeInSeconds($active_id);
8223  $now = mktime();
8224  if ($now > ($starting_time + $processing_time))
8225  {
8226  return TRUE;
8227  }
8228  else
8229  {
8230  return FALSE;
8231  }
8232  }
8233  else
8234  {
8235  return FALSE;
8236  }
8237  }
8238 
8239  function &getTestQuestions()
8240  {
8241  global $ilDB;
8242 
8243  $query = "
8244  SELECT questions.*,
8245  questtypes.type_tag,
8246  tstquest.sequence,
8247  tstquest.obligatory,
8248  origquest.obj_fi orig_obj_fi
8249 
8250  FROM qpl_questions questions
8251 
8252  INNER JOIN qpl_qst_type questtypes
8253  ON questtypes.question_type_id = questions.question_type_fi
8254 
8255  INNER JOIN tst_test_question tstquest
8256  ON tstquest.question_fi = questions.question_id
8257 
8258  LEFT JOIN qpl_questions origquest
8259  ON origquest.question_id = questions.original_id
8260 
8261  WHERE tstquest.test_fi = %s
8262 
8263  ORDER BY tstquest.sequence
8264  ";
8265 
8266  $query_result = $ilDB->queryF(
8267  $query, array('integer'), array($this->getTestId())
8268  );
8269 
8270  $questions = array();
8271 
8272  while ($row = $ilDB->fetchAssoc($query_result))
8273  {
8274  $question = $row;
8275 
8276  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8277 
8278  $questions[] = $question;
8279  }
8280 
8281  return $questions;
8282  }
8283 
8287  public function getPotentialRandomTestQuestions()
8288  {
8292  global $ilDB;
8293 
8294  $query = "
8295  SELECT questions.*,
8296  questtypes.type_tag,
8297  origquest.obj_fi orig_obj_fi
8298 
8299  FROM qpl_questions questions
8300 
8301  INNER JOIN qpl_qst_type questtypes
8302  ON questtypes.question_type_id = questions.question_type_fi
8303 
8304  INNER JOIN tst_rnd_cpy tstquest
8305  ON tstquest.qst_fi = questions.question_id
8306 
8307  LEFT JOIN qpl_questions origquest
8308  ON origquest.question_id = questions.original_id
8309 
8310  WHERE tstquest.tst_fi = %s
8311  ";
8312 
8313  $query_result = $ilDB->queryF(
8314  $query, array('integer'), array($this->getTestId())
8315  );
8316 
8317  $questions = array();
8318 
8319  while ($row = $ilDB->fetchAssoc($query_result))
8320  {
8321  $question = $row;
8322 
8323  $question['obligationPossible'] = self::isQuestionObligationPossible($row['question_id']);
8324 
8325  $questions[] = $question;
8326  }
8327 
8328  return $questions;
8329  }
8330 
8338  {
8339  return ($this->shuffle_questions) ? 1 : 0;
8340  }
8341 
8348  function setShuffleQuestions($a_shuffle)
8349  {
8350  $this->shuffle_questions = ($a_shuffle) ? 1 : 0;
8351  }
8352 
8366  {
8367  return ($this->show_summary) ? $this->show_summary : 0;
8368  }
8369 
8382  function setListOfQuestionsSettings($a_value = 0)
8383  {
8384  $this->show_summary = $a_value;
8385  }
8386 
8394  {
8395  if (($this->show_summary & 1) > 0)
8396  {
8397  return TRUE;
8398  }
8399  else
8400  {
8401  return FALSE;
8402  }
8403  }
8404 
8411  function setListOfQuestions($a_value = TRUE)
8412  {
8413  if ($a_value)
8414  {
8415  $this->show_summary = 1;
8416  }
8417  else
8418  {
8419  $this->show_summary = 0;
8420  }
8421  }
8422 
8430  {
8431  if (($this->show_summary & 2) > 0)
8432  {
8433  return TRUE;
8434  }
8435  else
8436  {
8437  return FALSE;
8438  }
8439  }
8440 
8447  function setListOfQuestionsStart($a_value = TRUE)
8448  {
8449  if ($a_value && $this->getListOfQuestions())
8450  {
8451  $this->show_summary = $this->show_summary | 2;
8452  }
8453  if (!$a_value && $this->getListOfQuestions())
8454  {
8455  if ($this->getListOfQuestionsStart())
8456  {
8457  $this->show_summary = $this->show_summary ^ 2;
8458  }
8459  }
8460  }
8461 
8469  {
8470  if (($this->show_summary & 4) > 0)
8471  {
8472  return TRUE;
8473  }
8474  else
8475  {
8476  return FALSE;
8477  }
8478  }
8479 
8486  function setListOfQuestionsEnd($a_value = TRUE)
8487  {
8488  if ($a_value && $this->getListOfQuestions())
8489  {
8490  $this->show_summary = $this->show_summary | 4;
8491  }
8492  if (!$a_value && $this->getListOfQuestions())
8493  {
8494  if ($this->getListOfQuestionsEnd())
8495  {
8496  $this->show_summary = $this->show_summary ^ 4;
8497  }
8498  }
8499  }
8500 
8508  {
8509  if (($this->show_summary & 8) > 0)
8510  {
8511  return TRUE;
8512  }
8513  else
8514  {
8515  return FALSE;
8516  }
8517  }
8518 
8525  function setListOfQuestionsDescription($a_value = TRUE)
8526  {
8527  if ($a_value && $this->getListOfQuestions())
8528  {
8529  $this->show_summary = $this->show_summary | 8;
8530  }
8531  if (!$a_value && $this->getListOfQuestions())
8532  {
8533  if ($this->getListOfQuestionsDescription())
8534  {
8535  $this->show_summary = $this->show_summary ^ 8;
8536  }
8537  }
8538  }
8539 
8547  {
8548  return ($this->results_presentation) ? $this->results_presentation : 0;
8549  }
8550 
8558  {
8559  if (($this->results_presentation & 1) > 0)
8560  {
8561  return TRUE;
8562  }
8563  else
8564  {
8565  return FALSE;
8566  }
8567  }
8568 
8576  {
8577  if (($this->results_presentation & 2) > 0)
8578  {
8579  return TRUE;
8580  }
8581  else
8582  {
8583  return FALSE;
8584  }
8585  }
8586 
8594  {
8595  if (($this->results_presentation & 4) > 0)
8596  {
8597  return TRUE;
8598  }
8599  else
8600  {
8601  return FALSE;
8602  }
8603  }
8604 
8612  {
8613  if (($this->results_presentation & 8) > 0)
8614  {
8615  return TRUE;
8616  }
8617  else
8618  {
8619  return FALSE;
8620  }
8621  }
8622 
8630  {
8631  if (($this->results_presentation & 16) > 0)
8632  {
8633  return TRUE;
8634  }
8635  else
8636  {
8637  return FALSE;
8638  }
8639  }
8640 
8648  {
8649  if (($this->results_presentation & 32) > 0)
8650  {
8651  return TRUE;
8652  }
8653  else
8654  {
8655  return FALSE;
8656  }
8657  }
8658 
8664  {
8665  if (($this->results_presentation & 64) > 0)
8666  {
8667  return TRUE;
8668  }
8669  else
8670  {
8671  return FALSE;
8672  }
8673  }
8674 
8680  {
8681  if(($this->results_presentation & 128) > 0)
8682  {
8683  return TRUE;
8684  }
8685  else
8686  {
8687  return FALSE;
8688  }
8689  }
8690 
8697  function setResultsPresentation($a_results_presentation = 3)
8698  {
8699  $this->results_presentation = $a_results_presentation;
8700  }
8701 
8710  function setShowPassDetails($a_details = 1)
8711  {
8712  if ($a_details)
8713  {
8714  $this->results_presentation = $this->results_presentation | 1;
8715  }
8716  else
8717  {
8718  if ($this->getShowPassDetails())
8719  {
8720  $this->results_presentation = $this->results_presentation ^ 1;
8721  }
8722  }
8723  }
8724 
8731  function setShowSolutionDetails($a_details = 1)
8732  {
8733  if ($a_details)
8734  {
8735  $this->results_presentation = $this->results_presentation | 2;
8736  }
8737  else
8738  {
8739  if ($this->getShowSolutionDetails())
8740  {
8741  $this->results_presentation = $this->results_presentation ^ 2;
8742  }
8743  }
8744  }
8745 
8752  function canShowSolutionPrintview($user_id = NULL)
8753  {
8754  return $this->getShowSolutionPrintview();
8755  }
8756 
8763  function setShowSolutionPrintview($a_printview = 1)
8764  {
8765  if ($a_printview)
8766  {
8767  $this->results_presentation = $this->results_presentation | 4;
8768  }
8769  else
8770  {
8771  if ($this->getShowSolutionPrintview())
8772  {
8773  $this->results_presentation = $this->results_presentation ^ 4;
8774  }
8775  }
8776  }
8777 
8784  function setShowSolutionFeedback($a_feedback = TRUE)
8785  {
8786  if ($a_feedback)
8787  {
8788  $this->results_presentation = $this->results_presentation | 8;
8789  }
8790  else
8791  {
8792  if ($this->getShowSolutionFeedback())
8793  {
8794  $this->results_presentation = $this->results_presentation ^ 8;
8795  }
8796  }
8797  }
8798 
8805  function setShowSolutionAnswersOnly($a_full = TRUE)
8806  {
8807  if ($a_full)
8808  {
8809  $this->results_presentation = $this->results_presentation | 16;
8810  }
8811  else
8812  {
8813  if ($this->getShowSolutionAnswersOnly())
8814  {
8815  $this->results_presentation = $this->results_presentation ^ 16;
8816  }
8817  }
8818  }
8819 
8826  function setShowSolutionSignature($a_signature = FALSE)
8827  {
8828  if ($a_signature)
8829  {
8830  $this->results_presentation = $this->results_presentation | 32;
8831  }
8832  else
8833  {
8834  if ($this->getShowSolutionSignature())
8835  {
8836  $this->results_presentation = $this->results_presentation ^ 32;
8837  }
8838  }
8839  }
8840 
8847  function setShowSolutionSuggested($a_solution = FALSE)
8848  {
8849  if ($a_solution)
8850  {
8851  $this->results_presentation = $this->results_presentation | 64;
8852  }
8853  else
8854  {
8855  if ($this->getShowSolutionSuggested())
8856  {
8857  $this->results_presentation = $this->results_presentation ^ 64;
8858  }
8859  }
8860  }
8861 
8867  public function setShowSolutionListComparison($a_comparison = FALSE)
8868  {
8869  if($a_comparison)
8870  {
8871  $this->results_presentation = $this->results_presentation | 128;
8872  }
8873  else
8874  {
8875  if($this->getShowSolutionListComparison())
8876  {
8877  $this->results_presentation = $this->results_presentation ^ 128;
8878  }
8879  }
8880  }
8881 
8882  public static function _getUserIdFromActiveId($active_id)
8883  {
8884  global $ilDB;
8885  $result = $ilDB->queryF("SELECT user_fi FROM tst_active WHERE active_id = %s",
8886  array('integer'),
8887  array($active_id)
8888  );
8889  if ($result->numRows())
8890  {
8891  $row = $ilDB->fetchAssoc($result);
8892  return $row["user_fi"];
8893  }
8894  else
8895  {
8896  return -1;
8897  }
8898  }
8899 
8900  function getAllowedUsers()
8901  {
8902  return ($this->allowedUsers) ? $this->allowedUsers : 0;
8903  }
8904 
8905  function setAllowedUsers($a_allowed_users)
8906  {
8907  $this->allowedUsers = $a_allowed_users;
8908  }
8909 
8911  {
8912  return ($this->allowedUsersTimeGap) ? $this->allowedUsersTimeGap : 0;
8913  }
8914 
8915  function setAllowedUsersTimeGap($a_allowed_users_time_gap)
8916  {
8917  $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
8918  }
8919 
8921  {
8922  global $ilDB;
8923 
8924  $nr_of_users = $this->getAllowedUsers();
8925  $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
8926  if (($nr_of_users > 0) && ($time_gap > 0))
8927  {
8928  $now = mktime();
8929  $time_border = $now - $time_gap;
8930  $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
8931  $result = $ilDB->queryF("SELECT DISTINCT tst_times.active_fi FROM tst_times, tst_active WHERE tst_times.tstamp > %s AND tst_times.active_fi = tst_active.active_id AND tst_active.test_fi = %s",
8932  array('integer', 'integer'),
8933  array($time_border, $this->getTestId())
8934  );
8935  if ($result->numRows() >= $nr_of_users)
8936  {
8937  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
8939  {
8940  $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
8941  }
8942  return FALSE;
8943  }
8944  else
8945  {
8946  return TRUE;
8947  }
8948  }
8949  return TRUE;
8950  }
8951 
8952  function _getLastAccess($active_id)
8953  {
8954  global $ilDB;
8955 
8956  $result = $ilDB->queryF("SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
8957  array('integer'),
8958  array($active_id)
8959  );
8960  if ($result->numRows())
8961  {
8962  $row = $ilDB->fetchAssoc($result);
8963  return $row["finished"];
8964  }
8965  return "";
8966  }
8967 
8975  function isHTML($a_text)
8976  {
8977  if (preg_match("/<[^>]*?>/", $a_text))
8978  {
8979  return TRUE;
8980  }
8981  else
8982  {
8983  return FALSE;
8984  }
8985  }
8986 
8994  function QTIMaterialToString($a_material)
8995  {
8996  $result = "";
8997  for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
8998  {
8999  $material = $a_material->getMaterial($i);
9000  if (strcmp($material["type"], "mattext") == 0)
9001  {
9002  $result .= $material["material"]->getContent();
9003  }
9004  if (strcmp($material["type"], "matimage") == 0)
9005  {
9006  $matimage = $material["material"];
9007  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
9008  {
9009  // import an mediaobject which was inserted using tiny mce
9010  if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
9011  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
9012  }
9013  }
9014  }
9015  global $ilLog;
9016  $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
9017  return $result;
9018  }
9019 
9028  function addQTIMaterial(&$a_xml_writer, $a_material)
9029  {
9030  include_once "./Services/RTE/classes/class.ilRTE.php";
9031  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9032 
9033  $a_xml_writer->xmlStartTag("material");
9034  $attrs = array(
9035  "texttype" => "text/plain"
9036  );
9037  if ($this->isHTML($a_material))
9038  {
9039  $attrs["texttype"] = "text/xhtml";
9040  }
9041  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
9042 
9043  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9044  foreach ($mobs as $mob)
9045  {
9046  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9047  if (strpos($a_material, "mm_$mob") !== FALSE)
9048  {
9049  if (ilObjMediaObject::_exists($mob))
9050  {
9051  $mob_obj =& new ilObjMediaObject($mob);
9052  $imgattrs = array(
9053  "label" => $moblabel,
9054  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9055  );
9056  }
9057  $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
9058  }
9059  }
9060  $a_xml_writer->xmlEndTag("material");
9061  }
9062 
9069  function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE)
9070  {
9071  include_once "./Services/Utilities/classes/class.ilUtil.php";
9072  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output);
9073  }
9074 
9081  function saveCertificateVisibility($a_value)
9082  {
9083  global $ilDB;
9084 
9085  $affectedRows = $ilDB->manipulateF("UPDATE tst_tests SET certificate_visibility = %s, tstamp = %s WHERE test_id = %s",
9086  array('text', 'integer', 'integer'),
9087  array($a_value, time(), $this->getTestId())
9088  );
9089  }
9090 
9098  {
9099  return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0;
9100  }
9101 
9108  function setCertificateVisibility($a_value)
9109  {
9110  $this->certificate_visibility = $a_value;
9111  }
9112 
9119  function getAnonymity()
9120  {
9121  return ($this->anonymity) ? 1 : 0;
9122  }
9123 
9130  function setAnonymity($a_value = 0)
9131  {
9132  switch ($a_value)
9133  {
9134  case 1:
9135  $this->anonymity = 1;
9136  break;
9137  default:
9138  $this->anonymity = 0;
9139  break;
9140  }
9141  }
9142 
9149  function getShowCancel()
9150  {
9151  return ($this->show_cancel) ? 1 : 0;
9152  }
9153 
9160  function setShowCancel($a_value = 1)
9161  {
9162  switch ($a_value)
9163  {
9164  case 1:
9165  $this->show_cancel = 1;
9166  break;
9167  default:
9168  $this->show_cancel = 0;
9169  break;
9170  }
9171  }
9172 
9179  function getShowMarker()
9180  {
9181  return ($this->show_marker) ? 1 : 0;
9182  }
9183 
9190  function setShowMarker($a_value = 1)
9191  {
9192  switch ($a_value)
9193  {
9194  case 1:
9195  $this->show_marker = 1;
9196  break;
9197  default:
9198  $this->show_marker = 0;
9199  break;
9200  }
9201  }
9202 
9210  {
9211  return ($this->fixed_participants) ? 1 : 0;
9212  }
9213 
9220  function setFixedParticipants($a_value = 1)
9221  {
9222  switch ($a_value)
9223  {
9224  case 1:
9225  $this->fixed_participants = 1;
9226  break;
9227  default:
9228  $this->fixed_participants = 0;
9229  break;
9230  }
9231  }
9232 
9240  function _lookupAnonymity($a_obj_id)
9241  {
9242  global $ilDB;
9243 
9244  $result = $ilDB->queryF("SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
9245  array('integer'),
9246  array($a_obj_id)
9247  );
9248  while($row = $ilDB->fetchAssoc($result))
9249  {
9250  return $row['anonymity'];
9251  }
9252  return 0;
9253  }
9254 
9261  public static function lookupQuestionSetTypeByActiveId($active_id)
9262  {
9263  global $ilDB;
9264 
9265  $query = "
9266  SELECT tst_tests.question_set_type
9267  FROM tst_active
9268  INNER JOIN tst_tests
9269  ON tst_active.test_fi = tst_tests.test_id
9270  WHERE tst_active.active_id = %s
9271  ";
9272 
9273  $res = $ilDB->queryF( $query, array('integer'), array($active_id) );
9274 
9275  while($row = $ilDB->fetchAssoc($res))
9276  {
9277  return $row['question_set_type'];
9278  }
9279 
9280  return null;
9281  }
9282 
9291  function _lookupRandomTestFromActiveId($active_id)
9292  {
9293  throw new Exception(__METHOD__.' is deprecated ... use ilObjTest::lookupQuestionSetTypeByActiveId() instead!');
9294 
9295  global $ilDB;
9296 
9297  $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",
9298  array('integer'),
9299  array($active_id)
9300  );
9301  while($row = $ilDB->fetchAssoc($result))
9302  {
9303  return $row['random_test'];
9304  }
9305  return 0;
9306  }
9307 
9316  function userLookupFullName($user_id, $overwrite_anonymity = FALSE, $sorted_order = FALSE, $suffix = "")
9317  {
9318  if ($this->getAnonymity() && !$overwrite_anonymity)
9319  {
9320  return $this->lng->txt("unknown") . $suffix;
9321  }
9322  else
9323  {
9324  include_once './Services/User/classes/class.ilObjUser.php';
9325  $uname = ilObjUser::_lookupName($user_id);
9326  if (strlen($uname["firstname"].$uname["lastname"]) == 0) $uname["firstname"] = $this->lng->txt("deleted_user");
9327  if ($sorted_order)
9328  {
9329  return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9330  }
9331  else
9332  {
9333  return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9334  }
9335  }
9336  }
9337 
9345  function getStartTestLabel($active_id)
9346  {
9347  if ($this->getNrOfTries() == 1)
9348  {
9349  return $this->lng->txt("tst_start_test");
9350  }
9351  $active_pass = $this->_getPass($active_id);
9352  $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9353  if ($res == 0)
9354  {
9355  if ($active_pass == 0)
9356  {
9357  return $this->lng->txt("tst_start_test");
9358  }
9359  else
9360  {
9361  return $this->lng->txt("tst_start_new_test_pass");
9362  }
9363  }
9364  else
9365  {
9366  return $this->lng->txt("tst_resume_test");
9367  }
9368  }
9369 
9375  public function getAvailableDefaults()
9376  {
9381  global $ilDB, $ilUser;
9382 
9383  $result = $ilDB->queryF(
9384  "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
9385  array('integer'),
9386  array($ilUser->getId())
9387  );
9388  $defaults = array();
9389  while($row = $ilDB->fetchAssoc($result))
9390  {
9391  $defaults[$row["test_defaults_id"]] = $row;
9392  }
9393  return $defaults;
9394  }
9395 
9403  function &getTestDefaults($test_defaults_id)
9404  {
9405  return self::_getTestDefaults($test_defaults_id);
9406  }
9407 
9408  public static function _getTestDefaults($test_defaults_id)
9409  {
9410  global $ilDB;
9411 
9412  $result = $ilDB->queryF("SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9413  array('integer'),
9414  array($test_defaults_id)
9415  );
9416  if ($result->numRows() == 1)
9417  {
9418  $row = $ilDB->fetchAssoc($result);
9419  return $row;
9420  }
9421  else
9422  {
9423  return NULL;
9424  }
9425  }
9426 
9433  function deleteDefaults($test_default_id)
9434  {
9435  global $ilDB;
9436  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9437  array('integer'),
9438  array($test_default_id)
9439  );
9440  }
9441 
9448  function addDefaults($a_name)
9449  {
9450  global $ilDB;
9451  global $ilUser;
9452  $testsettings = array(
9453  "TitleOutput" => $this->getTitleOutput(),
9454  "PassScoring" => $this->getPassScoring(),
9455  "Introduction" => $this->getIntroduction(),
9456  "FinalStatement" => $this->getFinalStatement(),
9457  "ShowInfo" => $this->getShowInfo(),
9458  "ForceJS" => $this->getForceJS(),
9459  "CustomStyle" => $this->getCustomStyle(),
9460  "ShowFinalStatement" => $this->getShowFinalStatement(),
9461  "SequenceSettings" => $this->getSequenceSettings(),
9462  "ScoreReporting" => $this->getScoreReporting(),
9463  "ScoreCutting" => $this->getScoreCutting(),
9464  'SpecificAnswerFeedback' => $this->getSpecificAnswerFeedback(),
9465  'PrintBsWithRes' => (int)$this->isBestSolutionPrintedWithResult(),
9466  "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9467  "AnswerFeedback" => $this->getAnswerFeedback(),
9468  "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9469  "ResultsPresentation" => $this->getResultsPresentation(),
9470  "Anonymity" => $this->getAnonymity(),
9471  "ShowCancel" => $this->getShowCancel(),
9472  "ShowMarker" => $this->getShowMarker(),
9473  "ReportingDate" => $this->getReportingDate(),
9474  "NrOfTries" => $this->getNrOfTries(),
9475  "Shuffle" => $this->getShuffleQuestions(),
9476  "Kiosk" => $this->getKiosk(),
9477  "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9478  "ProcessingTime" => $this->getProcessingTime(),
9479  "EnableProcessingTime" => $this->getEnableProcessingTime(),
9480  "ResetProcessingTime" => $this->getResetProcessingTime(),
9481  "StartingTime" => $this->getStartingTime(),
9482  "EndingTime" => $this->getEndingTime(),
9483  "ECTSOutput" => $this->getECTSOutput(),
9484  "ECTSFX" => $this->getECTSFX(),
9485  "ECTSGrades" => $this->getECTSGrades(),
9486  "questionSetType" => $this->getQuestionSetType(),
9487  "CountSystem" => $this->getCountSystem(),
9488  "MCScoring" => $this->getMCScoring(),
9489  "mailnotification" => $this->getMailNotification(),
9490  "mailnottype" => $this->getMailNotificationType(),
9491  "exportsettings" => $this->getExportSettings(),
9492  "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings(),
9493  'obligations_enabled' => (int)$this->areObligationsEnabled(),
9494  'offer_question_hints' => (int)$this->isOfferingQuestionHintsEnabled(),
9495  'pass_deletion_allowed' => (int)$this->isPassDeletionAllowed(),
9496  'enable_examview' => $this->getEnableExamview(),
9497  'show_examview_html' => $this->getShowExamviewHtml(),
9498  'show_examview_pdf' => $this->getShowExamviewPdf(),
9499  'char_selector_availability' => $this->getCharSelectorAvailability(),
9500  'char_selector_definition' => $this->getCharSelectorDefinition(),
9501  'redirection_mode' => $this->getRedirectionMode(),
9502  'redirection_url' => $this->getRedirectionUrl(),
9503  'sign_submission' => $this->getSignSubmission(),
9504  'autosave' => (int)$this->getAutosave(),
9505  'autosave_ival' => (int)$this->getAutosaveIval(),
9506  'examid_in_test_pass' => (int)$this->isShowExamIdInTestPassEnabled(),
9507  'examid_in_test_res' => (int)$this->isShowExamIdInTestResultsEnabled(),
9508 
9509  'enable_archiving' => (int)$this->getEnableArchiving(),
9510  'password' => (string)$this->getPassword(),
9511  'fixed_participants' => $this->getFixedParticipants(),
9512  'allowedusers' => $this->getAllowedUsers(),
9513  'alloweduserstimegap' => $this->getAllowedUsersTimeGap(),
9514  'pool_usage' => $this->getPoolUsage(),
9515  'activation_limited' => $this->isActivationLimited(),
9516  'activation_start_time' => $this->getActivationStartingTime(),
9517  'activation_end_time' => $this->getActivationEndingTime(),
9518  'activation_visibility' => $this->getActivationVisibility(),
9519  'highscore_enabled' => $this->getHighscoreEnabled(),
9520  'highscore_anon' => $this->getHighscoreAnon(),
9521  'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
9522  'highscore_score' => $this->getHighscoreScore(),
9523  'highscore_percentage' => $this->getHighscorePercentage(),
9524  'highscore_hints' => $this->getHighscoreHints(),
9525  'highscore_wtime' => $this->getHighscoreWTime(),
9526  'highscore_own_table' => $this->getHighscoreOwnTable(),
9527  'highscore_top_table' => $this->getHighscoreTopTable(),
9528  'highscore_top_num' => $this->getHighscoreTopNum(),
9529  'use_previous_answers' => (string)$this->getUsePreviousAnswers()
9530  );
9531  $next_id = $ilDB->nextId('tst_test_defaults');
9532  $ilDB->insert(
9533  'tst_test_defaults',
9534  array(
9535  'test_defaults_id' => array('integer', $next_id),
9536  'name' => array('text', $a_name),
9537  'user_fi' => array('integer', $ilUser->getId()),
9538  'defaults' => array('clob', serialize($testsettings)),
9539  'marks' => array('clob', serialize($this->mark_schema)),
9540  'tstamp' => array('integer', time())
9541  )
9542  );
9543  }
9544 
9552  public function applyDefaults($test_defaults)
9553  {
9554  $testsettings = unserialize($test_defaults["defaults"]);
9555  include_once "./Modules/Test/classes/class.assMarkSchema.php";
9556  $this->mark_schema = unserialize($test_defaults["marks"]);
9557 
9558  $this->setTitleOutput($testsettings["TitleOutput"]);
9559  $this->setPassScoring($testsettings["PassScoring"]);
9560  $this->setIntroduction($testsettings["Introduction"]);
9561  $this->setFinalStatement($testsettings["FinalStatement"]);
9562  $this->setShowInfo($testsettings["ShowInfo"]);
9563  $this->setForceJS($testsettings["ForceJS"]);
9564  $this->setCustomStyle($testsettings["CustomStyle"]);
9565  $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
9566  $this->setSequenceSettings($testsettings["SequenceSettings"]);
9567  $this->setScoreReporting($testsettings["ScoreReporting"]);
9568  $this->setScoreCutting($testsettings['ScoreCutting']);
9569  $this->setSpecificAnswerFeedback($testsettings['SpecificAnswerFeedback']);
9570  $this->setPrintBestSolutionWithResult((bool)$testsettings['PrintBsWithRes']);
9571  $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
9572  $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
9573  $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
9574  $this->setResultsPresentation($testsettings["ResultsPresentation"]);
9575  $this->setAnonymity($testsettings["Anonymity"]);
9576  $this->setShowCancel($testsettings["ShowCancel"]);
9577  $this->setShuffleQuestions($testsettings["Shuffle"]);
9578  $this->setShowMarker($testsettings["ShowMarker"]);
9579  $this->setReportingDate($testsettings["ReportingDate"]);
9580  $this->setNrOfTries($testsettings["NrOfTries"]);
9581  $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
9582  $this->setRedirectionMode($testsettings['redirection_mode']);
9583  $this->setRedirectionUrl($testsettings['redirection_url']);
9584  $this->setProcessingTime($testsettings["ProcessingTime"]);
9585  $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
9586  $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
9587  $this->setStartingTime($testsettings["StartingTime"]);
9588  $this->setKiosk($testsettings["Kiosk"]);
9589  $this->setEndingTime($testsettings["EndingTime"]);
9590  $this->setECTSOutput($testsettings["ECTSOutput"]);
9591  $this->setECTSFX($testsettings["ECTSFX"]);
9592  $this->setECTSGrades($testsettings["ECTSGrades"]);
9593  if( isset($testsettings["isRandomTest"]) )
9594  {
9595  if( $testsettings["isRandomTest"] )
9596  {
9597  $this->setQuestionSetType(self::QUESTION_SET_TYPE_RANDOM);
9598  }
9599  else
9600  {
9601  $this->setQuestionSetType(self::QUESTION_SET_TYPE_FIXED);
9602  }
9603  }
9604  elseif( isset($testsettings["questionSetType"]) )
9605  {
9606  $this->setQuestionSetType($testsettings["questionSetType"]);
9607  }
9608  $this->setCountSystem($testsettings["CountSystem"]);
9609  $this->setMCScoring($testsettings["MCScoring"]);
9610  $this->setMailNotification($testsettings["mailnotification"]);
9611  $this->setMailNotificationType($testsettings["mailnottype"]);
9612  $this->setExportSettings($testsettings['exportsettings']);
9613  $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
9614  $this->setObligationsEnabled($testsettings["obligations_enabled"]);
9615  $this->setOfferingQuestionHintsEnabled($testsettings["offer_question_hints"]);
9616  $this->setHighscoreEnabled($testsettings['highscore_enabled']);
9617  $this->setHighscoreAnon($testsettings['highscore_anon']);
9618  $this->setHighscoreAchievedTS($testsettings['highscore_achieved_ts']);
9619  $this->setHighscoreScore($testsettings['highscore_score']);
9620  $this->setHighscorePercentage($testsettings['highscore_percentage']);
9621  $this->setHighscoreHints($testsettings['highscore_hints']);
9622  $this->setHighscoreWTime($testsettings['highscore_wtime']);
9623  $this->setHighscoreOwnTable($testsettings['highscore_own_table']);
9624  $this->setHighscoreTopTable($testsettings['highscore_top_table']);
9625  $this->setHighscoreTopNum($testsettings['highscore_top_num']);
9626  $this->setPassDeletionAllowed($testsettings['pass_deletion_allowed']);
9627  if( isset($testsettings['examid_in_kiosk']) )
9628  {
9629  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_kiosk']);
9630  }
9631  else
9632  {
9633  $this->setShowExamIdInTestPassEnabled($testsettings['examid_in_test_pass']);
9634  }
9635  if( isset($testsettings['show_exam_id']) )
9636  {
9637  $this->setShowExamIdInTestResultsEnabled($testsettings['show_exam_id']);
9638  }
9639  else
9640  {
9641  $this->setShowExamIdInTestResultsEnabled($testsettings['examid_in_test_res']);
9642  }
9643  $this->setEnableExamview($testsettings['enable_examview']);
9644  $this->setShowExamviewHtml($testsettings['show_examview_html']);
9645  $this->setShowExamviewPdf($testsettings['show_examview_pdf']);
9646  $this->setEnableArchiving($testsettings['enable_archiving']);
9647  $this->setSignSubmission($testsettings['sign_submission']);
9648  $this->setCharSelectorAvailability($testsettings['char_selector_availability']);
9649  $this->setCharSelectorDefinition($testsettings['char_selector_definition']);
9650 
9651  $this->setRedirectionMode($testsettings['redirection_mode']);
9652  $this->setRedirectionUrl($testsettings['redirection_url']);
9653 
9654  $this->setAutosave($testsettings['autosave']);
9655  $this->setAutosaveIval($testsettings['autosave_ival']);
9656  $this->setShowExamIdInTestResultsEnabled((int)$testsettings['examid_in_test_res']);
9657  $this->setPassword($testsettings['password']);
9658  $this->setFixedParticipants($testsettings['fixed_participants'] );
9659  $this->setAllowedUsers($testsettings['allowedusers']);
9660  $this->setAllowedUsersTimeGap($testsettings['alloweduserstimegap']);
9661  $this->setUsePreviousAnswers($testsettings['use_previous_answers']);
9662  $this->setPoolUsage($testsettings['pool_usage']);
9663  $this->setActivationLimited($testsettings['activation_limited']);
9664  $this->setActivationStartingTime($testsettings['activation_start_time']);
9665  $this->setActivationEndingTime($testsettings['activation_end_time']);
9666  $this->setActivationVisibility($testsettings['activation_visibility']);
9667 
9668  $this->saveToDb();
9669 
9670  return true;
9671  }
9672 
9680  function processPrintoutput2FO($print_output)
9681  {
9682  if (extension_loaded("tidy"))
9683  {
9684  $config = array(
9685  "indent" => false,
9686  "output-xml" => true,
9687  "numeric-entities" => true
9688  );
9689  $tidy = new tidy();
9690  $tidy->parseString($print_output, $config, 'utf8');
9691  $tidy->cleanRepair();
9692  $print_output = tidy_get_output($tidy);
9693  $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
9694  }
9695  else
9696  {
9697  $print_output = str_replace("&nbsp;", "&#160;", $print_output);
9698  $print_output = str_replace("&otimes;", "X", $print_output);
9699  }
9700  $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
9701 
9702  // additional font support
9703  $xsl = str_replace(
9704  'font-family="Helvetica, unifont"',
9705  'font-family="'.$GLOBALS['ilSetting']->get('rpc_pdf_font','Helvetica, unifont').'"',
9706  $xsl
9707  );
9708 
9709  $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
9710  $xh = xslt_create();
9711  $params = array();
9712  $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", NULL, $args, $params);
9713  xslt_error($xh);
9714  xslt_free($xh);
9715  return $output;
9716  }
9717 
9724  public function deliverPDFfromHTML($content, $title = NULL)
9725  {
9726  $content = preg_replace("/href=\".*?\"/", "", $content);
9727  $printbody = new ilTemplate("tpl.il_as_tst_print_body.html", TRUE, TRUE, "Modules/Test");
9728  $printbody->setVariable("TITLE", ilUtil::prepareFormOutput($this->getTitle()));
9729  $printbody->setVariable("ADM_CONTENT", $content);
9730  $printbody->setCurrentBlock("css_file");
9731  $printbody->setVariable("CSS_FILE", $this->getTestStyleLocation("filesystem"));
9732  $printbody->parseCurrentBlock();
9733  $printbody->setCurrentBlock("css_file");
9734  $printbody->setVariable("CSS_FILE", ilUtil::getStyleSheetLocation("filesystem", "delos.css"));
9735  $printbody->parseCurrentBlock();
9736  $printoutput = $printbody->get();
9737  $html = str_replace("href=\"./", "href=\"" . ILIAS_HTTP_PATH . "/", $printoutput);
9738  $html = preg_replace("/<div id=\"dontprint\">.*?<\\/div>/ims", "", $html);
9739  if (extension_loaded("tidy"))
9740  {
9741  $config = array(
9742  "indent" => false,
9743  "output-xml" => true,
9744  "numeric-entities" => true
9745  );
9746  $tidy = new tidy();
9747  $tidy->parseString($html, $config, 'utf8');
9748  $tidy->cleanRepair();
9749  $html = tidy_get_output($tidy);
9750  $html = preg_replace("/^.*?(<html)/", "\\1", $html);
9751  }
9752  else
9753  {
9754  $html = str_replace("&nbsp;", "&#160;", $html);
9755  $html = str_replace("&otimes;", "X", $html);
9756  }
9757  $html = preg_replace("/src=\".\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html);
9758  $this->deliverPDFfromFO($this->processPrintoutput2FO($html), $title);
9759  }
9760 
9767  public function deliverPDFfromFO($fo, $title = null)
9768  {
9769  global $ilLog;
9770 
9771  include_once "./Services/Utilities/classes/class.ilUtil.php";
9772  $fo_file = ilUtil::ilTempnam() . ".fo";
9773  $fp = fopen($fo_file, "w"); fwrite($fp, $fo); fclose($fp);
9774 
9775  include_once './Services/WebServices/RPC/classes/class.ilRpcClientFactory.php';
9776  try
9777  {
9778  $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo);
9779  $filename = (strlen($title)) ? $title : $this->getTitle();
9780  ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
9781  return true;
9782  }
9783  catch(XML_RPC2_FaultException $e)
9784  {
9785  $ilLog->write(__METHOD__.': '.$e->getMessage());
9786  return false;
9787  }
9788  catch(Exception $e)
9789  {
9790  $ilLog->write(__METHOD__.': '.$e->getMessage());
9791  return false;
9792  }
9793 
9794  /*
9795  include_once "./Services/Transformation/classes/class.ilFO2PDF.php";
9796  $fo2pdf = new ilFO2PDF();
9797  $fo2pdf->setFOString($fo);
9798  $result = $fo2pdf->send();
9799  $filename = (strlen($title)) ? $title : $this->getTitle();
9800  ilUtil::deliverData($result, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
9801  */
9802  }
9803 
9813  static function getManualFeedback($active_id, $question_id, $pass)
9814  {
9815  global $ilDB;
9816  $feedback = "";
9817  $result = $ilDB->queryF("SELECT feedback FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
9818  array('integer', 'integer', 'integer'),
9819  array($active_id, $question_id, $pass)
9820  );
9821  if ($result->numRows())
9822  {
9823  $row = $ilDB->fetchAssoc($result);
9824  include_once("./Services/RTE/classes/class.ilRTE.php");
9825  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
9826  }
9827  return $feedback;
9828  }
9829 
9840  function saveManualFeedback($active_id, $question_id, $pass, $feedback)
9841  {
9842  global $ilDB;
9843 
9844  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
9845  array('integer', 'integer', 'integer'),
9846  array($active_id, $question_id, $pass)
9847  );
9848 
9849  if (strlen($feedback))
9850  {
9851  $next_id = $ilDB->nextId('tst_manual_fb');
9853  $result = $ilDB->insert('tst_manual_fb', array(
9854  'manual_feedback_id' => array( 'integer', $next_id ),
9855  'active_fi' => array( 'integer', $active_id ),
9856  'question_fi' => array( 'integer', $question_id ),
9857  'pass' => array( 'integer', $pass),
9858  'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( $feedback, 0) ),
9859  'tstamp' => array( 'integer', time() ),
9860  )
9861  );
9862  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
9864  {
9865  global $lng, $ilUser;
9866  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
9867  $username = ilObjTestAccess::_getParticipantData($active_id);
9868  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
9869  $this->logAction(sprintf($lng->txtlng("assessment", "log_manual_feedback", ilObjAssessmentFolder::_getLogLanguage()), $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")", $username, assQuestion::_getQuestionTitle($question_id), $feedback));
9870  }
9871  }
9872  if (PEAR::isError($result))
9873  {
9874  global $ilias;
9875  $ilias->raiseError($result->getMessage());
9876  }
9877  else
9878  {
9879  return TRUE;
9880  }
9881  }
9882 
9891  {
9892  global $ilUser;
9893  if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
9894  if ($this->getForceJS()) return TRUE;
9895  $assessmentSetting = new ilSetting("assessment");
9896  return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
9897  }
9898 
9899  function &createTestSequence($active_id, $pass, $shuffle)
9900  {
9901  include_once "./Modules/Test/classes/class.ilTestSequence.php";
9902  $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
9903  }
9904 
9910  public function setTestId($a_id)
9911  {
9912  $this->test_id = $a_id;
9913  }
9914 
9923  function getDetailedTestResults($participants)
9924  {
9925  $results = array();
9926  if (count($participants))
9927  {
9928  foreach ($participants as $active_id => $user_rec)
9929  {
9930  $row = array();
9931  $reached_points = 0;
9932  $max_points = 0;
9933  foreach ($this->questions as $value)
9934  {
9935  $question =& ilObjTest::_instanciateQuestion($value);
9936  if (is_object($question))
9937  {
9938  $max_points += $question->getMaximumPoints();
9939  $reached_points += $question->getReachedPoints($active_id);
9940  if ($max_points > 0)
9941  {
9942  $percentvalue = $reached_points / $max_points;
9943  if ($percentvalue < 0) $percentvalue = 0.0;
9944  }
9945  else
9946  {
9947  $percentvalue = 0;
9948  }
9949  if ($this->getAnonymity())
9950  {
9951  $user_rec['firstname'] = "";
9952  $user_rec['lastname'] = $this->lng->txt("unknown");
9953  }
9954  $row = array(
9955  "user_id"=>$user_rec['usr_id'],
9956  "matriculation" => $user_rec['matriculation'],
9957  "lastname" => $user_rec['lastname'],
9958  "firstname" => $user_rec['firstname'],
9959  "login"=>$user_rec['login'],
9960  "question_id" => $question->getId(),
9961  "question_title" => $question->getTitle(),
9962  "reached_points" => $reached_points,
9963  "max_points" => $max_points
9964  );
9965  $results[] = $row;
9966  }
9967  }
9968  }
9969  }
9970  return $results;
9971  }
9972 
9977  {
9978  global $ilDB;
9979 
9980  $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",
9981  array('integer'),
9982  array($a_q_id)
9983  );
9984  $rec = $ilDB->fetchAssoc($result);
9985  return $rec["obj_id"];
9986  }
9987 
9994  function isPluginActive($a_pname)
9995  {
9996  global $ilPluginAdmin;
9997  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
9998  {
9999  return TRUE;
10000  }
10001  else
10002  {
10003  return FALSE;
10004  }
10005  }
10006 
10007  public function getPassed($active_id)
10008  {
10009  global $ilDB;
10010 
10011  $result = $ilDB->queryF("SELECT passed FROM tst_result_cache WHERE active_fi = %s",
10012  array('integer'),
10013  array($active_id)
10014  );
10015  if ($result->numRows())
10016  {
10017  $row = $ilDB->fetchAssoc($result);
10018  return $row['passed'];
10019  }
10020  else
10021  {
10022  $counted_pass = ilObjTest::_getResultPass($active_id);
10023  $result_array =& $this->getTestResult($active_id, $counted_pass);
10024  return $result_array["test"]["passed"];
10025  }
10026  }
10027 
10033  function canShowCertificate($testSession, $user_id, $active_id)
10034  {
10035  if ($this->canShowTestResults($testSession, $user_id))
10036  {
10037  include_once "./Services/Certificate/classes/class.ilCertificate.php";
10038  include_once "./Modules/Test/classes/class.ilTestCertificateAdapter.php";
10039  $cert = new ilCertificate(new ilTestCertificateAdapter($this));
10040  if ($cert->isComplete())
10041  {
10042  $vis = $this->getCertificateVisibility();
10043  $showcert = FALSE;
10044  switch ($vis)
10045  {
10046  case 0:
10047  $showcert = TRUE;
10048  break;
10049  case 1:
10050  if ($this->getPassed($active_id))
10051  {
10052  $showcert = TRUE;
10053  }
10054  break;
10055  case 2:
10056  $showcert = FALSE;
10057  break;
10058  }
10059  if ($showcert)
10060  {
10061  return TRUE;
10062  }
10063  else
10064  {
10065  return FALSE;
10066  }
10067  }
10068  else
10069  {
10070  return FALSE;
10071  }
10072  }
10073  else
10074  {
10075  return FALSE;
10076  }
10077  }
10078 
10082  public function getParticipantsForTestAndQuestion($test_id, $question_id)
10083  {
10085  global $ilDB;
10086 
10087  $query = "
10088  SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
10089  FROM tst_test_result, tst_active, qpl_questions
10090  WHERE tst_active.active_id = tst_test_result.active_fi
10091  AND tst_active.test_fi = %s
10092  AND tst_test_result.question_fi = qpl_questions.question_id
10093  AND tst_test_result.question_fi = %s";
10094 
10095  $result = $ilDB->queryF($query,
10096  array('integer', 'integer'),
10097  array($test_id, $question_id)
10098  );
10099  $foundusers = array();
10101  while ($row = $ilDB->fetchAssoc($result))
10102  {
10103  if (!array_key_exists($row["active_fi"], $foundusers))
10104  {
10105  $foundusers[$row["active_fi"]] = array();
10106  }
10107  array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10108  }
10109  return $foundusers;
10110  }
10111 
10117  public function getAggregatedResultsData()
10118  {
10119  $data =& $this->getCompleteEvaluationData();
10120  $foundParticipants =& $data->getParticipants();
10121  $results = array("overview" => array(), "questions" => array());
10122  if (count($foundParticipants))
10123  {
10124  $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10125  $total_finished = $this->evalTotalFinished();
10126  $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10127  $average_time = $this->evalTotalStartedAverageTime();
10128  $diff_seconds = $average_time;
10129  $diff_hours = floor($diff_seconds/3600);
10130  $diff_seconds -= $diff_hours * 3600;
10131  $diff_minutes = floor($diff_seconds/60);
10132  $diff_seconds -= $diff_minutes * 60;
10133  $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10134  $total_passed = 0;
10135  $total_passed_reached = 0;
10136  $total_passed_max = 0;
10137  $total_passed_time = 0;
10138  foreach ($foundParticipants as $userdata)
10139  {
10140  if ($userdata->getPassed())
10141  {
10142  $total_passed++;
10143  $total_passed_reached += $userdata->getReached();
10144  $total_passed_max += $userdata->getMaxpoints();
10145  $total_passed_time += $userdata->getTimeOfWork();
10146  }
10147  }
10148  $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10149  $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10150  $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10151  $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10152  $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);
10153  $average_time = $average_passed_time;
10154  $diff_seconds = $average_time;
10155  $diff_hours = floor($diff_seconds/3600);
10156  $diff_seconds -= $diff_hours * 3600;
10157  $diff_minutes = floor($diff_seconds/60);
10158  $diff_seconds -= $diff_minutes * 60;
10159  $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10160  }
10161 
10162  foreach ($data->getQuestionTitles() as $question_id => $question_title)
10163  {
10164  $answered = 0;
10165  $reached = 0;
10166  $max = 0;
10167  foreach ($foundParticipants as $userdata)
10168  {
10169  for ($i = 0; $i <= $userdata->getLastPass(); $i++)
10170  {
10171  if (is_object($userdata->getPass($i)))
10172  {
10173  $question =& $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10174  if (is_array($question))
10175  {
10176  $answered++;
10177  $reached += $question["reached"];
10178  $max += $question["points"];
10179  }
10180  }
10181  }
10182  }
10183  $percent = $max ? $reached/$max * 100.0 : 0;
10184  $counter++;
10185  $results["questions"][$question_id] = array(
10186  $question_title,
10187  sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10188  sprintf("%.2f", $percent) . "%",
10189  $answered,
10190  sprintf("%.2f", $answered ? $reached / $answered : 0),
10191  sprintf("%.2f", $answered ? $max / $answered : 0),
10192  $percent / 100.0
10193  );
10194  }
10195  return $results;
10196  }
10197 
10201  function getXMLZip()
10202  {
10203  include_once("./Modules/Test/classes/class.ilTestExport.php");
10204  $test_exp = new ilTestExport($this, "xml");
10205  return $test_exp->buildExportFile();
10206  }
10207 
10211  public function getMailNotification()
10212  {
10213  return $this->mailnotification;
10214  }
10215 
10221  public function setMailNotification($a_notification)
10222  {
10223  $this->mailnotification = $a_notification;
10224  }
10225 
10226  public function sendSimpleNotification($active_id)
10227  {
10228  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10229 
10230  $mail = new ilTestMailNotification();
10231  $owner_id = $this->getOwner();
10232  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10233  $mail->sendSimpleNotification($owner_id, $this->getTitle(), $usr_data);
10234  }
10235 
10242  {
10243  include_once "./Modules/Test/classes/class.ilObjTestGUI.php";
10244  include_once "./Modules/Test/classes/tables/class.ilEvaluationAllTableGUI.php";
10245  $table_gui = new ilEvaluationAllTableGUI(new ilObjTestGUI(), 'outEvaluation', $this->getAnonymity());
10246  return $table_gui->getSelectedColumns();
10247  }
10248 
10249  public function sendAdvancedNotification($active_id)
10250  {
10251  include_once "./Modules/Test/classes/class.ilTestMailNotification.php";
10252 
10253  $mail = new ilTestMailNotification();
10254  $owner_id = $this->getOwner();
10255  $usr_data = $this->userLookupFullName(ilObjTest::_getUserIdFromActiveId($active_id));
10256 
10257  include_once "./Modules/Test/classes/class.ilTestExport.php";
10258  $exportObj = new ilTestExport($this, "results");
10259  $file = $exportObj->exportToExcel($deliver = FALSE, 'active_id', $active_id, $passedonly = FALSE);
10260  include_once "./Services/Mail/classes/class.ilFileDataMail.php";
10261  $fd = new ilFileDataMail(ANONYMOUS_USER_ID);
10262  $fd->copyAttachmentFile($file, "result_" . $active_id . ".xls");
10263  $file_names[] = "result_" . $active_id . ".xls";
10264 
10265  $mail->sendAdvancedNotification($owner_id, $this->getTitle(), $usr_data, $file_names);
10266 
10267  if(count($file_names))
10268  {
10269  $fd->unlinkFiles($file_names);
10270  unset($fd);
10271  @unlink($file);
10272  }
10273  }
10274 
10275  function createRandomSolutions($number)
10276  {
10277  global $ilDB;
10278 
10279  // 1. get a user
10280  $query = "SELECT usr_id FROM usr_data";
10281  $result = $ilDB->query($query);
10282  while ($data = $ilDB->fetchAssoc($result))
10283  {
10284  $activequery = sprintf("SELECT user_fi FROM tst_active WHERE test_fi = %s AND user_fi = %s",
10285  $ilDB->quote($this->getTestId()),
10286  $ilDB->quote($data['usr_id'])
10287  );
10288  $activeresult = $ilDB->query($activequery);
10289  if ($activeresult->numRows() == 0)
10290  {
10291  $user_id = $data['usr_id'];
10292  if ($user_id != 13)
10293  {
10294  include_once "./Modules/Test/classes/class.ilTestSession.php";
10295  $testSession = FALSE;
10296  $testSession = new ilTestSession();
10297  $testSession->setRefId($this->getRefId());
10298  $testSession->setTestId($this->getTestId());
10299  $testSession->setUserId($user_id);
10300  $testSession->saveToDb();
10301  $passes = ($this->getNrOfTries()) ? $this->getNrOfTries() : 10;
10302  $nr_of_passes = rand(1, $passes);
10303  $active_id = $testSession->getActiveId();
10304  for ($pass = 0; $pass < $nr_of_passes; $pass++)
10305  {
10306  include_once "./Modules/Test/classes/class.ilTestSequence.php";
10307  $testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
10308  if (!$testSequence->hasSequence())
10309  {
10310  $testSequence->createNewSequence($this->getQuestionCount(), $shuffle);
10311  $testSequence->saveToDb();
10312  }
10313  for ($seq = 1; $seq <= count($this->questions); $seq++)
10314  {
10315  $question_id = $testSequence->getQuestionForSequence($seq);
10316  $objQuestion = ilObjTest::_instanciateQuestion($question_id);
10317  $objQuestion->createRandomSolution($testSession->getActiveId(), $pass);
10318  }
10319  if ($pass < $nr_of_passes - 1)
10320  {
10321  $testSession->increasePass();
10322  $testSession->setLastSequence(0);
10323  $testSession->saveToDb();
10324  }
10325  else
10326  {
10327  $testSession->setSubmitted(1);
10328  $testSession->setSubmittedTimestamp(date('Y-m-d H:i:s'));
10329  $testSession->saveToDb();
10330  }
10331  }
10332  $number--;
10333  if ($number == 0) return;
10334  }
10335  }
10336  }
10337  }
10338 
10339  public function getResultsForActiveId($active_id)
10340  {
10341  global $ilDB;
10342 
10343  $query = "
10344  SELECT *
10345  FROM tst_result_cache
10346  WHERE active_fi = %s
10347  ";
10348 
10349  $result = $ilDB->queryF(
10350  $query, array('integer'), array($active_id)
10351  );
10352 
10353  if( !$result->numRows() )
10354  {
10355  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
10356 
10358 
10359  $query = "
10360  SELECT *
10361  FROM tst_result_cache
10362  WHERE active_fi = %s
10363  ";
10364 
10365  $result = $ilDB->queryF(
10366  $query, array('integer'), array($active_id)
10367  );
10368  }
10369 
10370  $row = $ilDB->fetchAssoc($result);
10371 
10372  return $row;
10373 
10374  }
10375 
10376  public function getMailNotificationType()
10377  {
10378  if ($this->mailnottype == 1)
10379  {
10380  return $this->mailnottype;
10381  }
10382  else
10383  {
10384  return 0;
10385  }
10386  }
10387 
10388  public function setMailNotificationType($a_type)
10389  {
10390  if ($a_type == 1)
10391  {
10392  $this->mailnottype = 1;
10393  }
10394  else
10395  {
10396  $this->mailnottype = 0;
10397  }
10398  }
10399 
10400  public function getExportSettings()
10401  {
10402  if ($this->exportsettings)
10403  {
10404  return $this->exportsettings;
10405  }
10406  else
10407  {
10408  return 0;
10409  }
10410  }
10411 
10412  public function setExportSettings($a_settings)
10413  {
10414  if ($a_settings)
10415  {
10416  $this->exportsettings = $a_settings;
10417  }
10418  else
10419  {
10420  $this->exportsettings = 0;
10421  }
10422  }
10423 
10425  {
10426  if (($this->exportsettings & 1) > 0)
10427  {
10428  return true;
10429  }
10430  else
10431  {
10432  return false;
10433  }
10434  }
10435 
10436  public function setExportSettingsSingleChoiceShort($a_settings)
10437  {
10438  if ($a_settings)
10439  {
10440  $this->exportsettings = $this->exportsettings | 1;
10441  }
10442  else
10443  {
10445  {
10446  $this->exportsettings = $this->exportsettings ^ 1;
10447  }
10448  }
10449  }
10450 
10451  public function getEnabledViewMode() {
10452  return $this->enabled_view_mode;
10453  }
10454 
10455  public function setEnabledViewMode($mode) {
10456  $this->enabled_view_mode = $mode;
10457  }
10458 
10460  $this->template_id = (int)$template_id;
10461  }
10462 
10463  function getTemplate() {
10464  return $this->template_id;
10465  }
10466 
10467  public function moveQuestionAfterOLD($previous_question_id, $new_question_id) {
10468  $new_array = array();
10469  $position = 1;
10470 
10471  $query = 'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
10472  $types = array('integer');
10473  $values = array($this->getTestId());
10474 
10475  $new_question_id += 1;
10476 
10477  global $ilDB;
10478  $inserted = false;
10479  $res = $ilDB->queryF($query, $types, $values);
10480  while($row = $ilDB->fetchAssoc($res)) {
10481 
10482  $qid = $row['question_fi'];
10483 
10484  if ($qid == $new_question_id) {
10485  continue;
10486  }
10487  else if ($qid == $previous_question_id) {
10488  $new_array[$position++] = $qid;
10489  $new_array[$position++] = $new_question_id;
10490  $inserted = true;
10491  }
10492  else {
10493  $new_array[$position++] = $qid;
10494  }
10495  }
10496 
10497  $update_query = 'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
10498  $update_types = array('integer', 'integer', 'integer');
10499 
10500  foreach($new_array as $position => $qid) {
10501  $ilDB->manipulateF(
10502  $update_query,
10503  $update_types,
10504  $vals = array(
10505  $position,
10506  $this->getTestId(),
10507  $qid
10508  )
10509  );
10510  }
10511  }
10512 
10514  if (is_array($options))
10515  {
10516  $this->setGenericAnswerFeedback( in_array('instant_feedback_generic', $options) ? 1 : 0);
10517  $this->setSpecificAnswerFeedback( in_array('instant_feedback_specific', $options) ? 1 : 0);
10518  $this->setAnswerFeedbackPoints( in_array('instant_feedback_points', $options) ? 1 : 0);
10519  $this->setInstantFeedbackSolution( in_array('instant_feedback_solution', $options) ? 1 : 0);
10520  } else {
10521  $this->setGenericAnswerFeedback(0);
10522  $this->setSpecificAnswerFeedback(0);
10523  $this->setAnswerFeedbackPoints(0);
10524  $this->setInstantFeedbackSolution(0);
10525  }
10526  }
10527 
10529  $setter = array(
10530  'pass_details' => 'setShowPassDetails',
10531  'solution_details' => 'setShowSolutionDetails',
10532  'solution_printview' => 'setShowSolutionPrintview',
10533  'solution_feedback' => 'setShowSolutionFeedback',
10534  'solution_answers_only' => 'setShowSolutionAnswersOnly',
10535  'solution_signature' => 'setShowSolutionSignature',
10536  'solution_suggested' => 'setShowSolutionSuggested',
10537  );
10538  foreach($setter as $key => $setter) {
10539  if (in_array($key, $options)) {
10540  $this->$setter(1);
10541  }
10542  else {
10543  $this->$setter(0);
10544  }
10545  }
10546  }
10547 
10548  public function getPoolUsage() {
10549  return (boolean) $this->poolUsage;
10550  }
10551 
10552  public function setPoolUsage($usage) {
10553  $this->poolUsage = (boolean)$usage;
10554  }
10555 
10556  public function setQuestionOrderAndObligations($orders, $obligations)
10557  {
10558  global $ilDB;
10559 
10560  asort($orders);
10561 
10562  $i = 0;
10563 
10564  foreach($orders as $id => $position)
10565  {
10566  $i++;
10567 
10568  $obligatory = (
10569  isset($obligations[$id]) && $obligations[$id] ? 1 : 0
10570  );
10571 
10572  $query = "
10573  UPDATE tst_test_question
10574  SET sequence = %s,
10575  obligatory = %s
10576  WHERE question_fi = %s
10577  ";
10578 
10579  $ilDB->manipulateF(
10580  $query, array('integer', 'integer', 'integer'), array($i, $obligatory, $id)
10581  );
10582  }
10583 
10584  $this->loadQuestions();
10585  }
10586 
10587  public function moveQuestionAfter($question_to_move, $question_before) {
10588  global $ilDB;
10589  //var_dump(func_get_args());
10590  if ($question_before) {
10591  $query = 'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
10592  $types = array('integer');
10593  $values = array($question_before);
10594  $rset = $ilDB->queryF($query, $types, $values);
10595  }
10596 
10597  if (!$question_before || ($rset && !($row = $ilDB->fetchAssoc($rset)))) {
10598  $row = array(
10599  'sequence' => 0,
10600  'test_fi' => $this->getTestId(),
10601  );
10602  }
10603 
10604  $update = 'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
10605  $types = array('integer', 'integer');
10606  $values = array($row['sequence'], $row['test_fi']);
10607  $ilDB->manipulateF($update, $types, $values);
10608 
10609  $update = 'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
10610  $types = array('integer', 'integer');
10611  $values = array($row['sequence'] + 1, $question_to_move);
10612  $ilDB->manipulateF($update, $types, $values);
10613 
10614  }
10615 
10617  {
10618  global $ilDB;
10619 
10621 
10622  $IN_questions = $ilDB->in('q1.question_id', array_keys($questions), false, 'integer');
10623 
10624  $query = "
10625  SELECT count(q1.question_id) cnt
10626 
10627  FROM qpl_questions q1
10628 
10629  INNER JOIN qpl_questions q2
10630  ON q2.question_id = q1.original_id
10631 
10632  WHERE $IN_questions
10633  AND q1.obj_fi = q2.obj_fi
10634  ";
10635 
10636  $rset = $ilDB->query($query);
10637 
10638  $row = $ilDB->fetchAssoc($rset);
10639 
10640  return $row['cnt'] > 0;
10641  }
10642 
10649  public static function _lookupFinishedUserTests($a_user_id)
10650  {
10651  global $ilDB;
10652 
10653  $result = $ilDB->queryF("SELECT test_fi,MAX(pass) AS pass FROM tst_active".
10654  " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)".
10655  " WHERE user_fi=%s".
10656  " GROUP BY test_fi",
10657  array('integer', 'integer'),
10658  array($a_user_id, 1)
10659  );
10660  $all = array();
10661  while($row = $ilDB->fetchAssoc($result))
10662  {
10663  $obj_id = self::_getObjectIDFromTestID($row["test_fi"]);
10664  $all[$obj_id] = (bool)$row["pass"];
10665  }
10666  return $all;
10667  }
10668  public function getQuestions()
10669  {
10670  return $this->questions;
10671  }
10672 
10673  public function isOnline()
10674  {
10675  return $this->online;
10676  }
10677 
10678  public function setOnline($a_online = true)
10679  {
10680  $this->online = (bool)$a_online;
10681  }
10682 
10683  public function setPrintBestSolutionWithResult($status)
10684  {
10685  $this->print_best_solution_with_result = (bool) $status;
10686  }
10687 
10689  {
10691  }
10692 
10699  {
10701  }
10702 
10709  {
10710  $this->offeringQuestionHintsEnabled = (bool)$offeringQuestionHintsEnabled;
10711  }
10712 
10713  function setActivationVisibility($a_value)
10714  {
10715  $this->activation_visibility = (bool) $a_value;
10716  }
10717 
10719  {
10721  }
10722 
10724  {
10725  return (bool)$this->activation_limited;
10726  }
10727 
10728  function setActivationLimited($a_value)
10729  {
10730  $this->activation_limited = (bool)$a_value;
10731  }
10732 
10733  /* GET/SET for highscore feature */
10734 
10740  public function setHighscoreEnabled($a_enabled)
10741  {
10742  $this->_highscore_enabled = (bool)$a_enabled;
10743  }
10744 
10750  public function getHighscoreEnabled()
10751  {
10752  return (bool) $this->_highscore_enabled;
10753  }
10754 
10762  public function setHighscoreAnon($a_anon)
10763  {
10764  $this->_highscore_anon = (bool)$a_anon;
10765  }
10766 
10776  public function getHighscoreAnon()
10777  {
10778  return (bool) $this->_highscore_anon;
10779  }
10780 
10789  public function isHighscoreAnon()
10790  {
10791  if ($this->getAnonymity() == 1)
10792  {
10793  return true;
10794  }
10795  else
10796  {
10797  return (bool)$this->getHighscoreAnon();
10798  }
10799  }
10800 
10806  public function setHighscoreAchievedTS($a_achieved_ts)
10807  {
10808  $this->_highscore_achieved_ts = (bool)$a_achieved_ts;
10809  }
10810 
10816  public function getHighscoreAchievedTS()
10817  {
10818  return (bool) $this->_highscore_achieved_ts;
10819  }
10820 
10826  public function setHighscoreScore($a_score)
10827  {
10828  $this->_highscore_score = (bool)$a_score;
10829  }
10830 
10836  public function getHighscoreScore()
10837  {
10838  return (bool) $this->_highscore_score;
10839  }
10840 
10846  public function setHighscorePercentage($a_percentage)
10847  {
10848  $this->_highscore_percentage = (bool)$a_percentage;
10849  }
10850 
10856  public function getHighscorePercentage()
10857  {
10858  return (bool) $this->_highscore_percentage;
10859  }
10860 
10866  public function setHighscoreHints($a_hints)
10867  {
10868  $this->_highscore_hints = (bool)$a_hints;
10869  }
10870 
10876  public function getHighscoreHints()
10877  {
10878  return (bool) $this->_highscore_hints;
10879  }
10880 
10886  public function setHighscoreWTime($a_wtime)
10887  {
10888  $this->_highscore_wtime = (bool)$a_wtime;
10889  }
10890 
10896  public function getHighscoreWTime()
10897  {
10898  return (bool) $this->_highscore_wtime;
10899  }
10900 
10906  public function setHighscoreOwnTable($a_own_table)
10907  {
10908  $this->_highscore_own_table = (bool)$a_own_table;
10909  }
10910 
10916  public function getHighscoreOwnTable()
10917  {
10918  return (bool) $this->_highscore_own_table;
10919  }
10920 
10926  public function setHighscoreTopTable($a_top_table)
10927  {
10928  $this->_highscore_top_table = (bool)$a_top_table;
10929  }
10930 
10936  public function getHighscoreTopTable()
10937  {
10938  return (bool) $this->_highscore_top_table;
10939  }
10940 
10947  public function setHighscoreTopNum($a_top_num)
10948  {
10949  $this->_highscore_top_num = (int)$a_top_num;
10950  }
10951 
10960  public function getHighscoreTopNum($a_retval = 10)
10961  {
10962  $retval = $a_retval;
10963  if ( (int) $this->_highscore_top_num != 0)
10964  {
10965  $retval = $this->_highscore_top_num;
10966  }
10967 
10968  return $retval;
10969  }
10970  /* End GET/SET for highscore feature*/
10971 
10972  public function setSpecificAnswerFeedback($specific_answer_feedback)
10973  {
10974  switch ($specific_answer_feedback)
10975  {
10976  case 1:
10977  $this->specific_answer_feedback = 1;
10978  break;
10979  default:
10980  $this->specific_answer_feedback = 0;
10981  break;
10982  }
10983  }
10984 
10985  public function getSpecificAnswerFeedback()
10986  {
10987  switch ($this->specific_answer_feedback)
10988  {
10989  case 1:
10990  return 1;
10991  default:
10992  return 0;
10993  }
10994  }
10995 
11002  {
11003  $this->obligationsEnabled = (bool)$obligationsEnabled;
11004  }
11005 
11011  public function areObligationsEnabled()
11012  {
11013  return (bool)$this->obligationsEnabled;
11014  }
11015 
11022  public static function isQuestionObligationPossible($questionId)
11023  {
11024  require_once('Modules/TestQuestionPool/classes/class.assQuestion.php');
11025 
11026  $classConcreteQuestion = assQuestion::_getQuestionType($questionId);
11027 
11028  assQuestion::_includeClass($classConcreteQuestion, 0);
11029 
11030  // static binder is not at work yet (in PHP < 5.3)
11031  //$obligationPossible = $classConcreteQuestion::isObligationPossible();
11032  $obligationPossible = call_user_func(array($classConcreteQuestion, 'isObligationPossible'), $questionId);
11033 
11034  return $obligationPossible;
11035  }
11036 
11043  public static function isQuestionObligatory($question_id)
11044  {
11045  global $ilDB;
11046 
11047  $rset = $ilDB->queryF('SELECT obligatory FROM tst_test_question WHERE question_fi = %s', array('integer'), array($question_id));
11048 
11049  if( $row = $ilDB->fetchAssoc($rset) )
11050  {
11051  return (bool) $row['obligatory'];
11052  }
11053 
11054  return false;
11055  }
11056 
11069  public static function allObligationsAnswered($test_id, $active_id, $pass)
11070  {
11071  global $ilDB;
11072 
11073  $rset = $ilDB->queryF(
11074  'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
11075  array('integer', 'integer'),
11076  array($active_id, $pass)
11077  );
11078 
11079  if( $row = $ilDB->fetchAssoc($rset) )
11080  {
11081  return (bool)$row['obligations_answered'];
11082  }
11083 
11084  return !self::hasObligations($test_id);
11085  }
11086 
11095  public static function hasObligations($test_id)
11096  {
11097  global $ilDB;
11098 
11099  $rset = $ilDB->queryF(
11100  'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
11101  array('integer'), array($test_id)
11102  );
11103 
11104  $row = $ilDB->fetchAssoc($rset);
11105 
11106  return (bool)$row['cnt'] > 0;
11107  }
11108 
11109  public function setAutosave($autosave)
11110  {
11111  $this->autosave = $autosave;
11112  }
11113 
11114  public function getAutosave()
11115  {
11116  return $this->autosave;
11117  }
11118 
11120  {
11121  $this->autosave_ival = $autosave_ival;
11122  }
11123 
11124  public function getAutosaveIval()
11125  {
11126  return $this->autosave_ival;
11127  }
11128 
11134  public function isPassDeletionAllowed()
11135  {
11137  }
11138 
11145  {
11146  $this->passDeletionAllowed = (bool)$passDeletionAllowed;
11147  }
11148 
11149  #region Examview / PDF Examview
11150 
11154  {
11155  $this->show_examview_html = $show_examview_html;
11156  }
11157 
11161  public function getShowExamviewHtml()
11162  {
11164  }
11165 
11170  {
11171  $this->show_examview_pdf = $show_examview_pdf;
11172  }
11173 
11177  public function getShowExamviewPdf()
11178  {
11179  return $this->show_examview_pdf;
11180  }
11181 
11186  {
11187  $this->enable_examview = $enable_examview;
11188  }
11189 
11193  public function getEnableExamview()
11194  {
11195  return $this->enable_examview;
11196  }
11197 
11198  #endregion
11199 
11201  {
11202  $this->activation_starting_time = $starting_time;
11203  }
11204 
11206  {
11207  $this->activation_ending_time = $ending_time;
11208  }
11209 
11211  {
11212  return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : NULL;
11213  }
11214 
11216  {
11217  return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : NULL;
11218  }
11219 
11221  {
11222  global $ilDB;
11223 
11224  $times = array();
11225  $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");
11226  while ($row = $ilDB->fetchAssoc($result))
11227  {
11228  $times[$row['active_fi']] = $row['started'];
11229  }
11230  return $times;
11231  }
11232 
11234  {
11235  global $ilDB;
11236 
11237  $times = array();
11238  $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",
11239  array('integer'),
11240  array($this->getTestId())
11241  );
11242  while ($row = $ilDB->fetchAssoc($result))
11243  {
11244  $times[$row['active_fi']] = $row['additionaltime'];
11245  }
11246  return $times;
11247  }
11248 
11249  public function getExtraTime($active_id)
11250  {
11251  global $ilDB;
11252 
11253  $result = $ilDB->queryF("SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
11254  array('integer'),
11255  array($active_id)
11256  );
11257  if ($result->numRows() > 0)
11258  {
11259  $row = $ilDB->fetchAssoc($result);
11260  return $row['additionaltime'];
11261  }
11262  return 0;
11263  }
11264 
11265  public function addExtraTime($active_id, $minutes)
11266  {
11267  global $ilDB;
11268 
11269  $participants = array();
11270  if ($active_id == 0)
11271  {
11272  $result = $ilDB->queryF("SELECT active_id FROM tst_active WHERE test_fi = %s",
11273  array('integer'),
11274  array($this->getTestId())
11275  );
11276  while ($row = $ilDB->fetchAssoc($result))
11277  {
11278  array_push($participants, $row['active_id']);
11279  }
11280  }
11281  else
11282  {
11283  array_push($participants, $active_id);
11284  }
11285  foreach ($participants as $active_id)
11286  {
11287  $result = $ilDB->queryF("SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
11288  array('integer'),
11289  array($active_id)
11290  );
11291  if ($result->numRows() > 0)
11292  {
11293  $ilDB->manipulateF("DELETE FROM tst_addtime WHERE active_fi = %s",
11294  array('integer'),
11295  array($active_id)
11296  );
11297  }
11298 
11299  $ilDB->manipulateF("UPDATE tst_active SET tries = %s, submitted = %s, submittimestamp = %s WHERE active_id = %s",
11300  array('integer','integer','timestamp','integer'),
11301  array(0, 0, NULL, $active_id)
11302  );
11303 
11304  $ilDB->manipulateF("INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
11305  array('integer','integer','integer'),
11306  array($active_id, $minutes, time())
11307  );
11308 
11309  require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
11311  {
11312  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_added_extratime", ilObjAssessmentFolder::_getLogLanguage()), $minutes, $active_id));
11313  }
11314  }
11315  }
11316 
11323  {
11324  $this->enable_archiving = $enable_archiving;
11325  return $this;
11326  }
11327 
11331  public function getEnableArchiving()
11332  {
11333  return $this->enable_archiving;
11334  }
11335 
11336  public function getMaxPassOfTest()
11337  {
11341  global $ilDB;
11342 
11343  $query = '
11344  SELECT MAX(tst_pass_result.pass) + 1 max_res
11345  FROM tst_pass_result
11346  INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
11347  WHERE test_fi = '.$ilDB->quote($this->getTestId(), 'integer').'
11348  ';
11349  $res = $ilDB->query($query);
11350  $data = $ilDB->fetchAssoc($res);
11351  return (int)$data['max_res'];
11352  }
11353 
11359  public function lookupExamId($active_id, $pass)
11360  {
11362  global $ilDB, $ilSetting;
11363 
11364  $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
11365  $exam_id_result = $ilDB->queryF( $exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ) );
11366  if ($ilDB->numRows( $exam_id_result ) == 1)
11367  {
11368  $exam_id_row = $ilDB->fetchAssoc( $exam_id_result );
11369 
11370  if ($exam_id_row['exam_id'] != null)
11371  {
11372  return $exam_id_row['exam_id'];
11373  }
11374  }
11375 
11376  return null;
11377  }
11378 
11385  public static function buildExamId($active_id, $pass)
11386  {
11388  global $ilSetting;
11389 
11390  $inst_id = $ilSetting->get( 'inst_id', null );
11391 
11392  $obj_id = self::_getObjectIDFromActiveID($active_id);
11393 
11394  $examId = 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
11395 
11396  return $examId;
11397  }
11398 
11400  {
11401  $this->show_exam_id_in_test_pass_enabled = $show_exam_id_in_test_pass_enabled;
11402  }
11403 
11405  {
11407  }
11408 
11413  {
11414  $this->show_exam_id_in_test_results_enabled = $show_exam_id_in_test_results_enabled;
11415  }
11416 
11421  {
11423  }
11424 
11429  {
11430  $this->sign_submission = $sign_submission;
11431  }
11432 
11436  public function getSignSubmission()
11437  {
11438  return $this->sign_submission;
11439  }
11440 
11444  public function setCharSelectorAvailability($availability)
11445  {
11446  $this->char_selector_availability = (int) $availability;
11447  }
11448 
11453  {
11454  return (int) $this->char_selector_availability;
11455  }
11456 
11460  public function setCharSelectorDefinition($definition = '')
11461  {
11462  $this->char_selector_definition = $definition;
11463  }
11464 
11468  public function getCharSelectorDefinition()
11469  {
11471  }
11472 
11473 
11480  {
11481  $this->questionSetType = $questionSetType;
11482  }
11483 
11489  public function getQuestionSetType()
11490  {
11491  return $this->questionSetType;
11492  }
11493 
11501  public static function lookupQuestionSetType($objId)
11502  {
11503  global $ilDB;
11504 
11505  $query = "SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
11506 
11507  $res = $ilDB->queryF($query, array('integer'), array($objId));
11508 
11509  $questionSetType = null;
11510 
11511  while( $row = $ilDB->fetchAssoc($res) )
11512  {
11513  $questionSetType = $row['question_set_type'];
11514  }
11515 
11516  return $questionSetType;
11517  }
11518 
11524  public function isRandomTest()
11525  {
11527  }
11528 
11534  public function isDynamicTest()
11535  {
11537  }
11538 
11546  public static function _lookupRandomTest($a_obj_id)
11547  {
11549  }
11550 
11552  {
11553  switch( $questionSetType )
11554  {
11556  return $lng->txt('tst_question_set_type_fixed');
11557 
11559  return $lng->txt('tst_question_set_type_random');
11560 
11562  return $lng->txt('tst_question_set_type_dynamic');
11563  }
11564 
11565  throw new ilTestException('invalid question set type value given: '.$questionSetType);
11566  }
11567 
11568  public function participantDataExist()
11569  {
11570  if( $this->participantDataExist === null )
11571  {
11572  $this->participantDataExist = (bool)$this->evalTotalPersons();
11573  }
11574 
11576  }
11577 
11578  public function recalculateScores($preserve_manscoring = false)
11579  {
11580  require_once 'class.ilTestScoring.php';
11581  $scoring = new ilTestScoring($this);
11582  $scoring->setPreserveManualScores($preserve_manscoring);
11583  $scoring->recalculateSolutions();
11584  }
11585 
11586  public static function getPoolQuestionChangeListeners(ilDB $db, $poolObjId)
11587  {
11588  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
11589 
11590  $questionChangeListeners = array(
11592  );
11593 
11594  return $questionChangeListeners;
11595  }
11596 
11597  public static function getTestObjIdsWithActiveForUserId($userId)
11598  {
11599  global $ilDB;
11600 
11601  $query = "
11602  SELECT obj_fi
11603  FROM tst_active
11604  INNER JOIN tst_tests
11605  ON test_id = test_fi
11606  WHERE user_fi = %s
11607  ";
11608 
11609  $res = $ilDB->queryF($query, array('integer'), array($userId));
11610 
11611  $objIds = array();
11612 
11613  while( $row = $ilDB->fetchAssoc($res) )
11614  {
11615  $objIds[] = (int)$row['obj_fi'];
11616  }
11617 
11618  return $objIds;
11619  }
11620 
11624  public function isTestFinalBroken()
11625  {
11626  return $this->testFinalBroken;
11627  }
11628 
11633  {
11634  $this->testFinalBroken = $testFinalBroken;
11635  }
11636 }