ILIAS  Release_3_10_x_branch Revision 61812
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilObjTest.php
Go to the documentation of this file.
1 <?php
2 /*
3  +-----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +-----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2008 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +-----------------------------------------------------------------------------+
22 */
23 
34 include_once "./classes/class.ilObject.php";
35 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
36 
37 class ilObjTest extends ilObject
38 {
46  protected $_kiosk;
47 
55  var $test_id;
56 
65 
66 
75  var $author;
76 
84  var $metadata;
85 
94 
104 
113 
124 
137 
148 
157 
169 
178 
188 
198 
210 
219 
228 
237 
246 
255 
264 
272  var $ects_fx;
273 
282 
293 
302 
310 
317 
324 
332 
339 
346 
353 
360 
367 
374 
381 
388 
395 
402 
409 
416 
423 
430 
437 
444 
450  private $_showinfo;
451 
457  private $_forcejs;
458 
464  private $_customStyle;
465 
472  function ilObjTest($a_id = 0,$a_call_by_reference = true)
473  {
474  global $ilUser;
475  $this->type = "tst";
476  include_once "./Modules/Test/classes/class.assMarkSchema.php";
477  $this->mark_schema = new ASS_MarkSchema();
478  $this->test_id = -1;
479  $this->author = $ilUser->fullname;
480  $this->introduction = "";
481  $this->questions = array();
482  $this->sequence_settings = TEST_FIXED_SEQUENCE;
483  $this->score_reporting = REPORT_AFTER_TEST;
484  $this->instant_verification = 0;
485  $this->answer_feedback_points = 0;
486  $this->reporting_date = "";
487  $this->nr_of_tries = 0;
488  $this->_kiosk = 0;
489  $this->use_previous_answers = 1;
490  $this->title_output = 0;
491  $this->starting_time = "";
492  $this->ending_time = "";
493  $this->processing_time = "00:00:00";
494  $this->enable_processing_time = "0";
495  $this->reset_processing_time = 0;
496  $this->ects_output = 0;
497  $this->ects_fx = "";
498  $this->random_test = 0;
499  $this->shuffle_questions = FALSE;
500  $this->show_summary = 8;
501  $this->random_question_count = "";
502  $this->count_system = COUNT_PARTIAL_SOLUTIONS;
503  $this->mc_scoring = SCORE_ZERO_POINTS_WHEN_UNANSWERED;
504  $this->score_cutting = SCORE_CUT_QUESTION;
505  $this->pass_scoring = SCORE_LAST_PASS;
506  $this->answer_feedback = 0;
507  $this->password = "";
508  $this->certificate_visibility = 0;
509  $this->allowedUsers = "";
510  $this->_showfinalstatement = FALSE;
511  $this->_finalstatement = "";
512  $this->_showinfo = TRUE;
513  $this->_forcejs = FALSE;
514  $this->_customStyle = "";
515  $this->allowedUsersTimeGap = "";
516  $this->anonymity = 0;
517  $this->show_cancel = 1;
518  $this->show_marker = 0;
519  $this->fixed_participants = 0;
520  $this->setShowPassDetails(TRUE);
521  $this->setShowSolutionDetails(TRUE);
522  $this->setShowSolutionAnswersOnly(FALSE);
523  $this->setShowSolutionSignature(FALSE);
524  $this->testSession = FALSE;
525  $this->testSequence = FALSE;
526  global $lng;
527  $lng->loadLanguageModule("assessment");
528  $this->mark_schema->createSimpleSchema($lng->txt("failed_short"), $lng->txt("failed_official"), 0, 0, $lng->txt("passed_short"), $lng->txt("passed_official"), 50, 1);
529  $this->ects_grades = array(
530  "A" => 90,
531  "B" => 65,
532  "C" => 35,
533  "D" => 10,
534  "E" => 0
535  );
536  $this->ilObject($a_id, $a_call_by_reference);
537  }
538 
542  function create($a_upload = false)
543  {
544  parent::create();
545 
546  // meta data will be created by
547  // import parser
548  if (!$a_upload)
549  {
550  $this->createMetaData();
551  }
552  }
553 
560  function update()
561  {
562  if (!parent::update())
563  {
564  return false;
565  }
566 
567  // put here object specific stuff
568 
569  return true;
570  }
571 
580  function createReference() {
582  $this->saveToDb();
583  return $result;
584  }
585 
591  function read($a_force_db = false)
592  {
593  parent::read($a_force_db);
594  $this->loadFromDb();
595  }
596 
597 
604  function delete()
605  {
606  // always call parent delete function first!!
607  if (!parent::delete())
608  {
609  return false;
610  }
611 
612  // delet meta data
613  $this->deleteMetaData();
614 
615  //put here your module specific stuff
616  $this->deleteTest();
617 
618  return true;
619  }
620 
628  function deleteTest()
629  {
630  global $ilDB;
631 
632  $query = sprintf("SELECT active_id FROM tst_active WHERE test_fi = %s",
633  $ilDB->quote($this->getTestId())
634  );
635  $result = $ilDB->query($query);
636  $active_array = array();
637  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
638  {
639  array_push($active_array, $row["active_id"]);
640  }
641 
642  $query = sprintf("DELETE FROM tst_active WHERE test_fi = %s",
643  $ilDB->quote($this->getTestId())
644  );
645  $result = $ilDB->query($query);
646 
647  if (count($active_array))
648  {
649  foreach ($active_array as $active_id)
650  {
651  $query = sprintf("DELETE FROM tst_times WHERE active_fi = %s",
652  $ilDB->quote($active_id)
653  );
654  $result = $ilDB->query($query);
655 
656  $query = sprintf("DELETE FROM tst_sequence WHERE active_fi = %s",
657  $ilDB->quote($active_id)
658  );
659  $result = $ilDB->query($query);
660  }
661  }
662 
663  $query = sprintf("DELETE FROM tst_mark WHERE test_fi = %s",
664  $ilDB->quote($this->getTestId())
665  );
666  $result = $ilDB->query($query);
667 
668  $query = sprintf("SELECT question_fi FROM tst_test_question WHERE test_fi = %s",
669  $ilDB->quote($this->getTestId())
670  );
671  $result = $ilDB->query($query);
672  while ($row = $result->fetchRow(MDB2_FETCHMODE_OBJECT))
673  {
674  $this->removeQuestion($row->question_fi);
675  }
676 
677  $query = sprintf("DELETE FROM tst_tests WHERE test_id = %s",
678  $ilDB->quote($this->getTestId())
679  );
680  $result = $ilDB->query($query);
681 
682  $query = sprintf("DELETE FROM tst_test_random WHERE test_fi = %s",
683  $ilDB->quote($this->getTestId())
684  );
685  $result = $ilDB->query($query);
686 
687  $query = sprintf("DELETE FROM tst_test_random_question USING tst_test_random_question, tst_active WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_test_random_question.active_fi",
688  $ilDB->quote($this->getTestId())
689  );
690  $result = $ilDB->query($query);
691 
692  $this->removeAllTestEditings();
693 
694  $query = sprintf("DELETE FROM tst_test_question WHERE test_fi = %s",
695  $ilDB->quote($this->getTestId())
696  );
697  $result = $ilDB->query($query);
698 
699  // delete export files
700  include_once "./Services/Utilities/classes/class.ilUtil.php";
701  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
702  $directory = $tst_data_dir."/tst_".$this->getId();
703  if (is_dir($directory))
704  {
705  include_once "./Services/Utilities/classes/class.ilUtil.php";
706  ilUtil::delDir($directory);
707  }
708  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
709  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
710  // remaining usages are not in text anymore -> delete them
711  // and media objects (note: delete method of ilObjMediaObject
712  // checks whether object is used in another context; if yes,
713  // the object is not deleted!)
714  foreach($mobs as $mob)
715  {
716  ilObjMediaObject::_removeUsage($mob, "tst:html", $this->getId());
717  if (ilObjMediaObject::_exists($mob))
718  {
719  $mob_obj =& new ilObjMediaObject($mob);
720  $mob_obj->delete();
721  }
722  }
723  }
724 
734  function initDefaultRoles()
735  {
736  global $rbacadmin;
737 
738  // create a local role folder
739  //$rfoldObj = $this->createRoleFolder("Local roles","Role Folder of forum obj_no.".$this->getId());
740 
741  // create moderator role and assign role to rolefolder...
742  //$roleObj = $rfoldObj->createRole("Moderator","Moderator of forum obj_no.".$this->getId());
743  //$roles[] = $roleObj->getId();
744 
745  //unset($rfoldObj);
746  //unset($roleObj);
747 
748  return $roles ? $roles : array();
749  }
750 
764  function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
765  {
766  global $tree;
767 
768  switch ($a_event)
769  {
770  case "link":
771 
772  //var_dump("<pre>",$a_params,"</pre>");
773  //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
774  //exit;
775  break;
776 
777  case "cut":
778 
779  //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
780  //exit;
781  break;
782 
783  case "copy":
784 
785  //var_dump("<pre>",$a_params,"</pre>");
786  //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
787  //exit;
788  break;
789 
790  case "paste":
791 
792  //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
793  //exit;
794  break;
795 
796  case "new":
797 
798  //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
799  //exit;
800  break;
801  }
802 
803  // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
804  if ($a_node_id==$_GET["ref_id"])
805  {
806  $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
807  $parent_type = $parent_obj->getType();
808  if($parent_type == $this->getType())
809  {
810  $a_node_id = (int) $tree->getParentId($a_node_id);
811  }
812  }
813 
814  parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
815  }
816 
823  {
824  include_once "./Services/Utilities/classes/class.ilUtil.php";
825  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
826  ilUtil::makeDir($tst_data_dir);
827  if(!is_writable($tst_data_dir))
828  {
829  $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
830  .") not writeable.",$this->ilias->error_obj->MESSAGE);
831  }
832 
833  // create learning module directory (data_dir/lm_data/lm_<id>)
834  $tst_dir = $tst_data_dir."/tst_".$this->getId();
835  ilUtil::makeDir($tst_dir);
836  if(!@is_dir($tst_dir))
837  {
838  $this->ilias->raiseError("Creation of Test Directory failed.",$this->ilias->error_obj->MESSAGE);
839  }
840  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
841  $export_dir = $tst_dir."/export";
842  ilUtil::makeDir($export_dir);
843  if(!@is_dir($export_dir))
844  {
845  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->MESSAGE);
846  }
847  }
848 
857  {
858  include_once "./Services/Utilities/classes/class.ilUtil.php";
859  $export_dir = ilUtil::getDataDir()."/tst_data"."/tst_".$this->getId()."/export";
860  return $export_dir;
861  }
862 
872  {
873  // quit if import dir not available
874  if (!@is_dir($dir) or
875  !is_writeable($dir))
876  {
877  return array();
878  }
879 
880  // open directory
881  $dir = dir($dir);
882 
883  // initialize array
884  $file = array();
885 
886  // get files and save the in the array
887  while ($entry = $dir->read())
888  {
889  if ($entry != "." and
890  $entry != ".." and
891  //substr($entry, -4) == ".zip" and
892  ereg("^[0-9]{10}_{2}[0-9]+_{2}(test(__results)?__)*[0-9]+\.[a-z]{1,3}\$", $entry))
893  {
894  $file[] = $entry;
895  }
896  }
897 
898  // close import directory
899  $dir->close();
900 
901  // sort files
902  sort ($file);
903  reset ($file);
904 
905  return $file;
906  }
907 
908 
915  {
916  global $ilias;
917 
918  include_once "./Services/Utilities/classes/class.ilUtil.php";
919  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
920  ilUtil::makeDir($tst_data_dir);
921 
922  if(!is_writable($tst_data_dir))
923  {
924  $ilias->raiseError("Test data directory (".$tst_data_dir
925  .") not writeable.",$ilias->error_obj->FATAL);
926  }
927 
928  // create test directory (data_dir/tst_data/tst_import)
929  $tst_dir = $tst_data_dir."/tst_import";
930  ilUtil::makeDir($tst_dir);
931  if(!@is_dir($tst_dir))
932  {
933  $ilias->raiseError("Creation of test import directory failed.",$ilias->error_obj->FATAL);
934  }
935  }
936 
946  {
947  include_once "./Services/Utilities/classes/class.ilUtil.php";
948  $import_dir = ilUtil::getDataDir()."/tst_data/tst_import";
949  if(@is_dir($import_dir))
950  {
951  return $import_dir;
952  }
953  else
954  {
955  return false;
956  }
957  }
958 
965  {
966  include_once "./Services/Utilities/classes/class.ilUtil.php";
967  $tst_data_dir = ilUtil::getDataDir()."/tst_data";
968  ilUtil::makeDir($tst_data_dir);
969 
970  if(!is_writable($tst_data_dir))
971  {
972  $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
973  .") not writeable.",$this->ilias->error_obj->FATAL);
974  }
975 
976  // create test directory (data_dir/tst_data/tst_import)
977  $tst_dir = $tst_data_dir."/tst_import";
978  ilUtil::makeDir($tst_dir);
979  if(!@is_dir($tst_dir))
980  {
981  $ilias->raiseError("Creation of test import directory failed.",$ilias->error_obj->FATAL);
982  }
983  }
984 
994  {
995  include_once "./Services/Utilities/classes/class.ilUtil.php";
996  $import_dir = ilUtil::getDataDir()."/tst_data/tst_import";
997  if(@is_dir($import_dir))
998  {
999  return $import_dir;
1000  }
1001  else
1002  {
1003  return false;
1004  }
1005  }
1006 
1007 
1018  {
1019  global $ilDB;
1020 
1021  $query = sprintf("SELECT * FROM object_data WHERE title = %s AND type = %s",
1022  $ilDB->quote($title),
1023  $ilDB->quote("tst")
1024  );
1025  $result = $ilDB->query($query);
1026  if ($result->numRows() == 1)
1027  {
1028  return TRUE;
1029  }
1030  return FALSE;
1031  }
1032 
1040  {
1041  global $ilDB;
1042 
1043  $query = sprintf("SELECT DISTINCT(qpl_question_type.type_tag) foundtypes FROM qpl_questions, tst_test_result, qpl_question_type, tst_active WHERE tst_test_result.question_fi = qpl_questions.question_id AND qpl_questions.question_type_fi = qpl_question_type.question_type_id AND tst_test_result.active_fi = tst_active.active_id AND tst_active.test_fi = %s AND qpl_question_type.type_tag = %s",
1044  $ilDB->quote($this->getTestId()),
1045  $ilDB->quote("assSingleChoice")
1046  );
1047  $result = $ilDB->query($query);
1048  if ($result->numRows() == 1)
1049  {
1050  $row = $ilDB->fetchAssoc($result);
1051  if (strcmp($row['foundtypes'], 'assSingleChoice') == 0)
1052  {
1053  return TRUE;
1054  }
1055  else
1056  {
1057  return false;
1058  }
1059  }
1060  return FALSE;
1061  }
1062 
1070  {
1071  global $ilDB;
1072 
1073  $query = sprintf("SELECT DISTINCT(qpl_question_singlechoice.shuffle) foundshuffles FROM qpl_questions, qpl_question_singlechoice, tst_test_result, qpl_question_type, tst_active WHERE tst_test_result.question_fi = qpl_questions.question_id AND qpl_questions.question_type_fi = qpl_question_type.question_type_id AND tst_test_result.active_fi = tst_active.active_id AND qpl_questions.question_id = qpl_question_singlechoice.question_fi AND tst_active.test_fi = %s AND qpl_question_type.type_tag = %s",
1074  $ilDB->quote($this->getTestId()),
1075  $ilDB->quote("assSingleChoice")
1076  );
1077  $result = $ilDB->query($query);
1078  if ($result->numRows() == 1)
1079  {
1080  $row = $ilDB->fetchAssoc($result);
1081  return ($row['foundshuffles'] == 0);
1082  }
1083  return FALSE;
1084  }
1085 
1094  function isComplete()
1095  {
1096  if ((count($this->mark_schema->mark_steps)) and (count($this->questions)))
1097  {
1098  return true;
1099  }
1100  else
1101  {
1102  if ($this->isRandomTest())
1103  {
1104  $arr = $this->getRandomQuestionpools();
1105  if (count($arr) && ($this->getRandomQuestionCount() > 0))
1106  {
1107  return true;
1108  }
1109  $count = 0;
1110  foreach ($arr as $array)
1111  {
1112  $count += $array["count"];
1113  }
1114  if ($count)
1115  {
1116  return true;
1117  }
1118  }
1119  return false;
1120  }
1121  }
1122 
1131  function _isComplete($obj_id)
1132  {
1133  $test = new ilObjTest($obj_id, false);
1134  $test->loadFromDb();
1135  return $test->isComplete();
1136  }
1137 
1145  function saveECTSStatus($ects_output = 0, $fx_support = "", $ects_a = 90, $ects_b = 65, $ects_c = 35, $ects_d = 10, $ects_e = 0)
1146  {
1147  global $ilDB;
1148  if ($this->test_id > 0) {
1149  $fx_support = preg_replace("/,/", ".", $fx_support);
1150  if (preg_match("/\d+/", $fx_support))
1151  {
1152  $fx_support = $fx_support;
1153  }
1154  else
1155  {
1156  $fx_support = "NULL";
1157  }
1158  $query = sprintf("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",
1159  $ilDB->quote("$ects_output"),
1160  $ilDB->quote($ects_a . ""),
1161  $ilDB->quote($ects_b . ""),
1162  $ilDB->quote($ects_c . ""),
1163  $ilDB->quote($ects_d . ""),
1164  $ilDB->quote($ects_e . ""),
1165  $fx_support,
1166  $this->getTestId()
1167  );
1168  $result = $ilDB->query($query);
1169  $this->ects_output = $ects_output;
1170  $this->ects_fx = $fx_support;
1171  }
1172  }
1173 
1182  {
1183  global $ilDB;
1184 
1185  $complete = 0;
1186  if ($this->isComplete())
1187  {
1188  $complete = 1;
1189  }
1190  if ($this->test_id > 0)
1191  {
1192  $query = sprintf("UPDATE tst_tests SET complete = %s WHERE test_id = %s",
1193  $ilDB->quote("$complete"),
1194  $ilDB->quote($this->test_id)
1195  );
1196  $result = $ilDB->query($query);
1197  }
1198  }
1199 
1207  function getAllRTEContent()
1208  {
1209  $result = array();
1210  array_push($result, $this->getIntroduction());
1211  array_push($result, $this->getFinalStatement());
1212  return $result;
1213  }
1214 
1223  {
1224  include_once("./Services/RTE/classes/class.ilRTE.php");
1225  $completecontent = "";
1226  foreach ($this->getAllRTEContent() as $content)
1227  {
1228  $completecontent .= $content;
1229  }
1230  ilRTE::_cleanupMediaObjectUsage($completecontent, $this->getType() . ":html",
1231  $this->getId());
1232  }
1233 
1242  function saveToDb($properties_only = FALSE)
1243  {
1244  global $ilDB, $ilLog;
1245 
1246  $complete = 0;
1247  if ($this->isComplete())
1248  {
1249  $complete = 1;
1250  }
1251  $ects_fx = "NULL";
1252  if (preg_match("/\d+/", $this->ects_fx))
1253  {
1255  }
1256  $random_question_count = "NULL";
1257  if ($this->random_question_count > 0)
1258  {
1259  $random_question_count = $ilDB->quote($this->random_question_count . "");
1260  }
1261  $shuffle_questions = 0;
1262  if ($this->getShuffleQuestions())
1263  {
1264  $shuffle_questions = 1;
1265  }
1266  $allowedUsers = $this->getAllowedUsers();
1267  if ($allowedUsers == 0)
1268  {
1269  $allowedUsers = "NULL";
1270  }
1271  else
1272  {
1273  $allowedUsers = $ilDB->quote($allowedUsers);
1274  }
1276  if ($allowedUsersTimeGap == 0)
1277  {
1278  $allowedUsersTimeGap = "NULL";
1279  }
1280  else
1281  {
1283  }
1284 
1285  // cleanup RTE images
1286  $this->cleanupMediaobjectUsage();
1287  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1288  if ($this->test_id == -1)
1289  {
1290  // Create new dataset
1291  $now = getdate();
1292  $created = sprintf("%04d%02d%02d%02d%02d%02d", $now['year'], $now['mon'], $now['mday'], $now['hours'], $now['minutes'], $now['seconds']);
1293  $query = sprintf("INSERT INTO tst_tests (test_id, obj_fi, author, introduction, finalstatement, showinfo, forcejs, customstyle, showfinalstatement, sequence_settings, " .
1294  "score_reporting, instant_verification, answer_feedback_points, answer_feedback, anonymity, show_cancel, show_marker, " .
1295  "fixed_participants, nr_of_tries, kiosk, use_previous_answers, title_output, processing_time, enable_processing_time, reset_processing_time, " .
1296  "reporting_date, starting_time, ending_time, complete, ects_output, ects_a, ects_b, ects_c, ects_d, ects_e, " .
1297  "ects_fx, random_test, random_question_count, count_system, mc_scoring, score_cutting, pass_scoring, " .
1298  "shuffle_questions, results_presentation, show_summary, password, allowedUsers, " .
1299  "allowedUsersTimeGap, certificate_visibility, created, TIMESTAMP) " .
1300  "VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, " .
1301  "%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
1302  $ilDB->quote($this->getId() . ""),
1303  $ilDB->quote($this->getAuthor() . ""),
1304  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->introduction, 0)),
1305  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1306  $ilDB->quote((($this->getShowInfo()) ? "1" : "0")),
1307  $ilDB->quote((($this->getForceJS()) ? "1" : "0")),
1308  (strlen($this->getCustomStyle())) ? $ilDB->quote($this->getCustomStyle()) : "NULL",
1309  $ilDB->quote((($this->getShowFinalStatement()) ? "1" : "0")),
1310  $ilDB->quote($this->sequence_settings . ""),
1311  $ilDB->quote($this->score_reporting . ""),
1312  $ilDB->quote($this->getInstantFeedbackSolution() . ""),
1313  $ilDB->quote($this->getAnswerFeedbackPoints() . ""),
1314  $ilDB->quote($this->getAnswerFeedback() . ""),
1315  $ilDB->quote($this->getAnonymity() . ""),
1316  $ilDB->quote($this->getShowCancel() . ""),
1317  $ilDB->quote($this->getShowMarker() . ""),
1318  $ilDB->quote($this->getFixedParticipants() . ""),
1319  $ilDB->quote(sprintf("%d", $this->getNrOfTries()) . ""),
1320  $ilDB->quote($this->getKiosk() . ""),
1321  $ilDB->quote(sprintf("%d", $this->getUsePreviousAnswers() . "")),
1322  $ilDB->quote(sprintf("%d", $this->getTitleOutput() . "")),
1323  $ilDB->quote($this->processing_time . ""),
1324  $ilDB->quote("$this->enable_processing_time"),
1325  $ilDB->quote($this->getResetProcessingTime() . ""),
1326  $ilDB->quote($this->reporting_date . ""),
1327  $ilDB->quote($this->starting_time . ""),
1328  $ilDB->quote($this->ending_time . ""),
1329  $ilDB->quote("$complete"),
1330  $ilDB->quote($this->ects_output . ""),
1331  $ilDB->quote($this->ects_grades["A"] . ""),
1332  $ilDB->quote($this->ects_grades["B"] . ""),
1333  $ilDB->quote($this->ects_grades["C"] . ""),
1334  $ilDB->quote($this->ects_grades["D"] . ""),
1335  $ilDB->quote($this->ects_grades["E"] . ""),
1336  $ects_fx,
1337  $ilDB->quote(sprintf("%d", $this->random_test) . ""),
1339  $ilDB->quote($this->count_system . ""),
1340  $ilDB->quote($this->mc_scoring . ""),
1341  $ilDB->quote($this->getScoreCutting() . ""),
1342  $ilDB->quote($this->getPassScoring() . ""),
1343  $ilDB->quote($shuffle_questions . ""),
1344  $ilDB->quote($this->getResultsPresentation() . ""),
1345  $ilDB->quote($this->getListOfQuestionsSettings() . ""),
1346  $ilDB->quote($this->getPassword() . ""),
1347  $allowedUsers,
1349  $ilDB->quote($this->getCertificateVisibility() . ""),
1350  $ilDB->quote($created)
1351  );
1352 
1354  {
1355  $this->logAction($this->lng->txtlng("assessment", "log_create_new_test", ilObjAssessmentFolder::_getLogLanguage()));
1356  }
1357  $result = $ilDB->query($query);
1358  if (PEAR::isError($result))
1359  {
1360  global $ilias;
1361  $ilias->raiseError($result->getMessage());
1362  }
1363  else
1364  {
1365  $this->test_id = $ilDB->getLastInsertId();
1366  }
1367  }
1368  else
1369  {
1370  // Modify existing dataset
1371  $oldrow = array();
1373  {
1374  $query = sprintf("SELECT * FROM tst_tests WHERE test_id = %s",
1375  $ilDB->quote($this->test_id)
1376  );
1377  $result = $ilDB->query($query);
1378  if ($result->numRows() == 1)
1379  {
1380  $oldrow = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
1381  }
1382  }
1383  $query = sprintf("UPDATE tst_tests SET author = %s, introduction = %s, finalstatement = %s, showinfo = %s, forcejs = %s, customstyle = %s, showfinalstatement = %s, sequence_settings = %s, score_reporting = %s, instant_verification = %s, answer_feedback_points = %s, answer_feedback = %s, anonymity = %s, show_cancel = %s, show_marker = %s, fixed_participants = %s, nr_of_tries = %s, kiosk = %s, use_previous_answers = %s, title_output = %s, processing_time = %s, enable_processing_time = %s, reset_processing_time = %s, reporting_date = %s, starting_time = %s, ending_time = %s, ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s, random_test = %s, complete = %s, count_system = %s, mc_scoring = %s, score_cutting = %s, pass_scoring = %s, shuffle_questions = %s, results_presentation = %s, show_summary = %s, password = %s, allowedUsers = %s, allowedUsersTimeGap = %s, certificate_visibility = %s WHERE test_id = %s",
1384  $ilDB->quote($this->getAuthor() . ""),
1385  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->introduction, 0)),
1386  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->getFinalStatement(), 0)),
1387  $ilDB->quote((($this->getShowInfo()) ? "1" : "0")),
1388  $ilDB->quote((($this->getForceJS()) ? "1" : "0")),
1389  (strlen($this->getCustomStyle())) ? $ilDB->quote($this->getCustomStyle()) : "NULL",
1390  $ilDB->quote((($this->getShowFinalStatement()) ? "1" : "0")),
1391  $ilDB->quote($this->sequence_settings . ""),
1392  $ilDB->quote($this->score_reporting . ""),
1393  $ilDB->quote($this->getInstantFeedbackSolution() . ""),
1394  $ilDB->quote($this->getAnswerFeedbackPoints() . ""),
1395  $ilDB->quote($this->getAnswerFeedback() . ""),
1396  $ilDB->quote($this->getAnonymity() . ""),
1397  $ilDB->quote($this->getShowCancel() . ""),
1398  $ilDB->quote($this->getShowMarker() . ""),
1399  $ilDB->quote($this->getFixedParticipants() . ""),
1400  $ilDB->quote(sprintf("%d", $this->getNrOfTries()) . ""),
1401  $ilDB->quote($this->getKiosk() . ""),
1402  $ilDB->quote(sprintf("%d", $this->getUsePreviousAnswers() . "")),
1403  $ilDB->quote(sprintf("%d", $this->getTitleOutput() . "")),
1404  $ilDB->quote($this->processing_time . ""),
1405  $ilDB->quote("$this->enable_processing_time"),
1406  $ilDB->quote($this->getResetProcessingTime() . ""),
1407  $ilDB->quote($this->reporting_date . ""),
1408  $ilDB->quote($this->starting_time . ""),
1409  $ilDB->quote($this->ending_time . ""),
1410  $ilDB->quote($this->ects_output . ""),
1411  $ilDB->quote($this->ects_grades["A"] . ""),
1412  $ilDB->quote($this->ects_grades["B"] . ""),
1413  $ilDB->quote($this->ects_grades["C"] . ""),
1414  $ilDB->quote($this->ects_grades["D"] . ""),
1415  $ilDB->quote($this->ects_grades["E"] . ""),
1416  $ects_fx,
1417  $ilDB->quote(sprintf("%d", $this->random_test) . ""),
1418  $ilDB->quote("$complete"),
1419  $ilDB->quote($this->count_system . ""),
1420  $ilDB->quote($this->mc_scoring . ""),
1421  $ilDB->quote($this->getScoreCutting() . ""),
1422  $ilDB->quote($this->getPassScoring() . ""),
1423  $ilDB->quote($shuffle_questions . ""),
1424  $ilDB->quote($this->getResultsPresentation() . ""),
1425  $ilDB->quote($this->getListOfQuestionsSettings() . ""),
1426  $ilDB->quote($this->getPassword() . ""),
1427  $allowedUsers,
1429  $ilDB->quote($this->getCertificateVisibility() . ""),
1430  $ilDB->quote($this->test_id)
1431  );
1432  $result = $ilDB->query($query);
1433  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1435  {
1436  $query = sprintf("SELECT * FROM tst_tests WHERE test_id = %s",
1437  $ilDB->quote($this->test_id)
1438  );
1439  $logresult = $ilDB->query($query);
1440  $newrow = array();
1441  if ($logresult->numRows() == 1)
1442  {
1443  $newrow = $logresult->fetchRow(MDB2_FETCHMODE_ASSOC);
1444  }
1445  $changed_fields = array();
1446  foreach ($oldrow as $key => $value)
1447  {
1448  if (strcmp($oldrow[$key], $newrow[$key]) != 0)
1449  {
1450  array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
1451  }
1452  }
1453  $changes = join($changed_fields, ", ");
1454  if (count($changed_fields) > 0)
1455  {
1456  $this->logAction($this->lng->txtlng("assessment", "log_modified_test", ilObjAssessmentFolder::_getLogLanguage()) . " [".$changes."]");
1457  }
1458  }
1459  if ($this->evalTotalPersons() > 0)
1460  {
1461  // reset the finished status of participants if the nr of test passes did change
1462 
1463  if ($this->getNrOfTries() > 0)
1464  {
1465  // set all unfinished tests with nr of passes >= allowed passes finished
1466  $query = sprintf("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = 0",
1467  $ilDB->quote($this->getTestId() . ""),
1468  $ilDB->quote($this->getNrOfTries() . "")
1469  );
1470  $aresult = $ilDB->query($query);
1471  while ($row = $aresult->fetchRow(MDB2_FETCHMODE_ASSOC))
1472  {
1473  $newquery = sprintf("UPDATE tst_active SET submitted = 1, submittimestamp = NOW() WHERE active_id = %s",
1474  $ilDB->quote($row["active_id"] . "")
1475  );
1476  $newresult = $ilDB->query($newquery);
1477  }
1478 
1479  // set all finished tests with nr of passes >= allowed passes not finished
1480  $query = sprintf("SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = 1",
1481  $ilDB->quote($this->getTestId() . ""),
1482  $ilDB->quote($this->getNrOfTries() . "")
1483  );
1484  $aresult = $ilDB->query($query);
1485  while ($row = $aresult->fetchRow(MDB2_FETCHMODE_ASSOC))
1486  {
1487  $newquery = sprintf("UPDATE tst_active SET submitted = 0, submittimestamp = NULL WHERE active_id = %s",
1488  $ilDB->quote($row["active_id"] . "")
1489  );
1490  $newresult = $ilDB->query($newquery);
1491  }
1492  }
1493  else
1494  {
1495  // set all finished tests with nr of passes >= allowed passes not finished
1496  $query = sprintf("SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = 1",
1497  $ilDB->quote($this->getTestId() . "")
1498  );
1499  $aresult = $ilDB->query($query);
1500  while ($row = $aresult->fetchRow(MDB2_FETCHMODE_ASSOC))
1501  {
1502  $newquery = sprintf("UPDATE tst_active SET submitted = 0, submittimestamp = NULL WHERE active_id = %s",
1503  $ilDB->quote($row["active_id"] . "")
1504  );
1505  $newresult = $ilDB->query($newquery);
1506  }
1507  }
1508  }
1509  }
1510  if (!$properties_only)
1511  {
1512  if (PEAR::isError($result))
1513  {
1514  global $ilias;
1515  $ilias->raiseError($result->getMessage());
1516  }
1517  else
1518  {
1519  if (!$this->isRandomTest())
1520  {
1521  $this->saveQuestionsToDb();
1522  }
1523  $this->mark_schema->saveToDb($this->test_id);
1524  }
1525  }
1526  }
1527 
1537  {
1538  global $ilDB;
1539 
1540  $oldquestions = array();
1541  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1543  {
1544  $query = sprintf("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1545  $ilDB->quote($this->getTestId())
1546  );
1547  $result = $ilDB->query($query);
1548  if ($result->numRows() > 0)
1549  {
1550  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
1551  {
1552  array_push($oldquestions, $row["question_fi"]);
1553  }
1554  }
1555  }
1556 
1557  // delete existing category relations
1558  $query = sprintf("DELETE FROM tst_test_question WHERE test_fi = %s",
1559  $ilDB->quote($this->getTestId())
1560  );
1561  $result = $ilDB->query($query);
1562  // create new category relations
1563  foreach ($this->questions as $key => $value) {
1564  $query = sprintf("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
1565  $ilDB->quote($this->getTestId() . ""),
1566  $ilDB->quote($value . ""),
1567  $ilDB->quote($key . "")
1568  );
1569  $result = $ilDB->query($query);
1570  }
1571  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1573  {
1574  $query = sprintf("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
1575  $ilDB->quote($this->getTestId())
1576  );
1577  $result = $ilDB->query($query);
1578  $newquestions = array();
1579  if ($result->numRows() > 0)
1580  {
1581  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
1582  {
1583  array_push($newquestions, $row["question_fi"]);
1584  }
1585  }
1586  foreach ($oldquestions as $index => $question_id)
1587  {
1588  if (strcmp($newquestions[$index], $question_id) != 0)
1589  {
1590  $pos = array_search($question_id, $newquestions);
1591  if ($pos === FALSE)
1592  {
1593  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
1594  }
1595  else
1596  {
1597  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1) . " => " . ($pos+1), $question_id);
1598  }
1599  }
1600  }
1601  foreach ($newquestions as $index => $question_id)
1602  {
1603  if (array_search($question_id, $oldquestions) === FALSE)
1604  {
1605  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($index+1), $question_id);
1606  }
1607  }
1608  }
1609  }
1610 
1619  function saveRandomQuestion($active_id, $question_id, $pass = NULL, $maxcount)
1620  {
1621  global $ilUser;
1622  global $ilDB;
1623 
1624  if (is_null($pass)) $pass = 0;
1625  $query = sprintf("SELECT test_random_question_id FROM tst_test_random_question WHERE active_fi = %s AND pass = %s",
1626  $ilDB->quote($active_id . ""),
1627  $ilDB->quote($pass . "")
1628  );
1629  $result = $ilDB->query($query);
1630  if ($result->numRows() < $maxcount)
1631  {
1632  $duplicate_id = $this->getRandomQuestionDuplicate($question_id, $active_id);
1633  if ($duplicate_id === FALSE)
1634  {
1635  $duplicate_id = $this->duplicateQuestionForTest($question_id);
1636  }
1637 
1638  $query = sprintf("INSERT INTO tst_test_random_question (test_random_question_id, active_fi, question_fi, sequence, pass, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, NULL)",
1639  $ilDB->quote($active_id . ""),
1640  $ilDB->quote($duplicate_id . ""),
1641  $ilDB->quote(($result->numRows()+1) . ""),
1642  $ilDB->quote($pass . "")
1643  );
1644  $result = $ilDB->query($query);
1645  }
1646  }
1647 
1659  function getRandomQuestionDuplicate($question_id, $active_id)
1660  {
1661  global $ilDB;
1662 
1663  $query = sprintf("SELECT qpl_questions.question_id FROM qpl_questions, tst_test_random_question WHERE qpl_questions.original_id = %s AND tst_test_random_question.question_fi = qpl_questions.question_id AND tst_test_random_question.active_fi = %s",
1664  $ilDB->quote($question_id . ""),
1665  $ilDB->quote($active_id . "")
1666  );
1667  $result = $ilDB->query($query);
1668  $num = $result->numRows();
1669  if ($num > 0)
1670  {
1671  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
1672  return $row["question_id"];
1673  }
1674  else
1675  {
1676  return FALSE;
1677  }
1678  }
1679 
1687  function getNrOfResultsForPass($active_id, $pass)
1688  {
1689  global $ilDB;
1690 
1691  $query = sprintf("SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
1692  $ilDB->quote($active_id . ""),
1693  $ilDB->quote($pass . "")
1694  );
1695  $result = $ilDB->query($query);
1696  return $result->numRows();
1697  }
1698 
1709  function hasRandomQuestionsForPass($active_id, $pass)
1710  {
1711  global $ilDB;
1712  $query = sprintf("SELECT test_random_question_id FROM tst_test_random_question WHERE active_fi = %s AND pass = %s",
1713  $ilDB->quote($active_id . ""),
1714  $ilDB->quote($pass . "")
1715  );
1716  $result = $ilDB->query($query);
1717  if ($result->numRows() > 0)
1718  {
1719  return TRUE;
1720  }
1721  else
1722  {
1723  return FALSE;
1724  }
1725  }
1726 
1735  function generateRandomQuestions($active_id, $pass = NULL)
1736  {
1737  global $ilUser;
1738  global $ilDB;
1739 
1740  if ($active_id > 0)
1741  {
1742  if ($this->hasRandomQuestionsForPass($active_id, $pass) > 0)
1743  {
1744  // Something went wrong. Maybe the user pressed the start button twice
1745  // Questions already exist so there is no need to create new questions
1746  return;
1747  }
1748  if ($pass > 0)
1749  {
1750  if ($this->getNrOfResultsForPass($active_id, $pass - 1) == 0)
1751  {
1752  // This means that someone maybe reloaded the test submission page
1753  // If there are no existing results for the previous test, it makes
1754  // no sense to create a new set of random questions
1755  return;
1756  }
1757  }
1758  }
1759  else
1760  {
1761  // This may not happen! If it happens, raise a fatal error...
1762  global $ilias, $ilErr;
1763  $ilias->raiseError(sprintf($this->lng->txt("error_random_question_generation"), $ilUser->getId(), $this->getTestId()), $ilErr->FATAL);
1764  }
1765 
1766  $num = $this->getRandomQuestionCount();
1767  if ($num > 0)
1768  {
1769  $qpls =& $this->getRandomQuestionpools();
1770  $rndquestions = $this->randomSelectQuestions($num, 0, 1, $qpls, $pass);
1771  $allquestions = array();
1772  foreach ($rndquestions as $question_id)
1773  {
1774  array_push($allquestions, $question_id);
1775  }
1776  if ($this->getShuffleQuestions())
1777  {
1778  srand ((float)microtime()*1000000);
1779  shuffle($allquestions);
1780  }
1781 
1782  $maxcount = 0;
1783  foreach ($qpls as $data)
1784  {
1785  $maxcount += $data["contains"];
1786  }
1787  if ($num > $maxcount) $num = $maxcount;
1788  foreach ($allquestions as $question_id)
1789  {
1790  $this->saveRandomQuestion($active_id, $question_id, $pass, $num);
1791  }
1792  }
1793  else
1794  {
1795  $qpls =& $this->getRandomQuestionpools();
1796  $allquestions = array();
1797  $maxcount = 0;
1798  foreach ($qpls as $key => $value)
1799  {
1800  if ($value["count"] > 0)
1801  {
1802  $rndquestions = $this->randomSelectQuestions($value["count"], $value["qpl"], 1, $pass);
1803  foreach ($rndquestions as $question_id)
1804  {
1805  array_push($allquestions, $question_id);
1806  }
1807  }
1808  $add = ($value["count"] <= $value["contains"]) ? $value["count"] : $value["contains"];
1809  $maxcount += $add;
1810  }
1811  if ($this->getShuffleQuestions())
1812  {
1813  srand ((float)microtime()*1000000);
1814  shuffle($allquestions);
1815  }
1816  foreach ($allquestions as $question_id)
1817  {
1818  $this->saveRandomQuestion($active_id, $question_id, $pass, $maxcount);
1819  }
1820  }
1821  }
1822 
1831  function saveRandomQuestionCount($total_questions = "NULL")
1832  {
1833  global $ilDB;
1834 
1835  if (strcmp($total_questions, "NULL") != 0)
1836  {
1837  $this->setRandomQuestionCount($total_questions);
1838  $total_questions = $ilDB->quote($total_questions);
1839  }
1840  $query = sprintf("UPDATE tst_tests SET random_question_count = %s WHERE test_id = %s",
1841  $total_questions,
1842  $ilDB->quote($this->getTestId() . "")
1843  );
1844  $result = $ilDB->query($query);
1845  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1847  {
1848  if (strcmp($total_questions, "NULL") == 0) $total_questions = '0';
1849  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_total_amount_of_questions", ilObjAssessmentFolder::_getLogLanguage()), $total_questions));
1850  }
1851  }
1852 
1862  function saveRandomQuestionpools($qpl_array)
1863  {
1864  global $ilDB;
1865 
1866  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1867  // delete existing random questionpools
1868  $query = sprintf("DELETE FROM tst_test_random WHERE test_fi = %s",
1869  $ilDB->quote($this->getTestId())
1870  );
1871  $result = $ilDB->query($query);
1873  {
1874  $this->logAction($this->lng->txtlng("assessment", "log_random_question_pool_deleted", ilObjAssessmentFolder::_getLogLanguage()));
1875  }
1876  // create new random questionpools
1877  foreach ($qpl_array as $key => $value) {
1878  if ($value["qpl"] > -1)
1879  {
1880  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1881  $count = ilObjQuestionPool::_getQuestionCount($value["qpl"]);
1882  if ($value["count"] > $count)
1883  {
1884  $value["count"] = $count;
1885  }
1886  $query = sprintf("INSERT INTO tst_test_random (test_random_id, test_fi, questionpool_fi, num_of_q, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
1887  $ilDB->quote($this->getTestId() . ""),
1888  $ilDB->quote($value["qpl"] . ""),
1889  $ilDB->quote(sprintf("%d", $value["count"]) . "")
1890  );
1891  $result = $ilDB->query($query);
1893  {
1894  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_random_question_pool_added", ilObjAssessmentFolder::_getLogLanguage()), $value["title"] . " (" . $value["qpl"] . ")", $value["count"]));
1895  }
1896  }
1897  }
1898  }
1899 
1910  {
1911  global $ilDB;
1912 
1913  $qpls = array();
1914  $counter = 0;
1915  $query = sprintf("SELECT tst_test_random.*, qpl_questionpool.questioncount FROM tst_test_random, qpl_questionpool WHERE tst_test_random.test_fi = %s AND tst_test_random.questionpool_fi = qpl_questionpool.obj_fi ORDER BY test_random_id",
1916  $ilDB->quote($this->getTestId() . "")
1917  );
1918  $result = $ilDB->query($query);
1919  if ($result->numRows())
1920  {
1921  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
1922  {
1923  $qpls[$counter] = array(
1924  "index" => $counter,
1925  "count" => $row["num_of_q"],
1926  "qpl" => $row["questionpool_fi"],
1927  "contains" => $row["questioncount"]
1928  );
1929  $counter++;
1930  }
1931  }
1932  return $qpls;
1933  }
1934 
1944  function loadFromDb()
1945  {
1946  global $ilDB;
1947 
1948  $query = sprintf("SELECT * FROM tst_tests WHERE obj_fi = %s",
1949  $ilDB->quote($this->getId())
1950  );
1951  $result = $ilDB->query($query);
1952  if ($result->numRows() == 1)
1953  {
1954  $data = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
1955  $this->test_id = $data->test_id;
1956  if (strlen($this->getAuthor()) == 0)
1957  {
1958  $this->saveAuthorToMetadata($data->author);
1959  }
1960  $this->author = $this->getAuthor();
1961  include_once("./Services/RTE/classes/class.ilRTE.php");
1962  $this->introduction = ilRTE::_replaceMediaObjectImageSrc($data->introduction, 1);
1963  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc($data->finalstatement, 1));
1964  $this->setShowInfo($data->showinfo);
1965  $this->setForceJS($data->forcejs);
1966  $this->setCustomStyle($data->customstyle);
1967  $this->setShowFinalStatement($data->showfinalstatement);
1968  $this->sequence_settings = $data->sequence_settings;
1969  $this->score_reporting = $data->score_reporting;
1970  $this->instant_verification = $data->instant_verification;
1971  $this->answer_feedback_points = $data->answer_feedback_points;
1972  $this->answer_feedback = $data->answer_feedback;
1973  $this->anonymity = $data->anonymity;
1974  $this->show_cancel = $data->show_cancel;
1975  $this->show_marker = $data->show_marker;
1976  $this->fixed_participants = $data->fixed_participants;
1977  $this->nr_of_tries = $data->nr_of_tries;
1978  $this->setKiosk($data->kiosk);
1979  $this->setUsePreviousAnswers($data->use_previous_answers);
1980  $this->setTitleOutput($data->title_output);
1981  $this->processing_time = $data->processing_time;
1982  $this->enable_processing_time = $data->enable_processing_time;
1983  $this->reset_processing_time = $data->reset_processing_time;
1984  $this->reporting_date = $data->reporting_date;
1985  $this->setShuffleQuestions($data->shuffle_questions);
1986  $this->setResultsPresentation($data->results_presentation);
1987  $this->setListOfQuestionsSettings($data->show_summary);
1988  $this->starting_time = $data->starting_time;
1989  $this->ending_time = $data->ending_time;
1990  $this->ects_output = $data->ects_output;
1991  $this->ects_grades = array(
1992  "A" => $data->ects_a,
1993  "B" => $data->ects_b,
1994  "C" => $data->ects_c,
1995  "D" => $data->ects_d,
1996  "E" => $data->ects_e
1997  );
1998  $this->ects_fx = $data->ects_fx;
1999  $this->random_test = $data->random_test;
2000  $this->random_question_count = $data->random_question_count;
2001  $this->mark_schema->flush();
2002  $this->mark_schema->loadFromDb($this->test_id);
2003  $this->count_system = $data->count_system;
2004  $this->mc_scoring = $data->mc_scoring;
2005  $this->setScoreCutting($data->score_cutting);
2006  $this->setPassword($data->password);
2007  $this->setAllowedUsers($data->allowedUsers);
2008  $this->setAllowedUsersTimeGap($data->allowedUsersTimeGap);
2009  $this->setPassScoring($data->pass_scoring);
2010  $this->setCertificateVisibility($data->certificate_visibility);
2011  $this->loadQuestions();
2012  }
2013  }
2014 
2023 function loadQuestions($active_id = "", $pass = NULL)
2024 {
2025  global $ilUser;
2026  global $ilDB;
2027 
2028  $this->questions = array();
2029  if (strcmp($active_id, "") == 0)
2030  {
2031  $active_id = $this->getActiveIdOfUser($ilUser->getId());
2032  }
2033  if ($this->isRandomTest())
2034  {
2035  if (is_null($pass))
2036  {
2037  $pass = $this->_getPass($active_id);
2038  }
2039  $query = sprintf("SELECT tst_test_random_question.* FROM tst_test_random_question, qpl_questions WHERE tst_test_random_question.active_fi = %s AND qpl_questions.question_id = tst_test_random_question.question_fi AND tst_test_random_question.pass = %s ORDER BY sequence",
2040  $ilDB->quote($active_id . ""),
2041  $ilDB->quote($pass . "")
2042  );
2043  $result = $ilDB->query($query);
2044  // The following is a fix for random tests prior to ILIAS 3.8. If someone started a random test in ILIAS < 3.8, there
2045  // is only one test pass (pass = 0) in tst_test_random_question while with ILIAS 3.8 there are questions for every test pass.
2046  // To prevent problems with tests started in an older version and continued in ILIAS 3.8, the first pass should be taken if
2047  // no questions are present for a newer pass.
2048  if ($result->numRows() == 0)
2049  {
2050  $query = sprintf("SELECT tst_test_random_question.* FROM tst_test_random_question, qpl_questions WHERE tst_test_random_question.active_fi = %s AND qpl_questions.question_id = tst_test_random_question.question_fi AND tst_test_random_question.pass = 0 ORDER BY sequence",
2051  $ilDB->quote($active_id . "")
2052  );
2053  $result = $ilDB->query($query);
2054  }
2055  }
2056  else
2057  {
2058  $query = sprintf("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",
2059  $ilDB->quote($this->test_id . "")
2060  );
2061  $result = $ilDB->query($query);
2062  }
2063  $index = 1;
2064  while ($data = $result->fetchRow(MDB2_FETCHMODE_OBJECT))
2065  {
2066  $this->questions[$index++] = $data->question_fi;
2067  }
2068 }
2069 
2080  {
2081  $this->introduction = $introduction;
2082  }
2083 
2093  public function setFinalStatement($a_statement = "")
2094  {
2095  $this->_finalstatement = $a_statement;
2096  }
2097 
2105  public function setShowInfo($a_boolean = TRUE)
2106  {
2107  if ($a_boolean)
2108  {
2109  $this->_showinfo = TRUE;
2110  }
2111  else
2112  {
2113  $this->_showinfo = FALSE;
2114  }
2115  }
2116 
2124  public function setForceJS($a_boolean = TRUE)
2125  {
2126  if ($a_boolean)
2127  {
2128  $this->_forcejs = TRUE;
2129  }
2130  else
2131  {
2132  $this->_forcejs = FALSE;
2133  }
2134  }
2135 
2143  public function setCustomStyle($a_customStyle = "")
2144  {
2145  $this->_customStyle = $a_customStyle;
2146  }
2147 
2155  public function getCustomStyle()
2156  {
2157  return $this->_customStyle;
2158  }
2159 
2167  public function getCustomStyles()
2168  {
2169  $css_path = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2170  $css_path = str_replace("ta.css", "customstyles", $css_path) . "/";
2171  $customstyles = array();
2172  if (is_dir($css_path))
2173  {
2174  $results = array();
2175  include_once "./Services/Utilities/classes/class.ilFileUtils.php";
2177  if (is_array($results["file"]))
2178  {
2179  foreach ($results["file"] as $filename)
2180  {
2181  if (strpos($filename, ".css"))
2182  {
2183  array_push($customstyles, $filename);
2184  }
2185  }
2186  }
2187  }
2188  return $customstyles;
2189  }
2190 
2198  public function getTestStyleLocation($mode = "output")
2199  {
2200  if (strlen($this->getCustomStyle()))
2201  {
2202  $default = ilUtil::getStyleSheetLocation("filesystem", "ta.css", "Modules/Test");
2203  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $default);
2204  if (file_exists($custom))
2205  {
2206  $custom = ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2207  $custom = str_replace("ta.css", "customstyles/" . $this->getCustomStyle(), $custom);
2208  return $custom;
2209  }
2210  else
2211  {
2212  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2213  }
2214  }
2215  else
2216  {
2217  return ilUtil::getStyleSheetLocation($mode, "ta.css", "Modules/Test");
2218  }
2219  }
2220 
2228  public function setShowFinalStatement($show = "")
2229  {
2230  if ($show)
2231  {
2232  $this->_showfinalstatement = TRUE;
2233  }
2234  else
2235  {
2236  $this->_showfinalstatement = FALSE;
2237  }
2238  }
2239 
2240 
2250  function isRandomTest()
2251  {
2252  return $this->random_test;
2253  }
2254 
2265  {
2267  }
2268 
2278  function getIntroduction()
2279  {
2280  return $this->introduction;
2281  }
2282 
2290  public function getFinalStatement()
2291  {
2292  return $this->_finalstatement;
2293  }
2294 
2302  public function getShowInfo()
2303  {
2304  return $this->_showinfo;
2305  }
2306 
2314  public function getForceJS()
2315  {
2316  return $this->_forcejs;
2317  }
2318 
2326  public function getShowFinalStatement()
2327  {
2329  }
2330 
2340  function getTestId()
2341  {
2342  return $this->test_id;
2343  }
2344 
2354  function getECTSOutput()
2355  {
2356  return $this->ects_output;
2357  }
2358 
2368  function setECTSOutput($a_ects_output)
2369  {
2370  $this->ects_output = $a_ects_output ? 1 : 0;
2371  }
2372 
2382  function getECTSFX()
2383  {
2384  return $this->ects_fx;
2385  }
2386 
2396  function setECTSFX($a_ects_fx)
2397  {
2398  $this->ects_fx = $a_ects_fx;
2399  }
2400 
2410  function &getECTSGrades()
2411  {
2412  return $this->ects_grades;
2413  }
2414 
2424  function setECTSGrades($a_ects_grades)
2425  {
2426  if (is_array($a_ects_grades))
2427  {
2428  $this->ects_grades = $a_ects_grades;
2429  }
2430  }
2431 
2442  {
2443  $this->sequence_settings = $sequence_settings;
2444  }
2445 
2456  {
2457  $this->score_reporting = $score_reporting;
2458  }
2459 
2469  function setInstantFeedbackSolution($instant_feedback = 0)
2470  {
2471  switch ($instant_feedback)
2472  {
2473  case 1:
2474  $this->instant_verification = 1;
2475  break;
2476  default:
2477  $this->instant_verification = 0;
2478  break;
2479  }
2480  }
2481 
2492  {
2493  switch ($answer_feedback)
2494  {
2495  case 1:
2496  $this->answer_feedback = 1;
2497  break;
2498  default:
2499  $this->answer_feedback = 0;
2500  break;
2501  }
2502  }
2503 
2514  {
2515  switch ($answer_feedback_points)
2516  {
2517  case 1:
2518  $this->answer_feedback_points = 1;
2519  break;
2520  default:
2521  $this->answer_feedback_points = 0;
2522  break;
2523  }
2524  }
2525 
2535  function setRandomTest($a_random_test = 0)
2536  {
2537  $this->random_test = $a_random_test;
2538  }
2539 
2549  function setRandomQuestionCount($a_random_question_count = "")
2550  {
2551  $this->random_question_count = $a_random_question_count;
2552  }
2553 
2564  {
2565  if (!$reporting_date)
2566  {
2567  $this->reporting_date = "";
2568  $this->ects_output = 0;
2569  }
2570  else
2571  {
2572  $this->reporting_date = $reporting_date;
2573  }
2574  }
2575 
2586  {
2587  return $this->sequence_settings;
2588  }
2589 
2600  {
2601  return $this->score_reporting;
2602  }
2603 
2614  {
2616  }
2617 
2628  {
2629  return $this->answer_feedback;
2630  }
2631 
2642  {
2644  }
2645 
2655  function getCountSystem()
2656  {
2657  return $this->count_system;
2658  }
2659 
2669  function _getCountSystem($active_id)
2670  {
2671  global $ilDB;
2672  $query = sprintf("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",
2673  $ilDB->quote($active_id)
2674  );
2675  $result = $ilDB->query($query);
2676  if ($result->numRows())
2677  {
2678  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
2679  return $row["count_system"];
2680  }
2681  return FALSE;
2682  }
2683 
2693  function getMCScoring()
2694  {
2695  return $this->mc_scoring;
2696  }
2697 
2707  function getScoreCutting()
2708  {
2709  return $this->score_cutting;
2710  }
2711 
2721  function getPassword()
2722  {
2723  return $this->password;
2724  }
2725 
2735  function getPassScoring()
2736  {
2737  return $this->pass_scoring;
2738  }
2739 
2749  function _getPassScoring($active_id)
2750  {
2751  global $ilDB;
2752  $query = sprintf("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",
2753  $ilDB->quote($active_id . "")
2754  );
2755  $result = $ilDB->query($query);
2756  if ($result->numRows())
2757  {
2758  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
2759  return $row["pass_scoring"];
2760  }
2761  return 0;
2762  }
2763 
2773  function _getMCScoring($active_id)
2774  {
2775  global $ilDB;
2776  $query = sprintf("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",
2777  $ilDB->quote($active_id)
2778  );
2779  $result = $ilDB->query($query);
2780  if ($result->numRows())
2781  {
2782  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
2783  return $row["mc_scoring"];
2784  }
2785  return FALSE;
2786  }
2787 
2797  function _getScoreCutting($active_id)
2798  {
2799  global $ilDB;
2800  $query = sprintf("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",
2801  $ilDB->quote($active_id)
2802  );
2803  $result = $ilDB->query($query);
2804  if ($result->numRows())
2805  {
2806  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
2807  return $row["score_cutting"];
2808  }
2809  return FALSE;
2810  }
2811 
2821  function getReportingDate()
2822  {
2823  return $this->reporting_date;
2824  }
2825 
2835  function getNrOfTries()
2836  {
2837  return $this->nr_of_tries;
2838  }
2839 
2849  function getKiosk()
2850  {
2851  return $this->_kiosk;
2852  }
2853 
2854 
2864  function setKiosk($kiosk = 0)
2865  {
2866  $this->_kiosk = $kiosk;
2867  }
2868 
2878  function getKioskMode()
2879  {
2880  if (($this->_kiosk & 1) > 0)
2881  {
2882  return TRUE;
2883  }
2884  else
2885  {
2886  return FALSE;
2887  }
2888  }
2889 
2899  public function setKioskMode($a_kiosk = FALSE)
2900  {
2901  if ($a_kiosk)
2902  {
2903  $this->_kiosk = $this->_kiosk | 1;
2904  }
2905  else
2906  {
2907  if ($this->getKioskMode())
2908  {
2909  $this->_kiosk = $this->_kiosk ^ 1;
2910  }
2911  }
2912  }
2913 
2923  public function getShowKioskModeTitle()
2924  {
2925  if (($this->_kiosk & 2) > 0)
2926  {
2927  return TRUE;
2928  }
2929  else
2930  {
2931  return FALSE;
2932  }
2933  }
2934 
2943  public function setShowKioskModeTitle($a_title = FALSE)
2944  {
2945  if ($a_title)
2946  {
2947  $this->_kiosk = $this->_kiosk | 2;
2948  }
2949  else
2950  {
2951  if ($this->getShowKioskModeTitle())
2952  {
2953  $this->_kiosk = $this->_kiosk ^ 2;
2954  }
2955  }
2956  }
2957 
2968  {
2969  if (($this->_kiosk & 4) > 0)
2970  {
2971  return TRUE;
2972  }
2973  else
2974  {
2975  return FALSE;
2976  }
2977  }
2978 
2987  public function setShowKioskModeParticipant($a_participant = FALSE)
2988  {
2989  if ($a_participant)
2990  {
2991  $this->_kiosk = $this->_kiosk | 4;
2992  }
2993  else
2994  {
2995  if ($this->getShowKioskModeParticipant())
2996  {
2997  $this->_kiosk = $this->_kiosk ^ 4;
2998  }
2999  }
3000  }
3001 
3012  {
3014  }
3015 
3025  function getTitleOutput()
3026  {
3027  return $this->title_output;
3028  }
3029 
3040  function _getTitleOutput($active_id)
3041  {
3042  global $ilDB;
3043 
3044  $query = sprintf("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",
3045  $ilDB->quote($active_id . "")
3046  );
3047  $result = $ilDB->query($query);
3048  if ($result->numRows())
3049  {
3050  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
3051  return $row["title_output"];
3052  }
3053  return 0;
3054  }
3055 
3067  function _getUsePreviousAnswers($active_id, $user_active_user_setting = false)
3068  {
3069  global $ilDB;
3070  global $ilUser;
3071 
3073 
3074  $query = sprintf("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",
3075  $ilDB->quote($active_id . "")
3076  );
3077  $result = $ilDB->query($query);
3078  if ($result->numRows())
3079  {
3080  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
3081  $use_previous_answers = $row["use_previous_answers"];
3082  }
3083 
3084  if ($use_previous_answers == 1)
3085  {
3086  if ($user_active_user_setting)
3087  {
3088  $res = $ilUser->getPref("tst_use_previous_answers");
3089  if ($res !== FALSE)
3090  {
3092  }
3093  }
3094  }
3095  return $use_previous_answers;
3096  }
3097 
3108  {
3109  return $this->processing_time;
3110  }
3111 
3122  {
3123  if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches))
3124  {
3125  return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3];
3126  }
3127  else
3128  {
3129  return 0;
3130  }
3131  }
3132 
3143  {
3144  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndingTime(), $matches))
3145  {
3146  $ending = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
3147  $now = time();
3148  return $ending - $now;
3149  }
3150  else
3151  {
3152  return 0;
3153  }
3154  }
3155 
3166  {
3168  }
3169 
3180  {
3182  }
3183 
3193  function getStartingTime()
3194  {
3195  return $this->starting_time;
3196  }
3197 
3207  function getEndingTime()
3208  {
3209  return $this->ending_time;
3210  }
3211 
3222  {
3223  $this->nr_of_tries = $nr_of_tries;
3224  }
3225 
3236  {
3238  {
3239  $this->use_previous_answers = 1;
3240  }
3241  else
3242  {
3243  $this->use_previous_answers = 0;
3244  }
3245  }
3246 
3257  {
3258  switch ($title_output)
3259  {
3260  case 1:
3261  $this->title_output = 1;
3262  break;
3263  case 2:
3264  $this->title_output = 2;
3265  break;
3266  default:
3267  $this->title_output = 0;
3268  break;
3269  }
3270  }
3271 
3281  function setProcessingTime($processing_time = "00:00:00")
3282  {
3283  $this->processing_time = $processing_time;
3284  }
3285 
3295  function setEnableProcessingTime($enable = 0)
3296  {
3297  if ($enable) {
3298  $this->enable_processing_time = "1";
3299  } else {
3300  $this->enable_processing_time = "0";
3301  }
3302  }
3303 
3313  function setResetProcessingTime($reset = 0)
3314  {
3315  if ($reset)
3316  {
3317  $this->reset_processing_time = 1;
3318  }
3319  else
3320  {
3321  $this->reset_processing_time = 0;
3322  }
3323  }
3324 
3335  {
3336  $this->starting_time = $starting_time;
3337  }
3338 
3349  {
3350  $this->ending_time = $ending_time;
3351  }
3352 
3362  function setCountSystem($a_count_system = COUNT_PARTIAL_SOLUTIONS)
3363  {
3364  $this->count_system = $a_count_system;
3365  }
3366 
3376  function setPassword($a_password = "")
3377  {
3378  $this->password = $a_password;
3379  }
3380 
3390  function setScoreCutting($a_score_cutting = SCORE_CUT_QUESTION)
3391  {
3392  $this->score_cutting = $a_score_cutting;
3393  }
3394 
3405  {
3406  $this->mc_scoring = $a_mc_scoring;
3407  }
3408 
3418  function setPassScoring($a_pass_scoring = SCORE_LAST_PASS)
3419  {
3420  switch ($a_pass_scoring)
3421  {
3422  case SCORE_BEST_PASS:
3423  $this->pass_scoring = SCORE_BEST_PASS;
3424  break;
3425  default:
3426  $this->pass_scoring = SCORE_LAST_PASS;
3427  break;
3428  }
3429  }
3430 
3440  function removeQuestion($question_id)
3441  {
3442  $question =& ilObjTest::_instanciateQuestion($question_id);
3443  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3445  {
3446  $this->logAction($this->lng->txtlng("assessment", "log_question_removed", ilObjAssessmentFolder::_getLogLanguage()), $question_id);
3447  }
3448  $question->delete($question_id);
3449  $this->removeAllTestEditings($question_id);
3450  $this->loadQuestions();
3451  $this->saveQuestionsToDb();
3452  }
3453 
3465  function removeAllTestEditings($question_id = "")
3466  {
3467  global $ilDB;
3468  // remove the question from tst_solutions
3469  if ($question_id)
3470  {
3471  $query = sprintf("DELETE FROM tst_solutions USING tst_solutions, tst_active where tst_solutions.active_fi = tst_active.active_id AND tst_active.test_fi = %s AND tst_solutions.question_fi = %s",
3472  $ilDB->quote($this->getTestId()),
3473  $ilDB->quote($question_id)
3474  );
3475  $query2 = sprintf("DELETE FROM tst_active_qst_sol_settings USING tst_active_qst_sol_settings, tst_active where tst_active_qst_sol_settings.active_fi = tst_active.active_id AND tst_active.test_fi = %s AND tst_active_qst_sol_settings.question_fi = %s",
3476  $ilDB->quote($this->getTestId()),
3477  $ilDB->quote($question_id)
3478  );
3479  $query3 = sprintf("DELETE FROM tst_test_result USING tst_test_result, tst_active WHERE tst_active.test_fi = %s AND tst_test_result.question_fi = %s AND tst_active.active_id = tst_test_result.active_fi",
3480  $ilDB->quote($this->getTestId()),
3481  $ilDB->quote($question_id)
3482  );
3483  $query4 = sprintf("DELETE FROM tst_test_pass_result USING tst_test_pass_result, tst_active WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_test_pass_result.active_fi",
3484  $ilDB->quote($this->getTestId())
3485  );
3486  }
3487  else
3488  {
3489  $query = sprintf("DELETE FROM tst_solutions USING tst_solutions, tst_active where tst_solutions.active_fi = tst_active.active_id AND tst_active.test_fi = %s",
3490  $ilDB->quote($this->getTestId())
3491  );
3492  $query2 = sprintf("DELETE FROM tst_active_qst_sol_settings USING tst_active_qst_sol_settings, tst_active where tst_active_qst_sol_settings.active_fi = tst_active.active_id AND tst_active.test_fi = %s",
3493  $ilDB->quote($this->getTestId())
3494  );
3495  $query3 = sprintf("DELETE FROM tst_test_result USING tst_test_result, tst_active WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_test_result.active_fi",
3496  $ilDB->quote($this->getTestId())
3497  );
3498  $query4 = sprintf("DELETE FROM tst_test_pass_result USING tst_test_pass_result, tst_active WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_test_pass_result.active_fi",
3499  $ilDB->quote($this->getTestId())
3500  );
3501  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3503  {
3504  $this->logAction($this->lng->txtlng("assessment", "log_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()));
3505  }
3506  }
3507  $query5 = sprintf("DELETE FROM tst_sequence USING tst_sequence, tst_active WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_sequence.active_fi",
3508  $ilDB->quote($this->getTestId())
3509  );
3510  $result = $ilDB->query($query);
3511  $result = $ilDB->query($query2);
3512  $result = $ilDB->query($query3);
3513  $result = $ilDB->query($query4);
3514  $result = $ilDB->query($query5);
3515 
3516  if ($this->isRandomTest())
3517  {
3518  $query = sprintf("DELETE FROM tst_test_random_question USING tst_test_random_question, tst_active WHERE tst_active.test_fi = %s AND tst_test_random_question.active_fi = tst_active.active_id",
3519  $ilDB->quote($this->getTestId())
3520  );
3521  $result = $ilDB->query($query);
3522  }
3523 
3524  // remove test_active entries, because test has changed
3525  $query = sprintf("DELETE FROM tst_active WHERE test_fi = %s",
3526  $ilDB->quote($this->getTestId())
3527  );
3528  $result = $ilDB->query($query);
3529 
3530  // remove saved user passwords
3531  $query = sprintf("DELETE FROM usr_pref WHERE keyword = %s",
3532  $ilDB->quote("tst_password_".$this->getTestId())
3533  );
3534  $result = $ilDB->query($query);
3535  }
3536 
3537  function removeSelectedTestResults($active_ids)
3538  {
3539  global $ilDB;
3540 
3541  // remove the question from tst_solutions
3542  foreach ($active_ids as $active_id)
3543  {
3544  $query = sprintf("DELETE FROM tst_solutions WHERE active_fi = %s",
3545  $ilDB->quote($active_id . "")
3546  );
3547  $query2 = sprintf("DELETE FROM tst_active_qst_sol_settings WHERE active_fi = %s",
3548  $ilDB->quote($active_id . "")
3549  );
3550  $query3 = sprintf("DELETE FROM tst_test_result WHERE active_fi = %s",
3551  $ilDB->quote($active_id . "")
3552  );
3553  $query4 = sprintf("DELETE FROM tst_test_pass_result WHERE active_fi = %s",
3554  $ilDB->quote($active_id . "")
3555  );
3556  $result = $ilDB->query($query);
3557  $result = $ilDB->query($query2);
3558  $result = $ilDB->query($query3);
3559  $result = $ilDB->query($query4);
3560 
3561  if ($this->isRandomTest())
3562  {
3563  $query = sprintf("DELETE FROM tst_test_random_question WHERE active_fi = %s",
3564  $ilDB->quote($active_id . "")
3565  );
3566  $result = $ilDB->query($query);
3567  }
3568 
3569  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3571  {
3572  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3573  }
3574  }
3575 
3576  // remove test_active entries of selected users
3577  foreach ($active_ids as $active_id)
3578  {
3579  $usr_id = $this->_getUserIdFromActiveId($active_id);
3580 
3581  $query = sprintf("DELETE FROM tst_active WHERE active_id = %s",
3582  $ilDB->quote($active_id . "")
3583  );
3584  $result = $ilDB->query($query);
3585 
3586  $query = sprintf("DELETE FROM tst_sequence WHERE active_fi = %s",
3587  $ilDB->quote($active_id)
3588  );
3589  $result = $ilDB->query($query);
3590 
3591  // remove saved user password
3592  if ($usr_id > 0)
3593  {
3594  $query = sprintf("DELETE FROM usr_pref WHERE usr_id = %s AND keyword = %s",
3595  $ilDB->quote($usr_id),
3596  $ilDB->quote("tst_password_".$this->getTestId())
3597  );
3598  $result = $ilDB->query($query);
3599  }
3600  }
3601  }
3602 
3603  function removeTestResultsForUser($user_id)
3604  {
3605  global $ilDB;
3606 
3607  $active_id = $this->getActiveIdOfUser($user_id);
3608 
3609  // remove the question from tst_solutions
3610  $query = sprintf("DELETE FROM tst_solutions WHERE active_fi = %s",
3611  $ilDB->quote($active_id . "")
3612  );
3613  $query2 = sprintf("DELETE FROM tst_active_qst_sol_settings WHERE active_fi = %s",
3614  $ilDB->quote($active_id . "")
3615  );
3616  $query3 = sprintf("DELETE FROM tst_test_result WHERE active_fi = %s",
3617  $ilDB->quote($active_id . "")
3618  );
3619  $query4 = sprintf("DELETE FROM tst_test_pass_result WHERE active_fi = %s",
3620  $ilDB->quote($active_id . "")
3621  );
3622  $result = $ilDB->query($query);
3623  $result = $ilDB->query($query2);
3624  $result = $ilDB->query($query3);
3625  $result = $ilDB->query($query4);
3626 
3627  if ($this->isRandomTest())
3628  {
3629  $query = sprintf("DELETE FROM tst_test_random_question WHERE active_fi = %s",
3630  $ilDB->quote($active_id . "")
3631  );
3632  $result = $ilDB->query($query);
3633  }
3634 
3635  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3637  {
3638  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_selected_user_data_removed", ilObjAssessmentFolder::_getLogLanguage()), $this->userLookupFullName($this->_getUserIdFromActiveId($active_id))));
3639  }
3640 
3641  $query = sprintf("DELETE FROM tst_sequence WHERE active_fi = %s",
3642  $ilDB->quote($active_id)
3643  );
3644  $result = $ilDB->query($query);
3645 
3646  // remove test_active entry
3647  $query = sprintf("DELETE FROM tst_active WHERE active_id = %s",
3648  $ilDB->quote($active_id . "")
3649  );
3650  $result = $ilDB->query($query);
3651 
3652  // remove saved user password
3653  if ($user_id > 0)
3654  {
3655  $query = sprintf("DELETE FROM usr_pref WHERE usr_id = %s AND keyword = %s",
3656  $ilDB->quote($user_id),
3657  $ilDB->quote("tst_password_".$this->getTestId())
3658  );
3659  $result = $ilDB->query($query);
3660  }
3661  }
3662 
3672  function questionMoveUp($question_id)
3673  {
3674  global $ilDB;
3675 
3676  // Move a question up in sequence
3677  $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3678  $ilDB->quote($this->getTestId()),
3679  $ilDB->quote($question_id)
3680  );
3681  $result = $ilDB->query($query);
3682  $data = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
3683  if ($data->sequence > 1) {
3684  // OK, it's not the top question, so move it up
3685  $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3686  $ilDB->quote($this->getTestId()),
3687  $ilDB->quote($data->sequence - 1)
3688  );
3689  $result = $ilDB->query($query);
3690  $data_previous = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
3691  // change previous dataset
3692  $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3693  $ilDB->quote($data->sequence),
3694  $ilDB->quote($data_previous->test_question_id)
3695  );
3696  $result = $ilDB->query($query);
3697  // move actual dataset up
3698  $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3699  $ilDB->quote($data->sequence - 1),
3700  $ilDB->quote($data->test_question_id)
3701  );
3702  $result = $ilDB->query($query);
3703  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3705  {
3706  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence-1), $question_id);
3707  }
3708  }
3709  $this->loadQuestions();
3710  }
3711 
3719  function questionMoveDown($question_id)
3720  {
3721  global $ilDB;
3722 
3723  // Move a question down in sequence
3724  $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
3725  $ilDB->quote($this->getTestId()),
3726  $ilDB->quote($question_id)
3727  );
3728  $result = $ilDB->query($query);
3729  $data = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
3730  $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
3731  $ilDB->quote($this->getTestId()),
3732  $ilDB->quote($data->sequence + 1)
3733  );
3734  $result = $ilDB->query($query);
3735  if ($result->numRows() == 1)
3736  {
3737  // OK, it's not the last question, so move it down
3738  $data_next = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
3739  // change next dataset
3740  $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3741  $ilDB->quote($data->sequence),
3742  $ilDB->quote($data_next->test_question_id)
3743  );
3744  $result = $ilDB->query($query);
3745  // move actual dataset down
3746  $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
3747  $ilDB->quote($data->sequence + 1),
3748  $ilDB->quote($data->test_question_id)
3749  );
3750  $result = $ilDB->query($query);
3751  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3753  {
3754  $this->logAction($this->lng->txtlng("assessment", "log_question_position_changed", ilObjAssessmentFolder::_getLogLanguage()) . ": " . ($data->sequence) . " => " . ($data->sequence+1), $question_id);
3755  }
3756  }
3757  $this->loadQuestions();
3758  }
3759 
3769  function duplicateQuestionForTest($question_id)
3770  {
3771  global $ilUser;
3772  $question =& ilObjTest::_instanciateQuestion($question_id);
3773  $duplicate_id = $question->duplicate(true);
3774 
3775  return $duplicate_id;
3776  }
3777 
3786  function insertQuestion($question_id)
3787  {
3788  global $ilDB;
3789 
3790  $duplicate_id = $this->duplicateQuestionForTest($question_id);
3791 
3792  // get maximum sequence index in test
3793  $query = sprintf("SELECT MAX(sequence) AS seq FROM tst_test_question WHERE test_fi=%s",
3794  $ilDB->quote($this->getTestId())
3795  );
3796  $result = $ilDB->query($query);
3797  $sequence = 1;
3798 
3799  if ($result->numRows() == 1)
3800  {
3801  $data = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
3802  $sequence = $data->seq + 1;
3803  }
3804 
3805  $query = sprintf("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
3806  $ilDB->quote($this->getTestId()),
3807  $ilDB->quote($duplicate_id),
3808  $ilDB->quote($sequence)
3809  );
3810  $result = $ilDB->query($query);
3811  if (PEAR::isError($result))
3812  {
3813  global $ilias;
3814  $ilias->raiseError($result->getMessage());
3815  }
3816  else
3817  {
3818  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3820  {
3821  $this->logAction($this->lng->txtlng("assessment", "log_question_added", ilObjAssessmentFolder::_getLogLanguage()) . ": " . $sequence, $duplicate_id);
3822  }
3823  }
3824  // remove test_active entries, because test has changed
3825  $query = sprintf("DELETE FROM tst_active WHERE test_fi = %s",
3826  $ilDB->quote($this->getTestId())
3827  );
3828  $result = $ilDB->query($query);
3829  $this->loadQuestions();
3830  $this->saveCompleteStatus();
3831  }
3832 
3840  function &getQuestionTitles()
3841  {
3842  $titles = array();
3843  if (!$this->isRandomTest())
3844  {
3845  global $ilDB;
3846  $query = sprintf("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",
3847  $ilDB->quote($this->getTestId() . "")
3848  );
3849  $result = $ilDB->query($query);
3850  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
3851  {
3852  array_push($titles, $row["title"]);
3853  }
3854  }
3855  return $titles;
3856  }
3857 
3866  {
3867  $titles = array();
3868  if (!$this->isRandomTest())
3869  {
3870  global $ilDB;
3871  $query = sprintf("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",
3872  $ilDB->quote($this->getTestId() . "")
3873  );
3874  $result = $ilDB->query($query);
3875  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
3876  {
3877  $titles[$row['question_id']] = $row["title"];
3878  }
3879  }
3880  return $titles;
3881  }
3882 
3894  {
3895  if ($this->getTitleOutput() == 2)
3896  {
3897  return $this->lng->txt("ass_question");
3898  }
3899  else
3900  {
3901  return $title;
3902  }
3903  }
3904 
3915  function getQuestionDataset($question_id)
3916  {
3917  global $ilDB;
3918 
3919  $query = sprintf("SELECT qpl_questions.*, qpl_question_type.type_tag FROM qpl_questions, qpl_question_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_question_type.question_type_id",
3920  $ilDB->quote("$question_id")
3921  );
3922  $result = $ilDB->query($query);
3923  $row = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
3924  return $row;
3925  }
3926 
3935  function &getExistingQuestions($pass = NULL)
3936  {
3937  global $ilUser;
3938  global $ilDB;
3939 
3940  $existing_questions = array();
3941  $active_id = $this->getActiveIdOfUser($ilUser->getId());
3942  if ($this->isRandomTest())
3943  {
3944  if (is_null($pass)) $pass = 0;
3945  $query = sprintf("SELECT qpl_questions.original_id FROM qpl_questions, tst_test_random_question WHERE tst_test_random_question.active_fi = %s AND tst_test_random_question.question_fi = qpl_questions.question_id AND tst_test_random_question.pass = %s",
3946  $ilDB->quote($active_id . ""),
3947  $ilDB->quote($pass . "")
3948  );
3949  }
3950  else
3951  {
3952  $query = sprintf("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",
3953  $ilDB->quote($this->getTestId())
3954  );
3955  }
3956  $result = $ilDB->query($query);
3957  while ($data = $result->fetchRow(MDB2_FETCHMODE_OBJECT)) {
3958  array_push($existing_questions, $data->original_id);
3959  }
3960  return $existing_questions;
3961  }
3962 
3972  function getQuestionType($question_id)
3973  {
3974  global $ilDB;
3975 
3976  if ($question_id < 1)
3977  return -1;
3978  $query = sprintf("SELECT type_tag FROM qpl_questions, qpl_question_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_question_type.question_type_id",
3979  $ilDB->quote($question_id)
3980  );
3981  $result = $ilDB->query($query);
3982  if ($result->numRows() == 1) {
3983  $data = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
3984  return $data->type_tag;
3985  } else {
3986  return "";
3987  }
3988  }
3989 
3998  function startWorkingTime($active_id, $pass)
3999  {
4000  global $ilDB;
4001 
4002  $q = sprintf("INSERT INTO tst_times (times_id, active_fi, started, finished, pass, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, NULL)",
4003  $ilDB->quote($active_id),
4004  $ilDB->quote(strftime("%Y-%m-%d %H:%M:%S")),
4005  $ilDB->quote(strftime("%Y-%m-%d %H:%M:%S")),
4006  $ilDB->quote($pass)
4007  );
4008  $result = $ilDB->query($q);
4009  return $ilDB->getLastInsertId();
4010  }
4011 
4020  function updateWorkingTime($times_id)
4021  {
4022  global $ilDB;
4023 
4024  $q = sprintf("UPDATE tst_times SET finished = %s WHERE times_id = %s",
4025  $ilDB->quote(strftime("%Y-%m-%d %H:%M:%S")),
4026  $ilDB->quote($times_id)
4027  );
4028  $result = $ilDB->query($q);
4029  }
4030 
4039  function &getWorkedQuestions($active_id, $pass = NULL)
4040  {
4041  global $ilUser;
4042  global $ilDB;
4043 
4044  if (is_null($pass))
4045  {
4046  $query = sprintf("SELECT * FROM tst_solutions WHERE active_fi = %s AND pass = 0 GROUP BY question_fi",
4047  $ilDB->quote($active_id . "")
4048  );
4049  }
4050  else
4051  {
4052  $query = sprintf("SELECT * FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
4053  $ilDB->quote($active_id . ""),
4054  $ilDB->quote($pass . "")
4055  );
4056  }
4057  $result = $ilDB->query($query);
4058  $result_array = array();
4059  while ($row = $result->fetchRow(MDB2_FETCHMODE_OBJECT))
4060  {
4061  array_push($result_array, $row->question_fi);
4062  }
4063  return $result_array;
4064  }
4065 
4076  function isTestFinishedToViewResults($active_id, $currentpass)
4077  {
4078  $num = $this->getPassFinishDate($active_id, $currentpass);
4079  if (($currentpass > 0) && ($num == 0))
4080  {
4081  return TRUE;
4082  }
4083  else
4084  {
4085  return FALSE;
4086  }
4087  }
4088 
4097  function &getAllQuestions($pass = NULL)
4098  {
4099  global $ilUser;
4100  global $ilDB;
4101 
4102  $result_array = array();
4103  if ($this->isRandomTest())
4104  {
4105  $active_id = $this->getActiveIdOfUser($ilUser->getId());
4106  $this->loadQuestions($active_id, $pass);
4107  if (count($this->questions) == 0) return $result_array;
4108  if (is_null($pass))
4109  {
4110  $pass = $this->_getPass($active_id);
4111  }
4112  $query = sprintf("SELECT qpl_questions.* FROM qpl_questions, tst_test_random_question WHERE tst_test_random_question.question_fi = qpl_questions.question_id AND tst_test_random_question.active_fi = %s AND tst_test_random_question.pass = %s AND qpl_questions.question_id IN ('" . join($this->questions, "','") . "')",
4113  $ilDB->quote($active_id . ""),
4114  $ilDB->quote($pass . "")
4115  );
4116  }
4117  else
4118  {
4119  if (count($this->questions) == 0) return $result_array;
4120  $query = "SELECT qpl_questions.* FROM qpl_questions, tst_test_question WHERE tst_test_question.question_fi = qpl_questions.question_id AND qpl_questions.question_id IN ('" . join($this->questions, "','") . "')";
4121  }
4122  $result = $ilDB->query($query);
4123  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4124  {
4125  $result_array[$row["question_id"]] = $row;
4126  }
4127  return $result_array;
4128  }
4129 
4140  function getActiveIdOfUser($user_id = "", $anonymous_id = "")
4141  {
4142  global $ilDB;
4143  global $ilUser;
4144 
4145  if (!$user_id) $user_id = $ilUser->getId();
4146  if (($_SESSION["AccountId"] == ANONYMOUS_USER_ID) && (strlen($_SESSION["tst_access_code"][$this->getTestId()])))
4147  {
4148  $query = sprintf("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4149  $ilDB->quote($user_id),
4150  $ilDB->quote($this->test_id),
4151  $ilDB->quote($_SESSION["tst_access_code"][$this->getTestId()])
4152  );
4153  }
4154  else if (strlen($anonymous_id))
4155  {
4156  $query = sprintf("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s",
4157  $ilDB->quote($user_id),
4158  $ilDB->quote($this->test_id),
4159  $ilDB->quote($anonymous_id)
4160  );
4161  }
4162  else
4163  {
4164  if ($_SESSION["AccountId"] == ANONYMOUS_USER_ID)
4165  {
4166  return NULL;
4167  }
4168  $query = sprintf("SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4169  $ilDB->quote($user_id),
4170  $ilDB->quote($this->test_id)
4171  );
4172  }
4173  $result = $ilDB->query($query);
4174  if ($result->numRows())
4175  {
4176  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
4177  return $row["active_id"];
4178  }
4179  else
4180  {
4181  return 0;
4182  }
4183  }
4184 
4195  function _getActiveIdOfUser($user_id = "", $test_id = "")
4196  {
4197  global $ilDB;
4198  global $ilUser;
4199 
4200  if (!$user_id) {
4201  $user_id = $ilUser->id;
4202  }
4203  if (!$test_id)
4204  {
4205  return "";
4206  }
4207  $query = sprintf("SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
4208  $ilDB->quote($user_id . ""),
4209  $ilDB->quote($test_id . "")
4210  );
4211 
4212  $result = $ilDB->query($query);
4213  if ($result->numRows())
4214  {
4215  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
4216  return $row["active_id"];
4217  }
4218  else
4219  {
4220  return "";
4221  }
4222  }
4223 
4232  function pcArrayShuffle($array)
4233  {
4234  mt_srand((double)microtime()*1000000);
4235  $i = count($array);
4236  if ($i > 0)
4237  {
4238  while(--$i)
4239  {
4240  $j = mt_rand(0, $i);
4241  if ($i != $j)
4242  {
4243  // swap elements
4244  $tmp = $array[$j];
4245  $array[$j] = $array[$i];
4246  $array[$i] = $tmp;
4247  }
4248  }
4249  }
4250  return $array;
4251  }
4252 
4262  function &getTestResult($active_id, $pass = NULL, $ordered_sequence = FALSE)
4263  {
4264  // global $ilBench;
4265  $total_max_points = 0;
4266  $total_reached_points = 0;
4267 
4268  $key = 1;
4269  $result_array = array();
4270  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
4271  $workedthrough = 0;
4272 
4273  if (is_null($pass))
4274  {
4275  $pass = $this->_getResultPass($active_id);
4276  }
4277  include_once "./Modules/Test/classes/class.ilTestSequence.php";
4278  $testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
4279  $sequence = array();
4280  if ($ordered_sequence)
4281  {
4282  $sequence = $testSequence->getOrderedSequence();
4283  }
4284  else
4285  {
4286  $sequence = $testSequence->getUserSequence();
4287  }
4288  foreach ($sequence as $sequenceindex)
4289  {
4290  $value = $testSequence->getQuestionForSequence($sequenceindex);
4291  $max_points = assQuestion::_getMaximumPoints($value);
4292  $total_max_points += $max_points;
4293  $reached_points = assQuestion::_getReachedPoints($active_id, $value, $pass);
4294  if (assQuestion::_isWorkedThrough($active_id, $value, $pass))
4295  {
4296  $workedthrough = 1;
4297  }
4298  else
4299  {
4300  $workedthrough = 0;
4301  }
4302  $total_reached_points += $reached_points;
4303  if ($max_points > 0)
4304  {
4305  $percentvalue = $reached_points / $max_points;
4306  }
4307  else
4308  {
4309  $percentvalue = 0;
4310  }
4311  if ($percentvalue < 0) $percentvalue = 0.0;
4312  if (assQuestion::_getSuggestedSolutionCount($value) == 1)
4313  {
4314  $solution_array =& assQuestion::_getSuggestedSolution($value, 0);
4315  $href = assQuestion::_getInternalLinkHref($solution_array["internal_link"]);
4316  }
4317  elseif (assQuestion::_getSuggestedSolutionCount($value) > 1)
4318  {
4319  $href = "see_details_for_further_information";
4320  }
4321  else
4322  {
4323  $href = "";
4324  }
4325  $info =& assQuestion::_getQuestionInfo($value);
4326  include_once "./Services/Utilities/classes/class.ilUtil.php";
4327  $row = array(
4328  "nr" => "$key",
4329  "title" => ilUtil::prepareFormOutput($this->getQuestionTitle($info["title"])),
4330  "max" => $max_points,
4331  "reached" => $reached_points,
4332  "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
4333  "solution" => $href,
4334  "type" => $info["type_tag"],
4335  "qid" => $value,
4336  "original_id" => $info["original_id"],
4337  "workedthrough" => $workedthrough
4338  );
4339  array_push($result_array, $row);
4340  $key++;
4341  }
4342 
4343  if ($this->getScoreCutting() == 1)
4344  {
4345  if ($total_reached_points < 0)
4346  {
4347  $total_reached_points = 0;
4348  }
4349  }
4350  $result_array["test"]["total_max_points"] = $total_max_points;
4351  $result_array["test"]["total_reached_points"] = $total_reached_points;
4352  if ((!$total_reached_points) or (!$total_max_points))
4353  {
4354  $percentage = 0.0;
4355  }
4356  else
4357  {
4358  $percentage = ($total_reached_points / $total_max_points) * 100.0;
4359  if ($percentage < 0) $percentage = 0.0;
4360  }
4361  $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4362  $passed = "";
4363  if ($mark_obj)
4364  {
4365  if ($mark_obj->getPassed())
4366  {
4367  $passed = 1;
4368  }
4369  else
4370  {
4371  $passed = 0;
4372  }
4373  }
4374  $result_array["test"]["passed"] = $passed;
4375  return $result_array;
4376  }
4377 
4386  function evalTotalPersons()
4387  {
4388  global $ilDB;
4389 
4390  $q = sprintf("SELECT COUNT(*) as total FROM tst_active WHERE test_fi = %s",
4391  $ilDB->quote($this->getTestId())
4392  );
4393  $result = $ilDB->query($q);
4394  $row = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
4395  return $row->total;
4396  }
4397 
4406  function getCompleteWorkingTime($user_id)
4407  {
4408  global $ilDB;
4409 
4410  $q = sprintf("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",
4411  $ilDB->quote($this->getTestId()),
4412  $ilDB->quote($user_id)
4413  );
4414  $result = $ilDB->query($q);
4415  $time = 0;
4416  while ($row = $result->fetchRow(MDB2_FETCHMODE_OBJECT))
4417  {
4418  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4419  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4420  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4421  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4422  $time += ($epoch_2 - $epoch_1);
4423  }
4424  return $time;
4425  }
4426 
4436  {
4437  return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
4438  }
4439 
4450  {
4451  global $ilDB;
4452 
4453  $query = sprintf("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",
4454  $ilDB->quote($test_id . "")
4455  );
4456  $result = $ilDB->query($query);
4457  $time = 0;
4458  $times = array();
4459  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4460  {
4461  if (!array_key_exists($row["active_fi"], $times))
4462  {
4463  $times[$row["active_fi"]] = 0;
4464  }
4465  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4466  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4467  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4468  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4469  $times[$row["active_fi"]] += ($epoch_2 - $epoch_1);
4470  }
4471  return $times;
4472  }
4473 
4483  {
4484  global $ilDB;
4485 
4486  $query = sprintf("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",
4487  $ilDB->quote($this->getTestId() . ""),
4488  $ilDB->quote($active_id . "")
4489  );
4490  $result = $ilDB->query($query);
4491  $time = 0;
4492  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4493  {
4494  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4495  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4496  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4497  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4498  $time += ($epoch_2 - $epoch_1);
4499  }
4500  return $time;
4501  }
4502 
4512  {
4513  global $ilDB;
4514 
4515  $query = sprintf("SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
4516  $ilDB->quote($active_id . ""),
4517  $ilDB->quote($pass . "")
4518  );
4519  $result = $ilDB->query($query);
4520  $time = 0;
4521  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4522  {
4523  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4524  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4525  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4526  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4527  $time += ($epoch_2 - $epoch_1);
4528  }
4529  return $time;
4530  }
4531 
4541  function getVisitTimeOfParticipant($active_id)
4542  {
4543  return ilObjTest::_getVisitTimeOfParticipant($this->getTestId(), $active_id);
4544  }
4545 
4556  function _getVisitTimeOfParticipant($test_id, $active_id)
4557  {
4558  global $ilDB;
4559 
4560  $query = sprintf("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",
4561  $ilDB->quote($test_id . ""),
4562  $ilDB->quote($active_id . "")
4563  );
4564  $result = $ilDB->query($query);
4565  $firstvisit = 0;
4566  $lastvisit = 0;
4567  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4568  {
4569  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
4570  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4571  if ($firstvisit == 0 || $epoch_1 < $firstvisit) $firstvisit = $epoch_1;
4572  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
4573  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4574  if ($epoch_2 > $lastvisit) $lastvisit = $epoch_2;
4575  }
4576  return array("firstvisit" => $firstvisit, "lastvisit" => $lastvisit);
4577  }
4578 
4587  function &evalStatistical($active_id)
4588  {
4589  global $ilDB;
4590 // global $ilBench;
4591  $pass = ilObjTest::_getResultPass($active_id);
4592  $test_result =& $this->getTestResult($active_id, $pass);
4593  $q = sprintf("SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
4594  $ilDB->quote($active_id)
4595  );
4596  $result = $ilDB->query($q);
4597  $times = array();
4598  $first_visit = 0;
4599  $last_visit = 0;
4600  while ($row = $result->fetchRow(MDB2_FETCHMODE_OBJECT)) {
4601  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
4602  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4603  if (!$first_visit) {
4604  $first_visit = $epoch_1;
4605  }
4606  if ($epoch_1 < $first_visit) {
4607  $first_visit = $epoch_1;
4608  }
4609  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
4610  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
4611  if (!$last_visit) {
4612  $last_visit = $epoch_2;
4613  }
4614  if ($epoch_2 > $last_visit) {
4615  $last_visit = $epoch_2;
4616  }
4617  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
4618  }
4619  $max_time = 0;
4620  foreach ($times as $key => $value) {
4621  $max_time += $value;
4622  }
4623  if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"]))
4624  {
4625  $percentage = 0.0;
4626  }
4627  else
4628  {
4629  $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
4630  if ($percentage < 0) $percentage = 0.0;
4631  }
4632  $mark_obj = $this->mark_schema->getMatchingMark($percentage);
4633  $first_date = getdate($first_visit);
4634  $last_date = getdate($last_visit);
4635  $qworkedthrough = 0;
4636  foreach ($test_result as $key => $value)
4637  {
4638  if (preg_match("/\d+/", $key))
4639  {
4640  $qworkedthrough += $value["workedthrough"];
4641  }
4642  }
4643  if (!$qworkedthrough)
4644  {
4645  $atimeofwork = 0;
4646  }
4647  else
4648  {
4649  $atimeofwork = $max_time / $qworkedthrough;
4650  }
4651  $result_mark = "";
4652  $passed = "";
4653  if ($mark_obj)
4654  {
4655  $result_mark = $mark_obj->getShortName();
4656  if ($mark_obj->getPassed())
4657  {
4658  $passed = 1;
4659  }
4660  else
4661  {
4662  $passed = 0;
4663  }
4664  }
4665  $percent_worked_through = 0;
4666  if (count($this->questions))
4667  {
4668  $percent_worked_through = $qworkedthrough / count($this->questions);
4669  }
4670  $result_array = array(
4671  "qworkedthrough" => $qworkedthrough,
4672  "qmax" => count($this->questions),
4673  "pworkedthrough" => $percent_worked_through,
4674  "timeofwork" => $max_time,
4675  "atimeofwork" => $atimeofwork,
4676  "firstvisit" => $first_date,
4677  "lastvisit" => $last_date,
4678  "resultspoints" => $test_result["test"]["total_reached_points"],
4679  "maxpoints" => $test_result["test"]["total_max_points"],
4680  "resultsmarks" => $result_mark,
4681  "passed" => $passed,
4682  "distancemedian" => "0"
4683  );
4684  foreach ($test_result as $key => $value)
4685  {
4686  if (preg_match("/\d+/", $key))
4687  {
4688  $result_array[$key] = $value;
4689  }
4690  }
4691  return $result_array;
4692  }
4693 
4704  {
4705  $totalpoints_array = array();
4706  $all_users =& $this->evalTotalParticipantsArray();
4707  foreach ($all_users as $active_id => $user_name)
4708  {
4709  $test_result =& $this->getTestResult($active_id);
4710  $reached = $test_result["test"]["total_reached_points"];
4711  $total = $test_result["test"]["total_max_points"];
4712  $percentage = $total != 0 ? $reached/$total : 0;
4713  $mark = $this->mark_schema->getMatchingMark($percentage*100.0);
4714  if ($mark)
4715  {
4716  if ($mark->getPassed())
4717  {
4718  array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
4719  }
4720  }
4721  }
4722  return $totalpoints_array;
4723  }
4724 
4733  function &getParticipants()
4734  {
4735  global $ilDB;
4736  $q = sprintf("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",
4737  $ilDB->quote($this->getTestId())
4738  );
4739  $result = $ilDB->query($q);
4740  $persons_array = array();
4741  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4742  {
4743  $name = $this->lng->txt("unknown");
4744  $fullname = $this->lng->txt("unknown");
4745  $login = "";
4746  if (!$this->getAnonymity())
4747  {
4748  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4749  {
4750  $name = $this->lng->txt("deleted_user");
4751  $fullname = $this->lng->txt("deleted_user");
4752  $login = $this->lng->txt("unknown");
4753  }
4754  else
4755  {
4756  $login = $row["login"];
4757  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4758  {
4759  $name = $this->lng->txt("unknown");
4760  $fullname = $this->lng->txt("unknown");
4761  }
4762  else
4763  {
4764  $name = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4765  $fullname = trim($row["title"] . " " . $row["firstname"] . " " . $row["lastname"]);
4766  }
4767  }
4768  }
4769  $persons_array[$row["active_id"]] = array(
4770  "name" => $name,
4771  "fullname" => $fullname,
4772  "login" => $login
4773  );
4774  }
4775  return $persons_array;
4776  }
4777 
4786  function &evalTotalPersonsArray($name_sort_order = "asc")
4787  {
4788  global $ilDB;
4789  $q = sprintf("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),
4790  $ilDB->quote($this->getTestId())
4791  );
4792  $result = $ilDB->query($q);
4793  $persons_array = array();
4794  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4795  {
4796  if ($this->getAnonymity())
4797  {
4798  $persons_array[$row["active_id"]] = $this->lng->txt("unknown");
4799  }
4800  else
4801  {
4802  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4803  {
4804  $persons_array[$row["active_id"]] = $this->lng->txt("deleted_user");
4805  }
4806  else
4807  {
4808  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4809  {
4810  $persons_array[$row["active_id"]] = $row["lastname"];
4811  }
4812  else
4813  {
4814  $persons_array[$row["active_id"]] = trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]);
4815  }
4816  }
4817  }
4818  }
4819  return $persons_array;
4820  }
4821 
4830  function &evalTotalParticipantsArray($name_sort_order = "asc")
4831  {
4832  global $ilDB;
4833  $q = sprintf("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),
4834  $ilDB->quote($this->getTestId())
4835  );
4836  $result = $ilDB->query($q);
4837  $persons_array = array();
4838  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4839  {
4840  if ($this->getAnonymity())
4841  {
4842  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("unknown"));
4843  }
4844  else
4845  {
4846  if (strlen($row["firstname"].$row["lastname"].$row["title"]) == 0)
4847  {
4848  $persons_array[$row["active_id"]] = array("name" => $this->lng->txt("deleted_user"));
4849  }
4850  else
4851  {
4852  if ($row["user_fi"] == ANONYMOUS_USER_ID)
4853  {
4854  $persons_array[$row["active_id"]] = array("name" => $row["lastname"]);
4855  }
4856  else
4857  {
4858  $persons_array[$row["active_id"]] = array("name" => trim($row["lastname"] . ", " . $row["firstname"] . " " . $row["title"]), "login" => $row["login"]);
4859  }
4860  }
4861  }
4862  }
4863  return $persons_array;
4864  }
4865 
4875  {
4876  global $ilDB;
4877 
4878  $q = sprintf("SELECT COUNT(*) as total FROM tst_active WHERE test_fi = %s AND tries > 0",
4879  $ilDB->quote($this->getTestId())
4880  );
4881  $result = $ilDB->query($q);
4882  $row = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
4883  return $row->total;
4884  }
4885 
4894  function &getQuestionsOfTest($active_id)
4895  {
4896  global $ilDB;
4897  if ($this->isRandomTest())
4898  {
4899  $query = sprintf("SELECT tst_test_random_question.sequence, tst_test_random_question.question_fi, " .
4900  "tst_test_random_question.pass, qpl_questions.points " .
4901  "FROM tst_test_random_question, qpl_questions " .
4902  "WHERE tst_test_random_question.question_fi = qpl_questions.question_id " .
4903  "AND tst_test_random_question.active_fi = %s ORDER BY tst_test_random_question.sequence LIMIT 0, %s",
4904  $ilDB->quote($active_id . ""),
4905  $this->getQuestionCount()
4906  );
4907  }
4908  else
4909  {
4910  $query = sprintf("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4911  "qpl_questions.points " .
4912  "FROM tst_test_question, tst_active, qpl_questions " .
4913  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4914  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4915  $ilDB->quote($active_id . "")
4916  );
4917  }
4918  $result = $ilDB->query($query);
4919  $qtest = array();
4920  if ($result->numRows())
4921  {
4922  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4923  {
4924  array_push($qtest, $row);
4925  }
4926  }
4927  return $qtest;
4928  }
4929 
4938  function &getQuestionsOfPass($active_id, $pass)
4939  {
4940  global $ilDB;
4941  if ($this->isRandomTest())
4942  {
4943  $query = sprintf("SELECT tst_test_random_question.sequence, tst_test_random_question.question_fi, " .
4944  "qpl_questions.points " .
4945  "FROM tst_test_random_question, qpl_questions " .
4946  "WHERE tst_test_random_question.question_fi = qpl_questions.question_id " .
4947  "AND tst_test_random_question.active_fi = %s AND tst_test_random_question.pass = %s " .
4948  "ORDER BY tst_test_random_question.sequence LIMIT 0, %s",
4949  $ilDB->quote($active_id . ""),
4950  $ilDB->quote($pass . ""),
4951  $this->getQuestionCount()
4952  );
4953  }
4954  else
4955  {
4956  $query = sprintf("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
4957  "qpl_questions.points " .
4958  "FROM tst_test_question, tst_active, qpl_questions " .
4959  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
4960  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
4961  $ilDB->quote($active_id . "")
4962  );
4963  }
4964  $result = $ilDB->query($query);
4965  $qpass = array();
4966  if ($result->numRows())
4967  {
4968  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
4969  {
4970  array_push($qpass, $row);
4971  }
4972  }
4973  return $qpass;
4974  }
4975 
4976  private function getMembershipByType($a_usr_id,$a_type)
4977  {
4978  global $ilDB;
4979 
4980  $query = "SELECT DISTINCT obd.obj_id,obr.ref_id FROM rbac_ua AS ua ".
4981  "JOIN rbac_fa AS fa ON ua.rol_id = fa.rol_id ".
4982  "JOIN tree AS t1 ON t1.child = fa.parent ".
4983  "JOIN object_reference AS obr ON t1.parent = obr.ref_id ".
4984  "JOIN object_data AS obd ON obr.obj_id = obd.obj_id ".
4985  "WHERE obd.type = ".$ilDB->quote($a_type)." ".
4986  "AND fa.assign = 'y' ".
4987  "AND ua.usr_id = ".$ilDB->quote($a_usr_id)." ";
4988  $res = $ilDB->query($query);
4989 
4990  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
4991  {
4992  $ref_ids[] = $row->obj_id;
4993  }
4994 
4995  return $ref_ids ? $ref_ids : array();
4996  }
4997 
4999  {
5000  global $ilDB;
5001  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5002  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5003  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5004  $data = new ilTestEvaluationData($this);
5005  $query = sprintf("SELECT tst_test_result.*, qpl_questions.original_id, qpl_questions.title AS questiontitle, " .
5006  "qpl_questions.points AS maxpoints " .
5007  "FROM tst_test_result, qpl_questions, tst_active " .
5008  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5009  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5010  "AND tst_active.test_fi = %s " .
5011  "ORDER BY active_id, pass, TIMESTAMP",
5012  $ilDB->quote($this->getTestId() . "")
5013  );
5014  $result = $ilDB->query($query);
5015  $pass = NULL;
5016  $checked = array();
5017  $datasets = 0;
5018  while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
5019  {
5020  $data->getParticipant($row["active_fi"])->getPass($row["pass"])->addAnsweredQuestion($row["original_id"] ? $row["original_id"] : $row["question_fi"], $row["maxpoints"], $row["points"]);
5021  }
5022 
5023  foreach (array_keys($data->getParticipants()) as $active_id)
5024  {
5025  if ($this->isRandomTest())
5026  {
5027  for ($testpass = 0; $testpass <= $data->getParticipant($active_id)->getLastPass(); $testpass++)
5028  {
5029  $query = sprintf("SELECT tst_test_random_question.sequence, tst_test_random_question.question_fi, qpl_questions.original_id, " .
5030  "tst_test_random_question.pass, qpl_questions.points, qpl_questions.title " .
5031  "FROM tst_test_random_question, qpl_questions " .
5032  "WHERE tst_test_random_question.question_fi = qpl_questions.question_id " .
5033  "AND tst_test_random_question.pass = %s " .
5034  "AND tst_test_random_question.active_fi = %s ORDER BY tst_test_random_question.sequence LIMIT 0, %s",
5035  $ilDB->quote($testpass . ""),
5036  $ilDB->quote($active_id . ""),
5037  $this->getQuestionCount()
5038  );
5039  $result = $ilDB->query($query);
5040  if ($result->numRows())
5041  {
5042  while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
5043  {
5044  $tpass = array_key_exists("pass", $row) ? $row["pass"] : 0;
5045  $data->getParticipant($active_id)->addQuestion($row["original_id"] ? $row["original_id"] : $row["question_fi"], $row["question_fi"], $row["points"], $row["sequence"], $tpass);
5046  $data->addQuestionTitle($row["original_id"] ? $row["original_id"] : $row["question_fi"], $row["title"]);
5047  }
5048  }
5049  }
5050  }
5051  else
5052  {
5053  $query = sprintf("SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
5054  "qpl_questions.points, qpl_questions.title, qpl_questions.original_id " .
5055  "FROM tst_test_question, tst_active, qpl_questions " .
5056  "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
5057  "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi ORDER BY tst_test_question.sequence",
5058  $ilDB->quote($active_id . "")
5059  );
5060  $result = $ilDB->query($query);
5061  if ($result->numRows())
5062  {
5063  $questionsbysequence = array();
5064  while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
5065  {
5066  $questionsbysequence[$row["sequence"]] = $row;
5067  }
5068  $sequery = sprintf("SELECT * FROM tst_sequence WHERE active_fi = %s",
5069  $ilDB->quote($active_id)
5070  );
5071  $seqresult = $ilDB->query($sequery);
5072  while ($seqrow = $seqresult->fetchRow(DB_FETCHMODE_ASSOC))
5073  {
5074  $questionsequence = unserialize($seqrow["sequence"]);
5075  foreach ($questionsequence as $sidx => $seq)
5076  {
5077  $qsid = $questionsbysequence[$seq]["original_id"] ? $questionsbysequence[$seq]["original_id"] : $questionsbysequence[$seq]["question_fi"];
5078  $data->getParticipant($active_id)->addQuestion($qsid, $questionsbysequence[$seq]["question_fi"], $questionsbysequence[$seq]["points"], $sidx + 1, $seqrow["pass"]);
5079  $data->addQuestionTitle($qsid, $questionsbysequence[$seq]["title"]);
5080  }
5081  }
5082  }
5083  }
5084  }
5085 
5086  if ($this->ects_output)
5087  {
5088  $passed_array =& $this->getTotalPointsPassedArray();
5089  }
5090  foreach (array_keys($data->getParticipants()) as $active_id)
5091  {
5092  $percentage = $data->getParticipant($active_id)->getReachedPointsInPercent();
5093  $mark = $this->mark_schema->getMatchingMark($percentage);
5094  if (is_object($mark))
5095  {
5096  $data->getParticipant($active_id)->setMark($mark->getShortName());
5097  $data->getParticipant($active_id)->setMarkOfficial($mark->getOfficialName());
5098  $data->getParticipant($active_id)->setPassed($mark->getPassed());
5099  }
5100  if ($this->ects_output)
5101  {
5102  $ects_mark = $this->getECTSGrade($passed_array, $data->getParticipant($active_id)->getReached(), $data->getParticipant($active_id)->getMaxPoints());
5103  $data->getParticipant($active_id)->setECTSMark($ects_mark);
5104  }
5105  $visitingTime =& $this->getVisitTimeOfParticipant($active_id);
5106  $data->getParticipant($active_id)->setFirstVisit($visitingTime["firstvisit"]);
5107  $data->getParticipant($active_id)->setLastVisit($visitingTime["lastvisit"]);
5108  }
5109  return $data;
5110  }
5111 
5113  {
5114  global $ilDB;
5115  $random = ilObjTest::_lookupRandomTestFromActiveId($active_id);
5116  if ($random)
5117  {
5118  $query = sprintf("SELECT tst_test_random_question.pass, COUNT(tst_test_random_question.question_fi) AS qcount, " .
5119  "SUM(qpl_questions.points) AS qsum FROM tst_test_random_question, qpl_questions " .
5120  "WHERE tst_test_random_question.question_fi = qpl_questions.question_id AND " .
5121  "tst_test_random_question.active_fi = %s and pass = %s GROUP BY tst_test_random_question.active_fi, " .
5122  "tst_test_random_question.pass",
5123  $ilDB->quote($active_id),
5124  $ilDB->quote($pass)
5125  );
5126  }
5127  else
5128  {
5129  $query = sprintf("SELECT COUNT(tst_test_question.question_fi) AS qcount, " .
5130  "SUM(qpl_questions.points) AS qsum FROM tst_test_question, qpl_questions, tst_active " .
5131  "WHERE tst_test_question.question_fi = qpl_questions.question_id AND tst_test_question.test_fi = tst_active.test_fi AND " .
5132  "tst_active.active_id = %s GROUP BY tst_test_question.test_fi",
5133  $ilDB->quote($active_id)
5134  );
5135  }
5136  $result = $ilDB->query($query);
5137  if ($result->numRows())
5138  {
5139  $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
5140  return array("count" => $row["qcount"], "points" => $row["qsum"]);
5141  }
5142  else
5143  {
5144  return array("count" => 0, "points" => 0);
5145  }
5146  }
5147 
5148  function &getCompleteEvaluationData($withStatistics = TRUE, $filterby = "", $filtertext = "")
5149  {
5150  include_once "./Modules/Test/classes/class.ilTestEvaluationData.php";
5151  include_once "./Modules/Test/classes/class.ilTestEvaluationPassData.php";
5152  include_once "./Modules/Test/classes/class.ilTestEvaluationUserData.php";
5154  if ($withStatistics)
5155  {
5156  $data->calculateStatistics();
5157  }
5158  $data->setFilter($filterby, $filtertext);
5159  return $data;
5160  }
5161 
5171  {
5172  return $this->_evalResultsOverview($this->getTestId());
5173  }
5174 
5184  {
5185  global $ilDB;
5186 
5187  $query = sprintf("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5188  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title AS questiontitle, " .
5189  "qpl_questions.points AS maxpoints " .
5190  "FROM tst_test_result, qpl_questions, tst_active " .
5191  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5192  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5193  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5194  "AND tst_active.test_fi = %s " .
5195  "ORDER BY active_id, pass, TIMESTAMP",
5196  $ilDB->quote($test_id . "")
5197  );
5198  $result = $ilDB->query($query);
5199  $overview = array();
5200  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
5201  {
5202  if (!array_key_exists($row["active_fi"], $overview))
5203  {
5204  $overview[$row["active_fi"]] = array();
5205  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5206  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5207  $overview[$row["active_fi"]]["title"] = $row["title"];
5208  $overview[$row["active_fi"]]["login"] = $row["login"];
5209  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5210  $overview[$row["active_fi"]]["started"] = $row["started"];
5211  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5212  }
5213  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5214  {
5215  $overview[$row["active_fi"]][$row["pass"]] = array();
5216  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5217  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5218  }
5219  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5220  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5221  }
5222  return $overview;
5223  }
5224 
5234  function &evalResultsOverviewOfParticipant($active_id)
5235  {
5236  global $ilDB;
5237 
5238  $query = sprintf("SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
5239  "tst_test_result.*, qpl_questions.original_id, qpl_questions.title AS questiontitle, " .
5240  "qpl_questions.points AS maxpoints " .
5241  "FROM tst_test_result, qpl_questions, tst_active " .
5242  "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
5243  "WHERE tst_active.active_id = tst_test_result.active_fi " .
5244  "AND qpl_questions.question_id = tst_test_result.question_fi " .
5245  "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
5246  "ORDER BY active_id, pass, TIMESTAMP",
5247  $ilDB->quote($this->getTestId() . ""),
5248  $ilDB->quote($active_id . "")
5249  );
5250  $result = $ilDB->query($query);
5251  $overview = array();
5252  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
5253  {
5254  if (!array_key_exists($row["active_fi"], $overview))
5255  {
5256  $overview[$row["active_fi"]] = array();
5257  $overview[$row["active_fi"]]["firstname"] = $row["firstname"];
5258  $overview[$row["active_fi"]]["lastname"] = $row["lastname"];
5259  $overview[$row["active_fi"]]["title"] = $row["title"];
5260  $overview[$row["active_fi"]]["login"] = $row["login"];
5261  $overview[$row["active_fi"]]["usr_id"] = $row["usr_id"];
5262  $overview[$row["active_fi"]]["started"] = $row["started"];
5263  $overview[$row["active_fi"]]["finished"] = $row["finished"];
5264  }
5265  if (!array_key_exists($row["pass"], $overview[$row["active_fi"]]))
5266  {
5267  $overview[$row["active_fi"]][$row["pass"]] = array();
5268  $overview[$row["active_fi"]][$row["pass"]]["reached"] = 0;
5269  $overview[$row["active_fi"]][$row["pass"]]["maxpoints"] = $row["maxpoints"];
5270  }
5271  array_push($overview[$row["active_fi"]][$row["pass"]], $row);
5272  $overview[$row["active_fi"]][$row["pass"]]["reached"] += $row["points"];
5273  }
5274  return $overview;
5275  }
5276 
5290  function buildName($user_id, $firstname, $lastname, $title)
5291  {
5292  $name = "";
5293  if (strlen($firstname.$lastname.$title) == 0)
5294  {
5295  $name = $this->lng->txt("deleted_user");
5296  }
5297  else
5298  {
5299  if ($user_id == ANONYMOUS_USER_ID)
5300  {
5301  $name = $lastname;
5302  }
5303  else
5304  {
5305  $name = trim($lastname . ", " . $firstname . " " . $title);
5306  }
5307  if ($this->getAnonymity())
5308  {
5309  $name = $this->lng->txt("anonymous");
5310  }
5311  }
5312  return $name;
5313  }
5314 
5329  function _buildName($is_anonymous, $user_id, $firstname, $lastname, $title)
5330  {
5331  global $lng;
5332  $name = "";
5333  if (strlen($firstname.$lastname.$title) == 0)
5334  {
5335  $name = $lng->txt("deleted_user");
5336  }
5337  else
5338  {
5339  if ($user_id == ANONYMOUS_USER_ID)
5340  {
5341  $name = $lastname;
5342  }
5343  else
5344  {
5345  $name = trim($lastname . ", " . $firstname . " " . $title);
5346  }
5347  if ($is_anonymous)
5348  {
5349  $name = $lng->txt("anonymous");
5350  }
5351  }
5352  return $name;
5353  }
5354 
5364  {
5365  global $ilDB;
5366 
5367  $q = sprintf("SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi",
5368  $ilDB->quote($this->getTestId())
5369  );
5370  $result = $ilDB->query($q);
5371  $times = array();
5372  while ($row = $result->fetchRow(MDB2_FETCHMODE_OBJECT))
5373  {
5374  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
5375  $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5376  preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
5377  $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5378  $times[$row->active_fi] += ($epoch_2 - $epoch_1);
5379  }
5380  $max_time = 0;
5381  $counter = 0;
5382  foreach ($times as $key => $value)
5383  {
5384  $max_time += $value;
5385  $counter++;
5386  }
5387  if ($counter)
5388  {
5389  $average_time = round($max_time / $counter);
5390  }
5391  else
5392  {
5393  $average_time = 0;
5394  }
5395  return $average_time;
5396  }
5397 
5406  function &getAvailableQuestionpools($use_object_id = false, $equal_points = false, $could_be_offline = false, $show_path = FALSE, $with_questioncount = FALSE, $permission = "read")
5407  {
5408  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5409  return ilObjQuestionPool::_getAvailableQuestionpools($use_object_id, $equal_points, $could_be_offline, $show_path, $with_questioncount, $permission);
5410  }
5411 
5421  {
5422  $time_in_seconds = 0;
5423  foreach ($this->questions as $question_id)
5424  {
5425  $question =& ilObjTest::_instanciateQuestion($question_id);
5426  $est_time = $question->getEstimatedWorkingTime();
5427  $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
5428  }
5429  $hours = (int)($time_in_seconds / 3600) ;
5430  $time_in_seconds = $time_in_seconds - ($hours * 3600);
5431  $minutes = (int)($time_in_seconds / 60);
5432  $time_in_seconds = $time_in_seconds - ($minutes * 60);
5433  $result = array("h" => $hours, "m" => $minutes, "s" => $time_in_seconds);
5434  return $result;
5435  }
5436 
5449  function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "", $pass = NULL)
5450  {
5451  global $rbacsystem;
5452  global $ilDB;
5453  // get the questionpool id if a questionpool ref id was entered
5454  if ($questionpool != 0)
5455  {
5456  // retrieve object id
5457  if (!$use_obj_id)
5458  {
5459  $query = sprintf("SELECT obj_id FROM object_reference WHERE ref_id = %s",
5460  $ilDB->quote("$questionpool")
5461  );
5462  $result = $ilDB->query($query);
5463  $row = $result->fetchRow(DB_FETCHMODE_ARRAY);
5464  $questionpool = $row[0];
5465  }
5466  }
5467 
5468  // get all existing questions in the test
5469  $query = sprintf("SELECT qpl_questions.original_id FROM qpl_questions, tst_test_question WHERE qpl_questions.question_id = tst_test_question.question_fi AND tst_test_question.test_fi = %s",
5470  $ilDB->quote($this->getTestId() . "")
5471  );
5472  $result = $ilDB->query($query);
5473  $original_ids = array();
5474  while ($row = $result->fetchRow(DB_FETCHMODE_ARRAY))
5475  {
5476  if (strcmp($row[0], "") != 0)
5477  {
5478  array_push($original_ids, $row[0]);
5479  }
5480  }
5481  $original_clause = "";
5482  if (count($original_ids))
5483  {
5484  $original_clause = " AND ISNULL(qpl_questions.original_id) AND qpl_questions.question_id NOT IN ('" . join($original_ids, "','") . "')";
5485  }
5486 
5487  // get a list of questionpools which are not allowed for the test (only for random selection of questions in test questions editor)
5488  if (($questionpool == 0) && (!is_array($qpls)))
5489  {
5490  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5491  $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = TRUE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE));
5492  $available = "";
5493  $constraint_qpls = "";
5494  if (count($available_pools))
5495  {
5496  $available = " AND qpl_questions.obj_fi IN ('" . join($available_pools, "','") . "')";
5497  }
5498  else
5499  {
5500  return array();
5501  }
5502  }
5503 
5504  $result_array = array();
5505  if ($questionpool == 0)
5506  {
5507  if (is_array($qpls))
5508  {
5509  if (count($qpls) > 0)
5510  {
5511  $qplidx = array();
5512  foreach ($qpls as $idx => $arr)
5513  {
5514  array_push($qplidx, $arr["qpl"]);
5515  }
5516  $constraint_qpls = " AND qpl_questions.obj_fi IN ('" . join($qplidx, "','") . "')";
5517  }
5518  }
5519  $query = "SELECT COUNT(question_id) FROM qpl_questions, object_data WHERE ISNULL(qpl_questions.original_id) AND object_data.type = 'qpl' AND object_data.obj_id = qpl_questions.obj_fi$available$constraint_qpls AND qpl_questions.complete = '1'$original_clause";
5520  }
5521  else
5522  {
5523  $query = sprintf("SELECT COUNT(question_id) FROM qpl_questions WHERE ISNULL(qpl_questions.original_id) AND obj_fi = %s$original_clause",
5524  $ilDB->quote("$questionpool")
5525  );
5526  }
5527  $result = $ilDB->query($query);
5528  $row = $result->fetchRow(DB_FETCHMODE_ARRAY);
5529  if (($row[0]) <= $nr_of_questions)
5530  {
5531  // take all available questions
5532  if ($questionpool == 0)
5533  {
5534  $query = "SELECT question_id FROM qpl_questions, object_data WHERE ISNULL(qpl_questions.original_id) AND object_data.type = 'qpl' AND object_data.obj_id = qpl_questions.obj_fi$available$constraint_qpls AND qpl_questions.complete = '1'$original_clause";
5535  }
5536  else
5537  {
5538  $query = sprintf("SELECT question_id FROM qpl_questions WHERE ISNULL(qpl_questions.original_id) AND obj_fi = %s AND qpl_questions.complete = '1'$original_clause",
5539  $ilDB->quote("$questionpool")
5540  );
5541  }
5542  $result = $ilDB->query($query);
5543  while ($row = $result->fetchRow(DB_FETCHMODE_ARRAY))
5544  {
5545  if ((!in_array($row[0], $this->questions)) && (strcmp($row[0], "") != 0))
5546  {
5547  $result_array[$row[0]] = $row[0];
5548  }
5549  }
5550  }
5551  else
5552  {
5553  // select a random number out of the maximum number of questions
5554  mt_srand((double)microtime()*1000000);
5555  $random_number = mt_rand(0, $row[0] - 1);
5556  $securitycounter = 500;
5557  while ((count($result_array) < $nr_of_questions) && ($securitycounter > 0))
5558  {
5559  if ($questionpool == 0)
5560  {
5561  $query = "SELECT question_id FROM qpl_questions, object_data WHERE ISNULL(qpl_questions.original_id) AND object_data.type = 'qpl' AND object_data.obj_id = qpl_questions.obj_fi$available$constraint_qpls AND qpl_questions.complete = '1'$original_clause LIMIT $random_number, 1";
5562  }
5563  else
5564  {
5565  $query = sprintf("SELECT question_id FROM qpl_questions WHERE ISNULL(qpl_questions.original_id) AND obj_fi = %s AND qpl_questions.complete = '1'$original_clause LIMIT $random_number, 1",
5566  $ilDB->quote("$questionpool")
5567  );
5568  }
5569  $result = $ilDB->query($query);
5570  $result_row = $result->fetchRow(DB_FETCHMODE_ARRAY);
5571  if ((!in_array($result_row[0], $this->questions)) && (strcmp($result_row[0], "") != 0))
5572  {
5573  $result_array[$result_row[0]] = $result_row[0];
5574  }
5575  $random_number = mt_rand(0, $row[0] - 1);
5576  $securitycounter--;
5577  }
5578  }
5579  return $result_array;
5580  }
5581 
5590  function getImagePath()
5591  {
5592  return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
5593  }
5594 
5603  function getImagePathWeb()
5604  {
5605  include_once "./Services/Utilities/classes/class.ilUtil.php";
5606  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
5608  }
5609 
5620  function &createQuestionGUI($question_type, $question_id = -1)
5621  {
5622  if ((!$question_type) and ($question_id > 0))
5623  {
5624  $question_type = $this->getQuestionType($question_id);
5625  }
5626  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5627  assQuestion::_includeClass($question_type, 1);
5628  $question_type_gui = $question_type . "GUI";
5629  $question = new $question_type_gui();
5630  if ($question_id > 0)
5631  {
5632  $question->object->loadFromDb($question_id);
5633  }
5634  return $question;
5635  }
5636 
5646  function &_instanciateQuestion($question_id)
5647  {
5648  if (strcmp($question_id, "") != 0)
5649  {
5650  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5651  return assQuestion::_instanciateQuestion($question_id);
5652  }
5653  }
5654 
5665  function moveQuestions($move_questions, $target_index, $insert_mode)
5666  {
5667  $this->questions = array_values($this->questions);
5668  $array_pos = array_search($target_index, $this->questions);
5669  if ($insert_mode == 0)
5670  {
5671  $part1 = array_slice($this->questions, 0, $array_pos);
5672  $part2 = array_slice($this->questions, $array_pos);
5673  }
5674  else if ($insert_mode == 1)
5675  {
5676  $part1 = array_slice($this->questions, 0, $array_pos + 1);
5677  $part2 = array_slice($this->questions, $array_pos + 1);
5678  }
5679  foreach ($move_questions as $question_id)
5680  {
5681  if (!(array_search($question_id, $part1) === FALSE))
5682  {
5683  unset($part1[array_search($question_id, $part1)]);
5684  }
5685  if (!(array_search($question_id, $part2) === FALSE))
5686  {
5687  unset($part2[array_search($question_id, $part2)]);
5688  }
5689  }
5690  $part1 = array_values($part1);
5691  $part2 = array_values($part2);
5692  $new_array = array_values(array_merge($part1, $move_questions, $part2));
5693  $this->questions = array();
5694  $counter = 1;
5695  foreach ($new_array as $question_id)
5696  {
5697  $this->questions[$counter] = $question_id;
5698  $counter++;
5699  }
5700  $this->saveQuestionsToDb();
5701  }
5702 
5703 
5714  {
5715  if ($this->getStartingTime())
5716  {
5717  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getStartingTime(), $matches))
5718  {
5719  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5720  $now = mktime();
5721  if ($now < $epoch_time)
5722  {
5723  // starting time not reached
5724  return false;
5725  }
5726  }
5727  }
5728  return true;
5729  }
5730 
5741  {
5742  if ($this->getEndingTime())
5743  {
5744  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndingTime(), $matches))
5745  {
5746  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
5747  $now = mktime();
5748  if ($now > $epoch_time)
5749  {
5750  // ending time reached
5751  return true;
5752  }
5753  }
5754  }
5755  return false;
5756  }
5757 
5765  function getQuestionsTable($sort, $sortorder, $textfilter, $startrow = 0, $completeonly = 0, $filter_question_type = "", $filter_questionpool = "")
5766  {
5767  global $ilUser;
5768  global $ilDB;
5769 
5770  $where = "";
5771  foreach ($textfilter as $sel_filter_type => $filter_text)
5772  {
5773  if (strlen($filter_text) > 0)
5774  {
5775  switch($sel_filter_type)
5776  {
5777  case "title":
5778  $where .= " AND qpl_questions.title LIKE " . $ilDB->quote("%" . $filter_text . "%");
5779  break;
5780  case "comment":
5781  $where .= " AND qpl_questions.comment LIKE " . $ilDB->quote("%" . $filter_text . "%");
5782  break;
5783  case "author":
5784  $where .= " AND qpl_questions.author LIKE " . $ilDB->quote("%" . $filter_text . "%");
5785  break;
5786  case "qpl":
5787  $where .= " AND object_data.title LIKE " . $ilDB->quote("%" . $filter_text . "%");
5788  break;
5789  }
5790  }
5791  }
5792 
5793  if ($filter_question_type && (strcmp($filter_question_type, "all") != 0))
5794  {
5795  $where .= " AND qpl_question_type.type_tag = " . $ilDB->quote($filter_question_type);
5796  }
5797 
5798  if ($filter_questionpool && (strcmp($filter_questionpool, "all") != 0))
5799  {
5800  $where .= " AND qpl_questions.obj_fi = $filter_questionpool";
5801  }
5802 
5803  // build sort order for sql query
5804  $order = "";
5805  $images = array();
5806  include_once "./Services/Utilities/classes/class.ilUtil.php";
5807  switch($sort)
5808  {
5809  case "title":
5810  $order = " ORDER BY qpl_questions.title $sortorder";
5811  $images["title"] = " <img src=\"" . ilUtil::getImagePath(strtolower($sortorder) . "_order.gif") . "\" alt=\"" . $this->lng->txt(strtolower($sortorder) . "ending_order")."\" />";
5812  break;
5813  case "comment":
5814  $order = " ORDER BY comment $sortorder";
5815  $images["comment"] = " <img src=\"" . ilUtil::getImagePath(strtolower($sortorder) . "_order.gif") . "\" alt=\"" . $this->lng->txt(strtolower($sortorder) . "ending_order")."\" />";
5816  break;
5817  case "type":
5818  $order = " ORDER BY question_type_id $sortorder";
5819  $images["type"] = " <img src=\"" . ilUtil::getImagePath(strtolower($sortorder) . "_order.gif") . "\" alt=\"" . $this->lng->txt(strtolower($sortorder) . "ending_order")."\" />";
5820  break;
5821  case "author":
5822  $order = " ORDER BY author $sortorder";
5823  $images["author"] = " <img src=\"" . ilUtil::getImagePath(strtolower($sortorder) . "_order.gif") . "\" alt=\"" . $this->lng->txt(strtolower($sortorder) . "ending_order")."\" />";
5824  break;
5825  case "created":
5826  $order = " ORDER BY created $sortorder";
5827  $images["created"] = " <img src=\"" . ilUtil::getImagePath(strtolower($sortorder) . "_order.gif") . "\" alt=\"" . $this->lng->txt(strtolower($sortorder) . "ending_order")."\" />";
5828  break;
5829  case "updated":
5830  $order = " ORDER BY timestamp14 $sortorder";
5831  $images["updated"] = " <img src=\"" . ilUtil::getImagePath(strtolower($sortorder) . "_order.gif") . "\" alt=\"" . $this->lng->txt(strtolower($sortorder) . "ending_order")."\" />";
5832  break;
5833  case "qpl":
5834  $order = " ORDER BY UPPER(object_data.title) $sortorder";
5835  $images["qpl"] = " <img src=\"" . ilUtil::getImagePath(strtolower($sortorder) . "_order.gif") . "\" alt=\"" . $this->lng->txt(strtolower($sortorder) . "ending_order")."\" />";
5836  break;
5837  }
5838  $maxentries = $ilUser->prefs["hits_per_page"];
5839  if ($maxentries < 1)
5840  {
5841  $maxentries = 9999;
5842  }
5843  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
5844  $available_pools = array_keys(ilObjQuestionPool::_getAvailableQuestionpools($use_object_id = TRUE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE));
5845  $available = "";
5846  if (count($available_pools))
5847  {
5848  $available = " AND qpl_questions.obj_fi IN ('" . join($available_pools, "','") . "')";
5849  }
5850  else
5851  {
5852  return array();
5853  }
5854  if ($completeonly)
5855  {
5856  $available .= " AND qpl_questions.complete = " . $ilDB->quote("1");
5857  }
5858 
5859  // get all questions in the test
5860  $query = sprintf("SELECT qpl_questions.original_id, qpl_questions.TIMESTAMP + 0 AS timestamp14 FROM qpl_questions, tst_test_question, object_data WHERE qpl_questions.question_id = tst_test_question.question_fi AND object_data.obj_id = qpl_questions.obj_fi AND tst_test_question.test_fi = %s",
5861  $ilDB->quote($this->getTestId() . "")
5862  );
5863  $result = $ilDB->query($query);
5864  $original_ids = array();
5865  while ($row = $result->fetchRow(DB_FETCHMODE_ARRAY))
5866  {
5867  if (strcmp($row[0], "") != 0)
5868  {
5869  array_push($original_ids, $row[0]);
5870  }
5871  }
5872  $original_clause = " ISNULL(qpl_questions.original_id)";
5873  if (count($original_ids))
5874  {
5875  $original_clause = " ISNULL(qpl_questions.original_id) AND qpl_questions.question_id NOT IN ('" . join($original_ids, "','") . "')";
5876  }
5877 
5878  $query = "SELECT qpl_questions.question_id, qpl_questions.TIMESTAMP + 0 AS timestamp14 FROM qpl_questions, qpl_question_type, object_data WHERE $original_clause$available AND object_data.obj_id = qpl_questions.obj_fi AND qpl_questions.question_type_fi = qpl_question_type.question_type_id $where$order$limit";
5879  $query_result = $ilDB->query($query);
5880  $max = $query_result->numRows();
5881  if ($startrow > $max -1)
5882  {
5883  $startrow = $max - ($max % $maxentries);
5884  }
5885  else if ($startrow < 0)
5886  {
5887  $startrow = 0;
5888  }
5889  $limit = " LIMIT $startrow, $maxentries";
5890  $query = "SELECT qpl_questions.*, qpl_questions.TIMESTAMP + 0 AS timestamp14, qpl_question_type.type_tag, qpl_question_type.plugin FROM qpl_questions, qpl_question_type, object_data WHERE $original_clause $available AND object_data.obj_id = qpl_questions.obj_fi AND qpl_questions.question_type_fi = qpl_question_type.question_type_id $where$order$limit";
5891  $query_result = $ilDB->query($query);
5892  $rows = array();
5893  if ($query_result->numRows())
5894  {
5895  while ($row = $query_result->fetchRow(MDB2_FETCHMODE_ASSOC))
5896  {
5897  if ($row["plugin"])
5898  {
5899  if ($this->isPluginActive($row["type_tag"]))
5900  {
5901  array_push($rows, $row);
5902  }
5903  }
5904  else
5905  {
5906  array_push($rows, $row);
5907  }
5908  }
5909  }
5910  $nextrow = $startrow + $maxentries;
5911  if ($nextrow > $max - 1)
5912  {
5913  $nextrow = $startrow;
5914  }
5915  $prevrow = $startrow - $maxentries;
5916  if ($prevrow < 0)
5917  {
5918  $prevrow = 0;
5919  }
5920  return array(
5921  "rows" => $rows,
5922  "images" => $images,
5923  "startrow" => $startrow,
5924  "nextrow" => $nextrow,
5925  "prevrow" => $prevrow,
5926  "step" => $maxentries,
5927  "rowcount" => $max
5928  );
5929  }
5930 
5939  function fromXML(&$assessment)
5940  {
5941  unset($_SESSION["import_mob_xhtml"]);
5942 
5943  $this->setDescription($assessment->getComment());
5944  $this->setTitle($assessment->getTitle());
5945 
5946  foreach ($assessment->objectives as $objectives)
5947  {
5948  foreach ($objectives->materials as $material)
5949  {
5950  $this->setIntroduction($this->QTIMaterialToString($material));
5951  }
5952  }
5953  if ($assessment->getPresentationMaterial())
5954  {
5955  $this->setFinalStatement($this->QTIMaterialToString($assessment->getPresentationMaterial()->getMaterial(0)));
5956  }
5957 
5958  foreach ($assessment->assessmentcontrol as $assessmentcontrol)
5959  {
5960  switch ($assessmentcontrol->getSolutionswitch())
5961  {
5962  case "Yes":
5963  $this->setInstantFeedbackSolution(1);
5964  break;
5965  default:
5966  $this->setInstantFeedbackSolution(0);
5967  break;
5968  }
5969  }
5970 
5971  foreach ($assessment->qtimetadata as $metadata)
5972  {
5973  switch ($metadata["label"])
5974  {
5975  case "test_type":
5976  // for old tests with a test type
5977  $type = $metadata["entry"];
5978  switch ($type)
5979  {
5980  case 1:
5981  // assessment
5982  $this->setAnonymity(1);
5983  break;
5984  case 2:
5985  // self assessment
5986  break;
5987  case 4:
5988  // online exam
5989  $this->setFixedParticipants(1);
5990  $this->setListOfQuestionsSettings(7);
5991  $this->setShowSolutionPrintview(1);
5992  break;
5993  case 5:
5994  // varying random test
5995  break;
5996  }
5997  break;
5998  case "sequence_settings":
5999  $this->setSequenceSettings($metadata["entry"]);
6000  break;
6001  case "author":
6002  $this->setAuthor($metadata["entry"]);
6003  break;
6004  case "nr_of_tries":
6005  $this->setNrOfTries($metadata["entry"]);
6006  break;
6007  case "kiosk":
6008  $this->setKiosk($metadata["entry"]);
6009  break;
6010  case "showfinalstatement":
6011  $this->setShowFinalStatement($metadata["entry"]);
6012  break;
6013  case "showinfo":
6014  $this->setShowInfo($metadata["entry"]);
6015  break;
6016  case "forcejs":
6017  $this->setForceJS($metadata["entry"]);
6018  break;
6019  case "customstyle":
6020  $this->setCustomStyle($metadata["entry"]);
6021  break;
6022  case "hide_previous_results":
6023  if ($metadata["entry"] == 0)
6024  {
6025  $this->setUsePreviousAnswers(1);
6026  }
6027  else
6028  {
6029  $this->setUsePreviousAnswers(0);
6030  }
6031  break;
6032  case "use_previous_answers":
6033  $this->setUsePreviousAnswers($metadata["entry"]);
6034  break;
6035  case "answer_feedback":
6036  $this->setAnswerFeedback($metadata["entry"]);
6037  break;
6038  case "hide_title_points":
6039  $this->setTitleOutput($metadata["entry"]);
6040  break;
6041  case "title_output":
6042  $this->setTitleOutput($metadata["entry"]);
6043  break;
6044  case "random_test":
6045  $this->setRandomTest($metadata["entry"]);
6046  break;
6047  case "random_question_count":
6048  $this->setRandomQuestionCount($metadata["entry"]);
6049  break;
6050  case "results_presentation":
6051  $this->setResultsPresentation($metadata["entry"]);
6052  break;
6053  case "reset_processing_time":
6054  $this->setResetProcessingTime($metadata["entry"]);
6055  break;
6056  case "show_solution_details":
6057  $this->setShowSolutionDetails($metadata["entry"]);
6058  break;
6059  case "show_solution_printview":
6060  $this->setShowSolutionPrintview($metadata["entry"]);
6061  break;
6062  case "show_solution_feedback":
6063  $this->setShowSolutionFeedback($metadata["entry"]);
6064  break;
6065  case "instant_verification":
6066  $this->setInstantFeedbackSolution($metadata["entry"]);
6067  break;
6068  case "answer_feedback_points":
6069  $this->setAnswerFeedbackPoints($metadata["entry"]);
6070  break;
6071  case "anonymity":
6072  $this->setAnonymity($metadata["entry"]);
6073  break;
6074  case "show_cancel":
6075  $this->setShowCancel($metadata["entry"]);
6076  break;
6077  case "show_marker":
6078  $this->setShowMarker($metadata["entry"]);
6079  break;
6080  case "fixed_participants":
6081  $this->setFixedParticipants($metadata["entry"]);
6082  break;
6083  case "score_reporting":
6084  $this->setScoreReporting($metadata["entry"]);
6085  break;
6086  case "shuffle_questions":
6087  $this->setShuffleQuestions($metadata["entry"]);
6088  break;
6089  case "count_system":
6090  $this->setCountSystem($metadata["entry"]);
6091  break;
6092  case "mc_scoring":
6093  $this->setMCScoring($metadata["entry"]);
6094  break;
6095  case "score_cutting":
6096  $this->setScoreCutting($metadata["entry"]);
6097  break;
6098  case "password":
6099  $this->setPassword($metadata["entry"]);
6100  break;
6101  case "allowedUsers":
6102  $this->setAllowedUsers($metadata["entry"]);
6103  break;
6104  case "allowedUsersTimeGap":
6105  $this->setAllowedUsersTimeGap($metadata["entry"]);
6106  break;
6107  case "pass_scoring":
6108  $this->setPassScoring($metadata["entry"]);
6109  break;
6110  case "show_summary":
6111  $this->setListOfQuestionsSettings($metadata["entry"]);
6112  break;
6113  case "reporting_date":
6114  $iso8601period = $metadata["entry"];
6115  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6116  {
6117  $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6118  }
6119  break;
6120  case "processing_time":
6121  $this->setProcessingTime($metadata['entry']);
6122  break;
6123  case "starting_time":
6124  $iso8601period = $metadata["entry"];
6125  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6126  {
6127  $this->setStartingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6128  }
6129  break;
6130  case "ending_time":
6131  $iso8601period = $metadata["entry"];
6132  if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
6133  {
6134  $this->setEndingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
6135  }
6136  break;
6137  }
6138  if (preg_match("/mark_step_\d+/", $metadata["label"]))
6139  {
6140  $xmlmark = $metadata["entry"];
6141  preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
6142  $mark_short = $matches[1];
6143  preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
6144  $mark_official = $matches[1];
6145  preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
6146  $mark_percentage = $matches[1];
6147  preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
6148  $mark_passed = $matches[1];
6149  $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
6150  }
6151  }
6152  // handle the import of media objects in XHTML code
6153  if (is_array($_SESSION["import_mob_xhtml"]))
6154  {
6155  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6156  include_once "./Services/RTE/classes/class.ilRTE.php";
6157  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
6158  foreach ($_SESSION["import_mob_xhtml"] as $mob)
6159  {
6160  $importfile = $this->getImportDirectory() . "/" . $_SESSION["tst_import_subdir"] . "/" . $mob["uri"];
6161  if (file_exists($importfile))
6162  {
6163  $media_object =& ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, FALSE);
6164  ilObjMediaObject::_saveUsage($media_object->getId(), "tst:html", $this->getId());
6165  $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction()), 1));
6166  $this->setFinalStatement(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getFinalStatement()), 1));
6167  }
6168  else
6169  {
6170  global $ilLog;
6171  $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!");
6172  }
6173  }
6174  $this->saveToDb();
6175  }
6176  }
6177 
6186  function toXML()
6187  {
6188  include_once("./classes/class.ilXmlWriter.php");
6189  $a_xml_writer = new ilXmlWriter;
6190  // set xml header
6191  $a_xml_writer->xmlHeader();
6192  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
6193  $a_xml_writer->xmlStartTag("questestinterop");
6194 
6195  $attrs = array(
6196  "ident" => "il_".IL_INST_ID."_tst_".$this->getTestId(),
6197  "title" => $this->getTitle()
6198  );
6199  $a_xml_writer->xmlStartTag("assessment", $attrs);
6200  // add qti comment
6201  $a_xml_writer->xmlElement("qticomment", NULL, $this->getDescription());
6202 
6203  // add qti duration
6204  if ($this->enable_processing_time)
6205  {
6206  preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
6207  $a_xml_writer->xmlElement("duration", NULL, sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
6208  }
6209 
6210 - // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
6211  $a_xml_writer->xmlStartTag("qtimetadata");
6212  $a_xml_writer->xmlStartTag("qtimetadatafield");
6213  $a_xml_writer->xmlElement("fieldlabel", NULL, "ILIAS_VERSION");
6214  $a_xml_writer->xmlElement("fieldentry", NULL, $this->ilias->getSetting("ilias_version"));
6215  $a_xml_writer->xmlEndTag("qtimetadatafield");
6216 
6217  // anonymity
6218  $a_xml_writer->xmlStartTag("qtimetadatafield");
6219  $a_xml_writer->xmlElement("fieldlabel", NULL, "anonymity");
6220  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnonymity()));
6221  $a_xml_writer->xmlEndTag("qtimetadatafield");
6222 
6223  // random test
6224  $a_xml_writer->xmlStartTag("qtimetadatafield");
6225  $a_xml_writer->xmlElement("fieldlabel", NULL, "random_test");
6226  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->isRandomTest()));
6227  $a_xml_writer->xmlEndTag("qtimetadatafield");
6228 
6229  // sequence settings
6230  $a_xml_writer->xmlStartTag("qtimetadatafield");
6231  $a_xml_writer->xmlElement("fieldlabel", NULL, "sequence_settings");
6232  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getSequenceSettings());
6233  $a_xml_writer->xmlEndTag("qtimetadatafield");
6234 
6235  // author
6236  $a_xml_writer->xmlStartTag("qtimetadatafield");
6237  $a_xml_writer->xmlElement("fieldlabel", NULL, "author");
6238  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAuthor());
6239  $a_xml_writer->xmlEndTag("qtimetadatafield");
6240 
6241  // reset processing time
6242  $a_xml_writer->xmlStartTag("qtimetadatafield");
6243  $a_xml_writer->xmlElement("fieldlabel", NULL, "reset_processing_time");
6244  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getResetProcessingTime());
6245  $a_xml_writer->xmlEndTag("qtimetadatafield");
6246 
6247  // count system
6248  $a_xml_writer->xmlStartTag("qtimetadatafield");
6249  $a_xml_writer->xmlElement("fieldlabel", NULL, "count_system");
6250  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCountSystem());
6251  $a_xml_writer->xmlEndTag("qtimetadatafield");
6252 
6253  // multiple choice scoring
6254  $a_xml_writer->xmlStartTag("qtimetadatafield");
6255  $a_xml_writer->xmlElement("fieldlabel", NULL, "mc_scoring");
6256  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getMCScoring());
6257  $a_xml_writer->xmlEndTag("qtimetadatafield");
6258 
6259  // multiple choice scoring
6260  $a_xml_writer->xmlStartTag("qtimetadatafield");
6261  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_cutting");
6262  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getScoreCutting());
6263  $a_xml_writer->xmlEndTag("qtimetadatafield");
6264 
6265  // multiple choice scoring
6266  $a_xml_writer->xmlStartTag("qtimetadatafield");
6267  $a_xml_writer->xmlElement("fieldlabel", NULL, "password");
6268  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassword());
6269  $a_xml_writer->xmlEndTag("qtimetadatafield");
6270 
6271  // allowed users
6272  $a_xml_writer->xmlStartTag("qtimetadatafield");
6273  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsers");
6274  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsers());
6275  $a_xml_writer->xmlEndTag("qtimetadatafield");
6276 
6277  // allowed users time gap
6278  $a_xml_writer->xmlStartTag("qtimetadatafield");
6279  $a_xml_writer->xmlElement("fieldlabel", NULL, "allowedUsersTimeGap");
6280  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAllowedUsersTimeGap());
6281  $a_xml_writer->xmlEndTag("qtimetadatafield");
6282 
6283  // pass scoring
6284  $a_xml_writer->xmlStartTag("qtimetadatafield");
6285  $a_xml_writer->xmlElement("fieldlabel", NULL, "pass_scoring");
6286  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getPassScoring());
6287  $a_xml_writer->xmlEndTag("qtimetadatafield");
6288 
6289  // score reporting date
6290  if ($this->getReportingDate())
6291  {
6292  $a_xml_writer->xmlStartTag("qtimetadatafield");
6293  $a_xml_writer->xmlElement("fieldlabel", NULL, "reporting_date");
6294  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
6295  $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]));
6296  $a_xml_writer->xmlEndTag("qtimetadatafield");
6297  }
6298  // number of tries
6299  $a_xml_writer->xmlStartTag("qtimetadatafield");
6300  $a_xml_writer->xmlElement("fieldlabel", NULL, "nr_of_tries");
6301  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getNrOfTries()));
6302  $a_xml_writer->xmlEndTag("qtimetadatafield");
6303 
6304  // kiosk
6305  $a_xml_writer->xmlStartTag("qtimetadatafield");
6306  $a_xml_writer->xmlElement("fieldlabel", NULL, "kiosk");
6307  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getKiosk()));
6308  $a_xml_writer->xmlEndTag("qtimetadatafield");
6309 
6310  // use previous answers
6311  $a_xml_writer->xmlStartTag("qtimetadatafield");
6312  $a_xml_writer->xmlElement("fieldlabel", NULL, "use_previous_answers");
6313  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getUsePreviousAnswers());
6314  $a_xml_writer->xmlEndTag("qtimetadatafield");
6315 
6316  // hide title points
6317  $a_xml_writer->xmlStartTag("qtimetadatafield");
6318  $a_xml_writer->xmlElement("fieldlabel", NULL, "title_output");
6319  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getTitleOutput()));
6320  $a_xml_writer->xmlEndTag("qtimetadatafield");
6321 
6322  // random question count
6323  $a_xml_writer->xmlStartTag("qtimetadatafield");
6324  $a_xml_writer->xmlElement("fieldlabel", NULL, "random_question_count");
6325  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getRandomQuestionCount()));
6326  $a_xml_writer->xmlEndTag("qtimetadatafield");
6327 
6328  // results presentation
6329  $a_xml_writer->xmlStartTag("qtimetadatafield");
6330  $a_xml_writer->xmlElement("fieldlabel", NULL, "results_presentation");
6331  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getResultsPresentation()));
6332  $a_xml_writer->xmlEndTag("qtimetadatafield");
6333 
6334  // solution details
6335  $a_xml_writer->xmlStartTag("qtimetadatafield");
6336  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_summary");
6337  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getListOfQuestionsSettings()));
6338  $a_xml_writer->xmlEndTag("qtimetadatafield");
6339 
6340  // solution details
6341  $a_xml_writer->xmlStartTag("qtimetadatafield");
6342  $a_xml_writer->xmlElement("fieldlabel", NULL, "score_reporting");
6343  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getScoreReporting()));
6344  $a_xml_writer->xmlEndTag("qtimetadatafield");
6345 
6346  // solution details
6347  $a_xml_writer->xmlStartTag("qtimetadatafield");
6348  $a_xml_writer->xmlElement("fieldlabel", NULL, "instant_verification");
6349  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getInstantFeedbackSolution()));
6350  $a_xml_writer->xmlEndTag("qtimetadatafield");
6351 
6352  // answer specific feedback
6353  $a_xml_writer->xmlStartTag("qtimetadatafield");
6354  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback");
6355  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedback()));
6356  $a_xml_writer->xmlEndTag("qtimetadatafield");
6357 
6358  // answer specific feedback of reached points
6359  $a_xml_writer->xmlStartTag("qtimetadatafield");
6360  $a_xml_writer->xmlElement("fieldlabel", NULL, "answer_feedback_points");
6361  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getAnswerFeedbackPoints()));
6362  $a_xml_writer->xmlEndTag("qtimetadatafield");
6363 
6364  // show cancel
6365  $a_xml_writer->xmlStartTag("qtimetadatafield");
6366  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_cancel");
6367  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowCancel()));
6368  $a_xml_writer->xmlEndTag("qtimetadatafield");
6369 
6370  // show marker
6371  $a_xml_writer->xmlStartTag("qtimetadatafield");
6372  $a_xml_writer->xmlElement("fieldlabel", NULL, "show_marker");
6373  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShowMarker()));
6374  $a_xml_writer->xmlEndTag("qtimetadatafield");
6375 
6376  // fixed participants
6377  $a_xml_writer->xmlStartTag("qtimetadatafield");
6378  $a_xml_writer->xmlElement("fieldlabel", NULL, "fixed_participants");
6379  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getFixedParticipants()));
6380  $a_xml_writer->xmlEndTag("qtimetadatafield");
6381 
6382  // show final statement
6383  $a_xml_writer->xmlStartTag("qtimetadatafield");
6384  $a_xml_writer->xmlElement("fieldlabel", NULL, "showfinalstatement");
6385  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowFinalStatement()) ? "1" : "0")));
6386  $a_xml_writer->xmlEndTag("qtimetadatafield");
6387 
6388  // show introduction only
6389  $a_xml_writer->xmlStartTag("qtimetadatafield");
6390  $a_xml_writer->xmlElement("fieldlabel", NULL, "showinfo");
6391  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getShowInfo()) ? "1" : "0")));
6392  $a_xml_writer->xmlEndTag("qtimetadatafield");
6393 
6394  // force JavaScript
6395  $a_xml_writer->xmlStartTag("qtimetadatafield");
6396  $a_xml_writer->xmlElement("fieldlabel", NULL, "forcejs");
6397  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", (($this->getForceJS()) ? "1" : "0")));
6398  $a_xml_writer->xmlEndTag("qtimetadatafield");
6399 
6400  // custom style
6401  $a_xml_writer->xmlStartTag("qtimetadatafield");
6402  $a_xml_writer->xmlElement("fieldlabel", NULL, "customstyle");
6403  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getCustomStyle());
6404  $a_xml_writer->xmlEndTag("qtimetadatafield");
6405 
6406  // shuffle questions
6407  $a_xml_writer->xmlStartTag("qtimetadatafield");
6408  $a_xml_writer->xmlElement("fieldlabel", NULL, "shuffle_questions");
6409  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("%d", $this->getShuffleQuestions()));
6410  $a_xml_writer->xmlEndTag("qtimetadatafield");
6411 
6412  // processing time
6413  $a_xml_writer->xmlStartTag("qtimetadatafield");
6414  $a_xml_writer->xmlElement("fieldlabel", NULL, "processing_time");
6415  $a_xml_writer->xmlElement("fieldentry", NULL, $this->getProcessingTime());
6416  $a_xml_writer->xmlEndTag("qtimetadatafield");
6417 
6418  // starting time
6419  if ($this->getStartingTime())
6420  {
6421  $a_xml_writer->xmlStartTag("qtimetadatafield");
6422  $a_xml_writer->xmlElement("fieldlabel", NULL, "starting_time");
6423  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->starting_time, $matches);
6424  $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]));
6425  $a_xml_writer->xmlEndTag("qtimetadatafield");
6426  }
6427  // ending time
6428  if ($this->getEndingTime())
6429  {
6430  $a_xml_writer->xmlStartTag("qtimetadatafield");
6431  $a_xml_writer->xmlElement("fieldlabel", NULL, "ending_time");
6432  preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->ending_time, $matches);
6433  $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]));
6434  $a_xml_writer->xmlEndTag("qtimetadatafield");
6435  }
6436  foreach ($this->mark_schema->mark_steps as $index => $mark)
6437  {
6438  // mark steps
6439  $a_xml_writer->xmlStartTag("qtimetadatafield");
6440  $a_xml_writer->xmlElement("fieldlabel", NULL, "mark_step_$index");
6441  $a_xml_writer->xmlElement("fieldentry", NULL, sprintf("<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>", $mark->getShortName(), $mark->getOfficialName(), $mark->getMinimumLevel(), $mark->getPassed()));
6442  $a_xml_writer->xmlEndTag("qtimetadatafield");
6443  }
6444  $a_xml_writer->xmlEndTag("qtimetadata");
6445 
6446  // add qti objectives
6447  $a_xml_writer->xmlStartTag("objectives");
6448  $this->addQTIMaterial($a_xml_writer, $this->getIntroduction());
6449  $a_xml_writer->xmlEndTag("objectives");
6450 
6451  // add qti assessmentcontrol
6452  if ($this->getInstantFeedbackSolution() == 1)
6453  {
6454  $attrs = array(
6455  "solutionswitch" => "Yes"
6456  );
6457  }
6458  else
6459  {
6460  $attrs = NULL;
6461  }
6462  $a_xml_writer->xmlElement("assessmentcontrol", $attrs, NULL);
6463 
6464  if (strlen($this->getFinalStatement()))
6465  {
6466  // add qti presentation_material
6467  $a_xml_writer->xmlStartTag("presentation_material");
6468  $a_xml_writer->xmlStartTag("flow_mat");
6469  $this->addQTIMaterial($a_xml_writer, $this->getFinalStatement());
6470  $a_xml_writer->xmlEndTag("flow_mat");
6471  $a_xml_writer->xmlEndTag("presentation_material");
6472  }
6473 
6474  $attrs = array(
6475  "ident" => "1"
6476  );
6477  $a_xml_writer->xmlElement("section", $attrs, NULL);
6478  $a_xml_writer->xmlEndTag("assessment");
6479  $a_xml_writer->xmlEndTag("questestinterop");
6480 
6481  $xml = $a_xml_writer->xmlDumpMem(FALSE);
6482 
6483  foreach ($this->questions as $question_id)
6484  {
6485  $question =& ilObjTest::_instanciateQuestion($question_id);
6486  $qti_question = $question->toXML(false);
6487  $qti_question = preg_replace("/<questestinterop>/", "", $qti_question);
6488  $qti_question = preg_replace("/<\/questestinterop>/", "", $qti_question);
6489  if (strpos($xml, "</section>") !== false)
6490  {
6491  $xml = str_replace("</section>", "$qti_question</section>", $xml);
6492  }
6493  else
6494  {
6495  $xml = str_replace("<section ident=\"1\"/>", "<section ident=\"1\">\n$qti_question</section>", $xml);
6496  }
6497  }
6498  return $xml;
6499  }
6500 
6507  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6508  {
6509  global $ilBench;
6510 
6511  $this->mob_ids = array();
6512  $this->file_ids = array();
6513 
6514  $attrs = array();
6515  $attrs["Type"] = "Test";
6516  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
6517 
6518  // MetaData
6519  $this->exportXMLMetaData($a_xml_writer);
6520 
6521  // PageObjects
6522  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
6523  $ilBench->start("ContentObjectExport", "exportPageObjects");
6524  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
6525  $ilBench->stop("ContentObjectExport", "exportPageObjects");
6526  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
6527 
6528  // MediaObjects
6529  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
6530  $ilBench->start("ContentObjectExport", "exportMediaObjects");
6531  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
6532  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
6533  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
6534 
6535  // FileItems
6536  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
6537  $ilBench->start("ContentObjectExport", "exportFileItems");
6538  $this->exportFileItems($a_target_dir, $expLog);
6539  $ilBench->stop("ContentObjectExport", "exportFileItems");
6540  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
6541 
6542  $a_xml_writer->xmlEndTag("ContentObject");
6543  }
6544 
6551  function exportXMLMetaData(&$a_xml_writer)
6552  {
6553  include_once "./Services/MetaData/classes/class.ilMD2XML.php";
6554  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
6555  $md2xml->setExportMode(true);
6556  $md2xml->startExport();
6557  $a_xml_writer->appendXML($md2xml->getXML());
6558  }
6559 
6567  function modifyExportIdentifier($a_tag, $a_param, $a_value)
6568  {
6569  if ($a_tag == "Identifier" && $a_param == "Entry")
6570  {
6571  include_once "./Services/Utilities/classes/class.ilUtil.php";
6572  $a_value = ilUtil::insertInstIntoID($a_value);
6573  }
6574 
6575  return $a_value;
6576  }
6577 
6578 
6585  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
6586  {
6587  global $ilBench;
6588 
6589  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
6590 
6591  foreach ($this->questions as $question_id)
6592  {
6593  $ilBench->start("ContentObjectExport", "exportPageObject");
6594  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
6595 
6596  $attrs = array();
6597  $a_xml_writer->xmlStartTag("PageObject", $attrs);
6598 
6599 
6600  // export xml to writer object
6601  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
6602  $page_object = new ilPageObject("qpl", $question_id);
6603  $page_object->buildDom();
6604  $page_object->insertInstIntoIDs($a_inst);
6605  $mob_ids = $page_object->collectMediaObjects(false);
6606  $file_ids = $page_object->collectFileItems();
6607  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
6608  $xml = str_replace("&","&amp;", $xml);
6609  $a_xml_writer->appendXML($xml);
6610  $page_object->freeDom();
6611  unset ($page_object);
6612 
6613  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
6614 
6615  // collect media objects
6616  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
6617  //$mob_ids = $page_obj->getMediaObjectIDs();
6618  foreach($mob_ids as $mob_id)
6619  {
6620  $this->mob_ids[$mob_id] = $mob_id;
6621  }
6622  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
6623 
6624  // collect all file items
6625  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
6626  //$file_ids = $page_obj->getFileItemIds();
6627  foreach($file_ids as $file_id)
6628  {
6629  $this->file_ids[$file_id] = $file_id;
6630  }
6631  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
6632 
6633  $a_xml_writer->xmlEndTag("PageObject");
6634  //unset($page_obj);
6635 
6636  $ilBench->stop("ContentObjectExport", "exportPageObject");
6637 
6638 
6639  }
6640  }
6641 
6648  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
6649  {
6650  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
6651 
6652  foreach ($this->mob_ids as $mob_id)
6653  {
6654  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
6655  if (ilObjMediaObject::_exists($mob_id))
6656  {
6657  $media_obj = new ilObjMediaObject($mob_id);
6658  $media_obj->exportXML($a_xml_writer, $a_inst);
6659  $media_obj->exportFiles($a_target_dir);
6660  unset($media_obj);
6661  }
6662  }
6663  }
6664 
6669  function exportFileItems($a_target_dir, &$expLog)
6670  {
6671  include_once "./Modules/File/classes/class.ilObjFile.php";
6672 
6673  foreach ($this->file_ids as $file_id)
6674  {
6675  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
6676  $file_obj = new ilObjFile($file_id, false);
6677  $file_obj->export($a_target_dir);
6678  unset($file_obj);
6679  }
6680  }
6681 
6686  function getImportMapping()
6687  {
6688  if (!is_array($this->import_mapping))
6689  {
6690  return array();
6691  }
6692  else
6693  {
6694  return $this->import_mapping;
6695  }
6696  }
6697 
6707  function getECTSGrade($passed_array, $reached_points, $max_points)
6708  {
6709  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);
6710  }
6711 
6722  function _getECTSGrade($points_passed, $reached_points, $max_points, $a, $b, $c, $d, $e, $fx)
6723  {
6724  include_once "./classes/class.ilStatistics.php";
6725  // calculate the median
6726  $passed_statistics = new ilStatistics();
6727  $passed_statistics->setData($points_passed);
6728  $ects_percentiles = array
6729  (
6730  "A" => $passed_statistics->quantile($a),
6731  "B" => $passed_statistics->quantile($b),
6732  "C" => $passed_statistics->quantile($c),
6733  "D" => $passed_statistics->quantile($d),
6734  "E" => $passed_statistics->quantile($e)
6735  );
6736  if (count($points_passed) && ($reached_points >= $ects_percentiles["A"]))
6737  {
6738  return "A";
6739  }
6740  else if (count($points_passed) && ($reached_points >= $ects_percentiles["B"]))
6741  {
6742  return "B";
6743  }
6744  else if (count($points_passed) && ($reached_points >= $ects_percentiles["C"]))
6745  {
6746  return "C";
6747  }
6748  else if (count($points_passed) && ($reached_points >= $ects_percentiles["D"]))
6749  {
6750  return "D";
6751  }
6752  else if (count($points_passed) && ($reached_points >= $ects_percentiles["E"]))
6753  {
6754  return "E";
6755  }
6756  else if (strcmp($fx, "") != 0)
6757  {
6758  if ($max_points > 0)
6759  {
6760  $percentage = ($reached_points / $max_points) * 100.0;
6761  if ($percentage < 0) $percentage = 0.0;
6762  }
6763  else
6764  {
6765  $percentage = 0.0;
6766  }
6767  if ($percentage >= $fx)
6768  {
6769  return "FX";
6770  }
6771  else
6772  {
6773  return "F";
6774  }
6775  }
6776  else
6777  {
6778  return "F";
6779  }
6780  }
6781 
6782  function checkMarks()
6783  {
6784  return $this->mark_schema->checkMarks();
6785  }
6786 
6787  function getMarkSchema()
6788  {
6789  return $this->mark_schema;
6790  }
6791 
6801  function setAuthor($author = "")
6802  {
6803  $this->author = $author;
6804  }
6805 
6817  function saveAuthorToMetadata($a_author = "")
6818  {
6819  $md =& new ilMD($this->getId(), 0, $this->getType());
6820  $md_life =& $md->getLifecycle();
6821  if (!$md_life)
6822  {
6823  if (strlen($a_author) == 0)
6824  {
6825  global $ilUser;
6826  $a_author = $ilUser->getFullname();
6827  }
6828 
6829  $md_life =& $md->addLifecycle();
6830  $md_life->save();
6831  $con =& $md_life->addContribute();
6832  $con->setRole("Author");
6833  $con->save();
6834  $ent =& $con->addEntity();
6835  $ent->setEntity($a_author);
6836  $ent->save();
6837  }
6838  }
6839 
6847  function createMetaData()
6848  {
6850  $this->saveAuthorToMetadata();
6851  }
6852 
6862  function getAuthor()
6863  {
6864  $author = array();
6865  include_once "./Services/MetaData/classes/class.ilMD.php";
6866  $md =& new ilMD($this->getId(), 0, $this->getType());
6867  $md_life =& $md->getLifecycle();
6868  if ($md_life)
6869  {
6870  $ids =& $md_life->getContributeIds();
6871  foreach ($ids as $id)
6872  {
6873  $md_cont =& $md_life->getContribute($id);
6874  if (strcmp($md_cont->getRole(), "Author") == 0)
6875  {
6876  $entids =& $md_cont->getEntityIds();
6877  foreach ($entids as $entid)
6878  {
6879  $md_ent =& $md_cont->getEntity($entid);
6880  array_push($author, $md_ent->getEntity());
6881  }
6882  }
6883  }
6884  }
6885  return join($author, ",");
6886  }
6887 
6897  function _lookupAuthor($obj_id)
6898  {
6899  $author = array();
6900  include_once "./Services/MetaData/classes/class.ilMD.php";
6901  $md =& new ilMD($obj_id, 0, "tst");
6902  $md_life =& $md->getLifecycle();
6903  if ($md_life)
6904  {
6905  $ids =& $md_life->getContributeIds();
6906  foreach ($ids as $id)
6907  {
6908  $md_cont =& $md_life->getContribute($id);
6909  if (strcmp($md_cont->getRole(), "Author") == 0)
6910  {
6911  $entids =& $md_cont->getEntityIds();
6912  foreach ($entids as $entid)
6913  {
6914  $md_ent =& $md_cont->getEntity($entid);
6915  array_push($author, $md_ent->getEntity());
6916  }
6917  }
6918  }
6919  }
6920  return join($author, ",");
6921  }
6922 
6931  function &_getAvailableTests($use_object_id = FALSE)
6932  {
6933  global $ilUser;
6934  global $ilDB;
6935 
6936  $result_array = array();
6937  $tests = ilUtil::_getObjectsByOperations("tst","write", $ilUser->getId(), -1);
6938  if (count($tests))
6939  {
6940  $titles = ilObject::_prepareCloneSelection($tests, "tst");
6941  $query = sprintf("SELECT object_data.*, object_reference.ref_id FROM object_data, object_reference WHERE object_data.obj_id = object_reference.obj_id AND object_reference.ref_id IN ('%s') ORDER BY object_data.title",
6942  implode("','", $tests)
6943  );
6944  $result = $ilDB->query($query);
6945  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
6946  {
6947  if ($use_object_id)
6948  {
6949  $result_array[$row["obj_id"]] = $titles[$row["ref_id"]];
6950  }
6951  else
6952  {
6953  $result_array[$row["ref_id"]] = $titles[$row["ref_id"]];
6954  }
6955  }
6956  }
6957  return $result_array;
6958  }
6959 
6968  function cloneRandomQuestions($new_id)
6969  {
6970  global $ilDB;
6971 
6972  if ($new_id > 0)
6973  {
6974  $query = sprintf("SELECT * FROM tst_test_random WHERE test_fi = %s ORDER BY test_random_id",
6975  $ilDB->quote($this->getTestId() . "")
6976  );
6977  $result = $ilDB->query($query);
6978  if ($result->numRows())
6979  {
6980  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
6981  {
6982  $query = sprintf("INSERT INTO tst_test_random (test_random_id, test_fi, questionpool_fi, num_of_q, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
6983  $ilDB->quote($new_id . ""),
6984  $ilDB->quote($row["questionpool_fi"] . ""),
6985  $ilDB->quote($row["num_of_q"] . "")
6986  );
6987  $insertresult = $ilDB->query($query);
6988  }
6989  }
6990  }
6991  }
6992 
6993 
7002  public function cloneObject($a_target_id,$a_copy_id = 0)
7003  {
7004  global $ilDB,$ilLog;
7005 
7006  $this->loadFromDb();
7007 
7008  // Copy settings
7009  $newObj = parent::cloneObject($a_target_id,$a_copy_id);
7010  $this->cloneMetaData($newObj);
7011  $newObj->setAnonymity($this->getAnonymity());
7012  $newObj->setAnswerFeedback($this->getAnswerFeedback());
7013  $newObj->setAnswerFeedbackPoints($this->getAnswerFeedbackPoints());
7014  $newObj->setAuthor($this->getAuthor());
7015  $newObj->setCountSystem($this->getCountSystem());
7016  $newObj->setECTSFX($this->getECTSFX());
7017  $newObj->setECTSGrades($this->getECTSGrades());
7018  $newObj->setECTSOutput($this->getECTSOutput());
7019  $newObj->setEnableProcessingTime($this->getEnableProcessingTime());
7020  $newObj->setEndingTime($this->getEndingTime());
7021  $newObj->setFixedParticipants($this->getFixedParticipants());
7022  $newObj->setInstantFeedbackSolution($this->getInstantFeedbackSolution());
7023  $newObj->setIntroduction($this->getIntroduction());
7024  $newObj->setFinalStatement($this->getFinalStatement());
7025  $newObj->setShowInfo($this->getShowInfo());
7026  $newObj->setForceJS($this->getForceJS());
7027  $newObj->setCustomStyle($this->getCustomStyle());
7028  $newObj->setShowFinalStatement($this->getShowFinalStatement());
7029  $newObj->setListOfQuestionsSettings($this->getListOfQuestionsSettings());
7030  $newObj->setMCScoring($this->getMCScoring());
7031  $newObj->setNrOfTries($this->getNrOfTries());
7032  $newObj->setPassScoring($this->getPassScoring());
7033  $newObj->setPassword($this->getPassword());
7034  $newObj->setProcessingTime($this->getProcessingTime());
7035  $newObj->setRandomQuestionCount($this->getRandomQuestionCount());
7036  $newObj->setRandomTest($this->isRandomTest());
7037  $newObj->setReportingDate($this->getReportingDate());
7038  $newObj->setResetProcessingTime($this->getResetProcessingTime());
7039  $newObj->setResultsPresentation($this->getResultsPresentation());
7040  $newObj->setScoreCutting($this->getScoreCutting());
7041  $newObj->setScoreReporting($this->getScoreReporting());
7042  $newObj->setSequenceSettings($this->getSequenceSettings());
7043  $newObj->setShowCancel($this->getShowCancel());
7044  $newObj->setShowMarker($this->getShowMarker());
7045  $newObj->setShuffleQuestions($this->getShuffleQuestions());
7046  $newObj->setStartingTime($this->getStartingTime());
7047  $newObj->setTitleOutput($this->getTitleOutput());
7048  $newObj->setUsePreviousAnswers($this->getUsePreviousAnswers());
7049  $newObj->setCertificateVisibility($this->getCertificateVisibility());
7050  $newObj->mark_schema = clone $this->mark_schema;
7051 
7052  $newObj->saveToDb();
7053  // clone certificate
7054  include_once "./Modules/Test/classes/class.ilTestCertificate.php";
7055  $cert = new ilTestCertificate($this);
7056  $cert->cloneCertificate($newObj->getId());
7057 
7058  if ($this->isRandomTest())
7059  {
7060  $newObj->saveRandomQuestionCount($newObj->getRandomQuestionCount());
7061  $this->cloneRandomQuestions($newObj->getTestId());
7062  }
7063  else
7064  {
7065  include_once("./Services/CopyWizard/classes/class.ilCopyWizardOptions.php");
7066  $cwo = ilCopyWizardOptions::_getInstance($a_copy_id);
7067 
7068  // clone the questions
7069  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7070  foreach ($this->questions as $key => $question_id)
7071  {
7072  $question = ilObjTest::_instanciateQuestion($question_id);
7073  $newObj->questions[$key] = $question->duplicate();
7074  $original_id = assQuestion::_getOriginalId($question_id);
7075  $question = ilObjTest::_instanciateQuestion($newObj->questions[$key]);
7076  $question->saveToDb($original_id);
7077 
7078  // Save the mapping of old question id <-> new question id
7079  // This will be used in class.ilObjCourse::cloneDependencies to copy learning objectives
7080  $cwo->appendMapping($this->getRefId().'_'.$question_id,$newObj->getRefId().'_'.$newObj->questions[$key]);
7081  $ilLog->write(__METHOD__.': Added mapping '.$this->getRefId().'_'.$question_id.' <-> ' .
7082  $newObj->getRefId().'_'.$newObj->questions[$key]);
7083  }
7084  }
7085  $newObj->saveToDb();
7086  return $newObj;
7087  }
7088 
7089  function _getRefIdFromObjId($obj_id)
7090  {
7091  global $ilDB;
7092 
7093  $query = sprintf("SELECT ref_id FROM object_reference WHERE obj_id=%s",
7094  $ilDB->quote($obj_id)
7095 
7096  );
7097  $result = $ilDB->query($query);
7098  if ($result->numRows())
7099  {
7100  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7101  return $row["ref_id"];
7102  }
7103  return 0;
7104  }
7105 
7114  function getQuestionCount()
7115  {
7116  $num = 0;
7117 
7118  if ($this->isRandomTest())
7119  {
7120  if ($this->getRandomQuestionCount())
7121  {
7122  $num = $this->getRandomQuestionCount();
7123  $qpls =& $this->getRandomQuestionpools();
7124  $maxcount = 0;
7125  foreach ($qpls as $data)
7126  {
7127  $maxcount += $data["contains"];
7128  }
7129  if ($num > $maxcount) $num = $maxcount;
7130  }
7131  else
7132  {
7133  $qpls =& $this->getRandomQuestionpools();
7134  foreach ($qpls as $data)
7135  {
7136  $add = ($data["count"] <= $data["contains"]) ? $data["count"] : $data["contains"];
7137  $num += $add;
7138  }
7139  }
7140  }
7141  else
7142  {
7143  $num = count($this->questions);
7144  }
7145  return $num;
7146  }
7147 
7157  {
7158  global $ilDB;
7159 
7160  $num = 0;
7161 
7162  $query = sprintf("SELECT * FROM tst_tests WHERE test_id = %s",
7163  $ilDB->quote($test_id . "")
7164  );
7165  $result = $ilDB->query($query);
7166  if (!$result->numRows())
7167  {
7168  return 0;
7169  }
7170  $test = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7171 
7172  if ($test["random_test"] == 1)
7173  {
7174  $qpls = array();
7175  $counter = 0;
7176  $query = sprintf("SELECT * FROM tst_test_random WHERE test_fi = %s ORDER BY test_random_id",
7177  $ilDB->quote($test_id . "")
7178  );
7179  $result = $ilDB->query($query);
7180  if ($result->numRows())
7181  {
7182  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
7183  {
7184  $countquery = sprintf("SELECT question_id FROM qpl_questions WHERE obj_fi = %s AND original_id IS NULL",
7185  $ilDB->quote($row["questionpool_fi"] . "")
7186  );
7187  $countresult = $ilDB->query($countquery);
7188  $contains = $countresult->numRows();
7189  $qpls[$counter] = array(
7190  "index" => $counter,
7191  "count" => $row["num_of_q"],
7192  "qpl" => $row["questionpool_fi"],
7193  "contains" => $contains
7194  );
7195  $counter++;
7196  }
7197  }
7198  if ($test["random_question_count"] > 0)
7199  {
7200  $num = $test["random_question_count"];
7201  $maxcount = 0;
7202  foreach ($qpls as $data)
7203  {
7204  $maxcount += $data["contains"];
7205  }
7206  if ($num > $maxcount) $num = $maxcount;
7207  }
7208  else
7209  {
7210  $num = 0;
7211  foreach ($qpls as $data)
7212  {
7213  $add = ($data["count"] <= $data["contains"]) ? $data["count"] : $data["contains"];
7214  $num += $add;
7215  }
7216  }
7217  }
7218  else
7219  {
7220  $query = sprintf("SELECT test_question_id FROM tst_test_question WHERE test_fi = %s",
7221  $ilDB->quote($test_id . "")
7222  );
7223  $result = $ilDB->query($query);
7224  $num = $result->numRows();
7225  }
7226  return $num;
7227  }
7228 
7237  {
7238  global $ilDB;
7239 
7240  // delete eventually set questions of a previous non-random test
7241  $this->removeAllTestEditings();
7242  $query = sprintf("DELETE FROM tst_test_question WHERE test_fi = %s",
7243  $ilDB->quote($this->getTestId())
7244  );
7245  $result = $ilDB->query($query);
7246  $this->questions = array();
7247  $this->saveCompleteStatus();
7248  }
7249 
7258  {
7259  global $ilDB;
7260  // delete eventually set random question pools of a previous random test
7261  $this->removeAllTestEditings();
7262  $query = sprintf("DELETE FROM tst_test_random WHERE test_fi = %s",
7263  $ilDB->quote($this->getTestId())
7264  );
7265  $result = $ilDB->query($query);
7266  $this->questions = array();
7267  $this->saveCompleteStatus();
7268  }
7269 
7279  function logAction($logtext = "", $question_id = "")
7280  {
7281  global $ilUser;
7282 
7283  $original_id = "";
7284  if (strcmp($question_id, "") != 0)
7285  {
7286  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7287  $original_id = assQuestion::_getOriginalId($question_id);
7288  }
7289  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
7290  ilObjAssessmentFolder::_addLog($ilUser->getId(), $this->getId(), $logtext, $question_id, $original_id, TRUE, $this->getRefId());
7291  }
7292 
7303  {
7304  global $ilDB;
7305  $object_id = FALSE;
7306  $query = sprintf("SELECT obj_fi FROM tst_tests WHERE test_id = %s",
7307  $ilDB->quote($test_id . "")
7308  );
7309  $result = $ilDB->query($query);
7310  if ($result->numRows())
7311  {
7312  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7313  $object_id = $row["obj_fi"];
7314  }
7315  return $object_id;
7316  }
7317 
7327  function _getObjectIDFromActiveID($active_id)
7328  {
7329  global $ilDB;
7330  $object_id = FALSE;
7331  $query = sprintf("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",
7332  $ilDB->quote($active_id . "")
7333  );
7334  $result = $ilDB->query($query);
7335  if ($result->numRows())
7336  {
7337  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7338  $object_id = $row["obj_fi"];
7339  }
7340  return $object_id;
7341  }
7342 
7352  function _getTestIDFromObjectID($object_id)
7353  {
7354  global $ilDB;
7355  $test_id = FALSE;
7356  $query = sprintf("SELECT test_id FROM tst_tests WHERE obj_fi = %s",
7357  $ilDB->quote($object_id . "")
7358  );
7359  $result = $ilDB->query($query);
7360  if ($result->numRows())
7361  {
7362  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7363  $test_id = $row["test_id"];
7364  }
7365  return $test_id;
7366  }
7367 
7378  function getTextAnswer($active_id, $question_id, $pass = NULL)
7379  {
7380  global $ilDB;
7381 
7382  $res = "";
7383  if (($active_id) && ($question_id))
7384  {
7385  if (is_null($pass))
7386  {
7387  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
7388  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
7389  }
7390  $query = sprintf("SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
7391  $ilDB->quote($active_id . ""),
7392  $ilDB->quote($question_id . ""),
7393  $ilDB->quote($pass . "")
7394  );
7395  $result = $ilDB->query($query);
7396  if ($result->numRows() == 1)
7397  {
7398  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7399  $res = $row["value1"];
7400  }
7401  }
7402  return $res;
7403  }
7404 
7414  function getQuestiontext($question_id)
7415  {
7416  global $ilDB;
7417 
7418  $res = "";
7419  if ($question_id)
7420  {
7421  $query = sprintf("SELECT question_text FROM qpl_questions WHERE question_id = %s",
7422  $ilDB->quote($question_id . "")
7423  );
7424  $result = $ilDB->query($query);
7425  if ($result->numRows() == 1)
7426  {
7427  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7428  $res = $row["question_text"];
7429  }
7430  }
7431  return $res;
7432  }
7433 
7442  function &getInvitedUsers($user_id="", $order="login, lastname, firstname")
7443  {
7444  global $ilDB;
7445 
7446  $result_array = array();
7447 
7448  if ($this->getAnonymity())
7449  {
7450  if (is_numeric($user_id))
7451  {
7452  $query = sprintf("SELECT tst_active.active_id, tst_active.tries, usr_id, '' AS login, %s AS lastname, '' AS firstname, tst_invited_user.clientip, " .
7453  "tst_active.submitted as test_finished, matriculation, IF(tst_active.active_id IS NULL,0,1) as test_started " .
7454  "FROM usr_data, tst_invited_user " .
7455  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7456  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7457  "ORDER BY %s",
7458  $ilDB->quote($this->lng->txt("unknown")),
7459  $ilDB->quote($this->test_id),
7460  $user_id,
7461  $order
7462  );
7463  }
7464  else
7465  {
7466  $query = sprintf("SELECT tst_active.active_id, usr_id, '' AS login, %s AS lastname, '' AS firstname, tst_invited_user.clientip, " .
7467  "tst_active.submitted as test_finished, matriculation, IF(tst_active.active_id IS NULL,0,1) as test_started " .
7468  "FROM usr_data, tst_invited_user " .
7469  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7470  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7471  "ORDER BY %s",
7472  $ilDB->quote($this->lng->txt("unknown")),
7473  $ilDB->quote($this->test_id),
7474  $order
7475  );
7476  }
7477  }
7478  else
7479  {
7480  if (is_numeric($user_id))
7481  {
7482  $query = sprintf("SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7483  "tst_active.submitted as test_finished, matriculation, IF(tst_active.active_id IS NULL,0,1) as test_started " .
7484  "FROM usr_data, tst_invited_user " .
7485  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7486  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
7487  "ORDER BY %s",
7488  $ilDB->quote($this->test_id),
7489  $user_id,
7490  $order
7491  );
7492  }
7493  else
7494  {
7495  $query = sprintf("SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
7496  "tst_active.submitted as test_finished, matriculation, IF(tst_active.active_id IS NULL,0,1) as test_started " .
7497  "FROM usr_data, tst_invited_user " .
7498  "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
7499  "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
7500  "ORDER BY %s",
7501  $ilDB->quote($this->test_id),
7502  $order
7503  );
7504  }
7505  }
7506  return $this->getArrayData($query, "usr_id");
7507  }
7508 
7518  {
7519  global $ilDB;
7520 
7521  if ($this->getAnonymity())
7522  {
7523  $q = sprintf("SELECT tst_active.active_id, tst_active.tries, tst_active.user_fi AS usr_id, '' AS login, %s AS lastname, '' AS firstname, tst_active.submitted as test_finished, usr_data.matriculation, usr_data.active, IF(tst_active.active_id IS NULL,0,1) as test_started ".
7524  "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),
7525  $ilDB->quote($this->lng->txt("unknown")),
7526  $ilDB->quote($this->getTestId())
7527  );
7528  }
7529  else
7530  {
7531  $q = sprintf("SELECT tst_active.active_id, tst_active.tries, tst_active.user_fi AS usr_id, usr_data.login, usr_data.lastname, usr_data.firstname, tst_active.submitted as test_finished, usr_data.matriculation, usr_data.active, IF(tst_active.active_id IS NULL,0,1) as test_started ".
7532  "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),
7533  $ilDB->quote($this->getTestId())
7534  );
7535  }
7536  $data = $this->getArrayData($q, "active_id");
7537  foreach ($data as $index => $participant)
7538  {
7539  if (strlen(trim($participant->firstname.$participant->lastname)) == 0)
7540  {
7541  $data[$index]->lastname = $this->lng->txt("deleted_user");
7542  }
7543  }
7544  return $data;
7545  }
7546 
7556  function &getUserData($ids)
7557  {
7558  if (!is_array($ids) || count($ids) ==0)
7559  return array();
7560 
7561  $result_array = array();
7562 
7563  if ($this->getAnonymity())
7564  {
7565  $query = sprintf("SELECT usr_id, '' AS login, %s AS lastname, '' AS firstname, client_ip as clientip FROM usr_data WHERE usr_id IN ('%s') ORDER BY login",
7566  $ilDB->quote($this->lng->txt("unknown")),
7567  join ($ids,"','")
7568  );
7569  }
7570  else
7571  {
7572  $query = sprintf("SELECT usr_id, login, lastname, firstname, client_ip as clientip FROM usr_data WHERE usr_id IN ('%s') ORDER BY login",
7573  join ($ids,"','")
7574  );
7575  }
7576 
7577  return $this->getArrayData ($query, "usr_id");
7578  }
7579 
7590  function &getArrayData($query, $id_field)
7591  {
7592  return ilObjTest::_getArrayData ($query, $id_field);
7593  }
7594 
7595  function &_getArrayData($query, $id_field)
7596  {
7597  global $ilDB;
7598  $result = $ilDB->query($query);
7599  while ($row = $result->fetchRow(MDB2_FETCHMODE_OBJECT))
7600  {
7601  $result_array[$row->$id_field]= $row;
7602  }
7603  return ($result_array)?$result_array:array();
7604  }
7605 
7606  function &getGroupData($ids)
7607  {
7608  if (!is_array($ids) || count($ids) ==0)
7609  return array();
7610 
7611  $result_array = array();
7612 
7613  $query = sprintf("SELECT ref_id, title, description FROM `grp_settings` g, object_data o, object_reference r WHERE o.obj_id=g.obj_id AND o.obj_id = r.obj_id AND ref_id IN ('%s')",
7614  join ($ids,"','")
7615  );
7616 
7617  return $this->getArrayData ($query, "ref_id");
7618  }
7619 
7620  function &getRoleData($ids)
7621  {
7622  if (!is_array($ids) || count($ids) ==0)
7623  return array();
7624 
7625  $result_array = array();
7626 
7627  $query = sprintf("SELECT obj_id, description, title FROM role_data, object_data o WHERE o.obj_id=role_id AND role_id IN ('%s')",
7628  join ($ids,"','")
7629  );
7630 
7631  return $this->getArrayData ($query, "obj_id");
7632  }
7633 
7634 
7643  function inviteGroup($group_id)
7644  {
7645  include_once "./Modules/Group/classes/class.ilObjGroup.php";
7646  $group = new ilObjGroup($group_id);
7647  $members = $group->getGroupMemberIds();
7648  include_once './Services/User/classes/class.ilObjUser.php';
7649  foreach ($members as $user_id)
7650  {
7651  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7652  }
7653  }
7654 
7663  function inviteRole($role_id)
7664  {
7665  global $rbacreview;
7666  $members = $rbacreview->assignedUsers($role_id,"usr_id");
7667  include_once './Services/User/classes/class.ilObjUser.php';
7668  foreach ($members as $user_id)
7669  {
7670  $this->inviteUser($user_id, ilObjUser::_lookupClientIP($user_id));
7671  }
7672  }
7673 
7674 
7675 
7684  function disinviteUser($user_id)
7685  {
7686  global $ilDB;
7687 
7688  $query = sprintf("DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
7689  $ilDB->quote($this->test_id),
7690  $ilDB->quote($user_id)
7691  );
7692  $result = $ilDB->query($query);
7693  }
7694 
7703  function inviteUser($user_id, $client_ip="")
7704  {
7705  global $ilDB;
7706 
7707  $query = sprintf("INSERT IGNORE INTO tst_invited_user (test_fi, user_fi, clientip) VALUES (%s, %s, %s)",
7708  $ilDB->quote($this->test_id),
7709  $ilDB->quote($user_id),
7710  $ilDB->quote($client_ip)
7711  );
7712  $result = $ilDB->query($query);
7713  }
7714 
7715 
7716  function setClientIP($user_id, $client_ip)
7717  {
7718  global $ilDB;
7719 
7720  $query = sprintf("UPDATE tst_invited_user SET clientip=%s WHERE test_fi=%s and user_fi=%s",
7721  $ilDB->quote($client_ip),
7722  $ilDB->quote($this->test_id),
7723  $ilDB->quote($user_id)
7724  );
7725  $insertresult = $ilDB->query($query);
7726  }
7727 
7733  function _getSolvedQuestions($active_id, $question_fi = null)
7734  {
7735  global $ilDB;
7736  if (is_numeric($question_fi))
7737  $query = sprintf("SELECT question_fi, solved FROM tst_active_qst_sol_settings " .
7738  "WHERE active_fi = %s AND question_fi=%s",
7739  $ilDB->quote($active_id),
7740  $question_fi
7741  );
7742  else $query = sprintf("SELECT question_fi, solved FROM tst_active_qst_sol_settings " .
7743  "WHERE active_fi = %s",
7744  $ilDB->quote($active_id)
7745  );
7746  return ilObjTest::_getArrayData ($query, "question_fi");
7747  }
7748 
7749 
7753  function setQuestionSetSolved($value, $question_id, $user_id)
7754  {
7755  global $ilDB;
7756 
7757  $active_id = $this->getActiveIdOfUser($user_id);
7758  $query = sprintf("REPLACE INTO tst_active_qst_sol_settings SET solved=%s, question_fi=%s, active_fi = %s",
7759  $ilDB->quote($value),
7760  $ilDB->quote($question_id),
7761  $ilDB->quote($active_id)
7762  );
7763 
7764  $ilDB->query($query);
7765  }
7766 
7767 
7771  function setActiveTestSubmitted($user_id)
7772  {
7773  global $ilDB, $ilLog;
7774 
7775  $query = sprintf("UPDATE tst_active SET submitted = 1, submittimestamp = NOW() WHERE test_fi = %s AND user_fi = %s",
7776  $ilDB->quote($this->getTestId() . ""),
7777  $ilDB->quote($user_id . "")
7778  );
7779  $result = $ilDB->query($query);
7780  $this->testSession = NULL;
7781  }
7782 
7786  function isActiveTestSubmitted($user_id = null)
7787  {
7788  global $ilUser;
7789  global $ilDB;
7790 
7791  if (!is_numeric($user_id))
7792  $user_id = $ilUser->getId();
7793 
7794  $query = sprintf("SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=1",
7795  $ilDB->quote($this->test_id),
7796  $ilDB->quote($user_id)
7797  );
7798  $result = $ilDB->query($query);
7799 
7800  return $result->numRows() == 1;
7801 
7802  }
7807  {
7808  return $this->getNrOfTries() != 0;
7809  }
7810 
7811 
7816  function isNrOfTriesReached($tries)
7817  {
7818  return $tries >= (int) $this->getNrOfTries();
7819  }
7820 
7821 
7830  function getAllTestResults($participants, $prepareForCSV = true)
7831  {
7832  $results = array();
7833  $row = array(
7834  "user_id" => $this->lng->txt("user_id"),
7835  "matriculation" => $this->lng->txt("matriculation"),
7836  "lastname" => $this->lng->txt("lastname"),
7837  "firstname" => $this->lng->txt("firstname"),
7838  "login" =>$this->lng->txt("login"),
7839  "reached_points" => $this->lng->txt("tst_reached_points"),
7840  "max_points" => $this->lng->txt("tst_maximum_points"),
7841  "percent_value" => $this->lng->txt("tst_percent_solved"),
7842  "mark" => $this->lng->txt("tst_mark"),
7843  "ects" => $this->lng->txt("ects_grade")
7844  );
7845  $results[] = $row;
7846  #print_r($participants);
7847  if (count($participants))
7848  {
7849  if ($this->ects_output)
7850  {
7851  $passed_array =& $this->getTotalPointsPassedArray();
7852  }
7853  foreach ($participants as $active_id => $user_rec)
7854  {
7855  $row = array();
7856  $reached_points = 0;
7857  $max_points = 0;
7858  foreach ($this->questions as $value)
7859  {
7860  $question =& ilObjTest::_instanciateQuestion($value);
7861  if (is_object($question))
7862  {
7863  $max_points += $question->getMaximumPoints();
7864  $reached_points += $question->getReachedPoints($active_id);
7865  }
7866  }
7867  if ($max_points > 0)
7868  {
7869  $percentvalue = $reached_points / $max_points;
7870  if ($percentvalue < 0) $percentvalue = 0.0;
7871  }
7872  else
7873  {
7874  $percentvalue = 0;
7875  }
7876  $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
7877  $passed = "";
7878  if ($mark_obj)
7879  {
7880  $mark = $mark_obj->getOfficialName();
7881  $ects_mark = $this->getECTSGrade($passed_array, $reached_points, $max_points);
7882  }
7883  if ($this->getAnonymity())
7884  {
7885  $user_rec->firstname = "";
7886  $user_rec->lastname = $this->lng->txt("unknown");
7887  }
7888  $row = array(
7889 "user_id"=>$user_rec->usr_id,
7890  "matriculation" => $user_rec->matriculation,
7891  "lastname" => $user_rec->lastname,
7892  "firstname" => $user_rec->firstname,
7893 "login"=>$user_rec->login,
7894  "reached_points" => $reached_points,
7895  "max_points" => $max_points,
7896  "percent_value" => $percentvalue,
7897  "mark" => $mark,
7898  "ects" => $ects_mark
7899  );
7900  $results[] = $prepareForCSV ? $this->processCSVRow ($row, true) : $row;
7901  }
7902  }
7903  return $results;
7904  }
7905 
7918  function &processCSVRow($row, $quoteAll = FALSE, $separator = ";")
7919  {
7920  $resultarray = array();
7921  foreach ($row as $rowindex => $entry)
7922  {
7923  $surround = FALSE;
7924  if ($quoteAll)
7925  {
7926  $surround = TRUE;
7927  }
7928  if (strpos($entry, "\"") !== FALSE)
7929  {
7930  $entry = str_replace("\"", "\"\"", $entry);
7931  $surround = TRUE;
7932  }
7933  if (strpos($entry, $separator) !== FALSE)
7934  {
7935  $surround = TRUE;
7936  }
7937  // replace all CR LF with LF (for Excel for Windows compatibility
7938  $entry = str_replace(chr(13).chr(10), chr(10), $entry);
7939  if ($surround)
7940  {
7941  $resultarray[$rowindex] = utf8_decode("\"" . $entry . "\"");
7942  }
7943  else
7944  {
7945  $resultarray[$rowindex] = utf8_decode($entry);
7946  }
7947  }
7948  return $resultarray;
7949  }
7950 
7961  function _getPass($active_id)
7962  {
7963  global $ilDB;
7964  $query = sprintf("SELECT tries FROM tst_active WHERE active_id = %s",
7965  $ilDB->quote($active_id . "")
7966  );
7967  $result = $ilDB->query($query);
7968  if ($result->numRows())
7969  {
7970  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
7971  return $row["tries"];
7972  }
7973  else
7974  {
7975  return 0;
7976  }
7977  }
7978 
7990  function _getMaxPass($active_id)
7991  {
7992  global $ilDB;
7993  $query = sprintf("SELECT MAX(pass) as maxpass FROM tst_test_result WHERE active_fi = %s",
7994  $ilDB->quote($active_id . "")
7995  );
7996  $result = $ilDB->query($query);
7997  if ($result->numRows())
7998  {
7999  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
8000  $max = $row["maxpass"];
8001  }
8002  else
8003  {
8004  $max = NULL;
8005  }
8006  return $max;
8007  }
8008 
8019  function _getBestPass($active_id)
8020  {
8021  global $ilDB;
8022 
8023  $query = sprintf("SELECT * FROM tst_test_pass_result WHERE active_fi = %s",
8024  $ilDB->quote($active_id . "")
8025  );
8026  $result = $ilDB->query($query);
8027  if ($result->numRows())
8028  {
8029  $bestrow = null;
8030  $bestpoints = -1;
8031  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
8032  {
8033  if ($row["points"] > $bestpoints)
8034  {
8035  $bestrow = $row;
8036  $bestpoints = $row["points"];
8037  }
8038  }
8039  if (is_array($bestrow))
8040  {
8041  return $bestrow["pass"];
8042  }
8043  else
8044  {
8045  return 0;
8046  }
8047  }
8048  else
8049  {
8050  return 0;
8051  }
8052  }
8053 
8064  function _getResultPass($active_id)
8065  {
8066  $counted_pass = NULL;
8067  if (ilObjTest::_getPassScoring($active_id) == SCORE_BEST_PASS)
8068  {
8069  $counted_pass = ilObjTest::_getBestPass($active_id);
8070  }
8071  else
8072  {
8073  $counted_pass = ilObjTest::_getMaxPass($active_id);
8074  }
8075  return $counted_pass;
8076  }
8077 
8089  function getAnsweredQuestionCount($active_id, $pass = NULL)
8090  {
8091  if ($this->isRandomTest())
8092  {
8093  $this->loadQuestions($active_id, $pass);
8094  }
8095  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
8096  $workedthrough = 0;
8097  foreach ($this->questions as $value)
8098  {
8099  if (assQuestion::_isWorkedThrough($active_id, $value, $pass))
8100  {
8101  $workedthrough += 1;
8102  }
8103  }
8104  return $workedthrough;
8105  }
8106 
8118  function getPassFinishDate($active_id, $pass)
8119  {
8120  global $ilDB;
8121  if (is_null($pass)) $pass = 0;
8122  $query = sprintf("SELECT tst_test_result.TIMESTAMP + 0 AS timestamp14 FROM tst_test_result WHERE active_fi = %s AND pass = %s ORDER BY tst_test_result.TIMESTAMP DESC",
8123  $ilDB->quote($active_id . ""),
8124  $ilDB->quote($pass . "")
8125  );
8126  $result = $ilDB->query($query);
8127  if ($result->numRows())
8128  {
8129  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
8130  return $row["timestamp14"];
8131  }
8132  else
8133  {
8134  return 0;
8135  }
8136  }
8137 
8147  function isExecutable($user_id, $allowPassIncrease = FALSE)
8148  {
8149  $result = array(
8150  "executable" => true,
8151  "errormessage" => ""
8152  );
8153  if (!$this->startingTimeReached())
8154  {
8155  $result["executable"] = false;
8156  $result["errormessage"] = sprintf($this->lng->txt("detail_starting_time_not_reached"), ilFormat::ftimestamp2datetimeDB($this->getStartingTime()));
8157  return $result;
8158  }
8159  if ($this->endingTimeReached())
8160  {
8161  $result["executable"] = false;
8162  $result["errormessage"] = sprintf($this->lng->txt("detail_ending_time_reached"), ilFormat::ftimestamp2datetimeDB($this->getEndingTime()));
8163  return $result;
8164  }
8165 
8166  $active_id = $this->getActiveIdOfUser($user_id);
8167 
8168  if ($this->getEnableProcessingTime())
8169  {
8170  if ($active_id > 0)
8171  {
8172  $starting_time = $this->getStartingTimeOfUser($active_id);
8173  if ($starting_time !== FALSE)
8174  {
8176  {
8177  if ($allowPassIncrease && $this->getResetProcessingTime() && (($this->getNrOfTries() == 0) || ($this->getNrOfTries() > ($this->_getPass($active_id)+1))))
8178  {
8179  // a test pass was quitted because the maximum processing time was reached, but the time
8180  // will be resetted for future passes, so if there are more passes allowed, the participant may
8181  // start the test again.
8182  // This code block is only called when $allowPassIncrease is TRUE which only happens when
8183  // the test info page is opened. Otherwise this will lead to unexpected results!
8184  $this->getTestSession()->increasePass();
8185  $this->getTestSession()->setLastSequence(0);
8186  $this->getTestSession()->saveToDb();
8187  }
8188  else
8189  {
8190  $result["executable"] = false;
8191  $result["errormessage"] = $this->lng->txt("detail_max_processing_time_reached");
8192  }
8193  return $result;
8194  }
8195  }
8196  }
8197  }
8198 
8199  if ($this->hasNrOfTriesRestriction() && ($active_id > 0) && $this->isNrOfTriesReached($this->getTestSession($active_id)->getPass()))
8200  {
8201  $result["executable"] = false;
8202  $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8203  return $result;
8204  }
8205 
8206  if ($this->getTestSession($active_id)->isSubmitted())
8207  {
8208  $result["executable"] = FALSE;
8209  $result["errormessage"] = $this->lng->txt("maximum_nr_of_tries_reached");
8210  return $result;
8211  }
8212 
8213  // TODO: max. processing time
8214 
8215  return $result;
8216  }
8217 
8226  function canViewResults()
8227  {
8228  $result = true;
8229  if ($this->getReportingDate())
8230  {
8231  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
8232  {
8233  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8234  $now = mktime();
8235  if ($now < $epoch_time)
8236  {
8237  $result = false;
8238  }
8239  }
8240  }
8241  return $result;
8242  }
8243 
8244  function canShowTestResults($user_id)
8245  {
8246  $result = true;
8247  $active_id = $this->getActiveIdOfUser($user_id);
8248  if ($active_id > 0)
8249  {
8250  $starting_time = $this->getStartingTimeOfUser($active_id);
8251  }
8252  $notimeleft = FALSE;
8253  if ($starting_time !== FALSE)
8254  {
8256  {
8257  $notimeleft = TRUE;
8258  }
8259  }
8260  if (!$this->isTestFinishedToViewResults($active_id, $this->getTestSession($active_id)->getPass()) && ($this->getScoreReporting() == REPORT_AFTER_TEST))
8261  {
8262  $result = FALSE;
8263  }
8264  if (($this->endingTimeReached()) || $notimeleft) $result = TRUE;
8265  $result = $result & $this->canViewResults();
8266  return $result;
8267  }
8268 
8269  function canEditMarks()
8270  {
8271  $total = $this->evalTotalPersons();
8272  if ($total > 0)
8273  {
8274  if ($this->getReportingDate())
8275  {
8276  if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches))
8277  {
8278  $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8279  $now = mktime();
8280  if ($now < $epoch_time)
8281  {
8282  return true;
8283  }
8284  }
8285  }
8286  return false;
8287  }
8288  else
8289  {
8290  return true;
8291  }
8292  }
8293 
8303  function getStartingTimeOfUser($active_id)
8304  {
8305  global $ilDB;
8306 
8307  if ($active_id < 1) return FALSE;
8308  $pass = ($this->getResetProcessingTime()) ? $this->_getPass($active_id) : 0;
8309  $query = sprintf("SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
8310  $ilDB->quote($active_id . ""),
8311  $ilDB->quote($pass . "")
8312  );
8313  $result = $ilDB->query($query);
8314  if ($result->numRows())
8315  {
8316  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
8317  if (preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches))
8318  {
8319  return mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
8320  }
8321  else
8322  {
8323  return mktime();
8324  }
8325  }
8326  else
8327  {
8328  return mktime();
8329  }
8330  }
8331 
8343  {
8344  if ($this->getEnableProcessingTime())
8345  {
8347  $now = mktime();
8348  if ($now > ($starting_time + $processing_time))
8349  {
8350  return TRUE;
8351  }
8352  else
8353  {
8354  return FALSE;
8355  }
8356  }
8357  else
8358  {
8359  return FALSE;
8360  }
8361  }
8362 
8363  function &getTestQuestions()
8364  {
8365  global $ilDB;
8366  $query = sprintf("SELECT qpl_questions.*, qpl_question_type.type_tag FROM qpl_questions, qpl_question_type, tst_test_question WHERE qpl_questions.question_type_fi = qpl_question_type.question_type_id AND tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ORDER BY sequence",
8367  $ilDB->quote($this->getTestId() . "")
8368  );
8369  $query_result = $ilDB->query($query);
8370  $removableQuestions = array();
8371  while ($row = $query_result->fetchRow(MDB2_FETCHMODE_ASSOC))
8372  {
8373  array_push($removableQuestions, $row);
8374  }
8375  return $removableQuestions;
8376  }
8377 
8387  {
8388  return $this->shuffle_questions;
8389  }
8390 
8399  function setShuffleQuestions($a_shuffle)
8400  {
8401  if ($a_shuffle)
8402  {
8403  $this->shuffle_questions = TRUE;
8404  }
8405  else
8406  {
8407  $this->shuffle_questions = FALSE;
8408  }
8409  }
8410 
8426  {
8427  return $this->show_summary;
8428  }
8429 
8444  function setListOfQuestionsSettings($a_value = 0)
8445  {
8446  $this->show_summary = $a_value;
8447  }
8448 
8458  {
8459  if (($this->show_summary & 1) > 0)
8460  {
8461  return TRUE;
8462  }
8463  else
8464  {
8465  return FALSE;
8466  }
8467  }
8468 
8477  function setListOfQuestions($a_value = TRUE)
8478  {
8479  if ($a_value)
8480  {
8481  $this->show_summary = 1;
8482  }
8483  else
8484  {
8485  $this->show_summary = 0;
8486  }
8487  }
8488 
8498  {
8499  if (($this->show_summary & 2) > 0)
8500  {
8501  return TRUE;
8502  }
8503  else
8504  {
8505  return FALSE;
8506  }
8507  }
8508 
8517  function setListOfQuestionsStart($a_value = TRUE)
8518  {
8519  if ($a_value && $this->getListOfQuestions())
8520  {
8521  $this->show_summary = $this->show_summary | 2;
8522  }
8523  if (!$a_value && $this->getListOfQuestions())
8524  {
8525  if ($this->getListOfQuestionsStart())
8526  {
8527  $this->show_summary = $this->show_summary ^ 2;
8528  }
8529  }
8530  }
8531 
8541  {
8542  if (($this->show_summary & 4) > 0)
8543  {
8544  return TRUE;
8545  }
8546  else
8547  {
8548  return FALSE;
8549  }
8550  }
8551 
8560  function setListOfQuestionsEnd($a_value = TRUE)
8561  {
8562  if ($a_value && $this->getListOfQuestions())
8563  {
8564  $this->show_summary = $this->show_summary | 4;
8565  }
8566  if (!$a_value && $this->getListOfQuestions())
8567  {
8568  if ($this->getListOfQuestionsEnd())
8569  {
8570  $this->show_summary = $this->show_summary ^ 4;
8571  }
8572  }
8573  }
8574 
8584  {
8585  if (($this->show_summary & 8) > 0)
8586  {
8587  return TRUE;
8588  }
8589  else
8590  {
8591  return FALSE;
8592  }
8593  }
8594 
8603  function setListOfQuestionsDescription($a_value = TRUE)
8604  {
8605  if ($a_value && $this->getListOfQuestions())
8606  {
8607  $this->show_summary = $this->show_summary | 8;
8608  }
8609  if (!$a_value && $this->getListOfQuestions())
8610  {
8611  if ($this->getListOfQuestionsDescription())
8612  {
8613  $this->show_summary = $this->show_summary ^ 8;
8614  }
8615  }
8616  }
8617 
8627  {
8629  }
8630 
8640  {
8641  if (($this->results_presentation & 1) > 0)
8642  {
8643  return TRUE;
8644  }
8645  else
8646  {
8647  return FALSE;
8648  }
8649  }
8650 
8660  {
8661  if (($this->results_presentation & 2) > 0)
8662  {
8663  return TRUE;
8664  }
8665  else
8666  {
8667  return FALSE;
8668  }
8669  }
8670 
8680  {
8681  if (($this->results_presentation & 4) > 0)
8682  {
8683  return TRUE;
8684  }
8685  else
8686  {
8687  return FALSE;
8688  }
8689  }
8690 
8700  {
8701  if (($this->results_presentation & 8) > 0)
8702  {
8703  return TRUE;
8704  }
8705  else
8706  {
8707  return FALSE;
8708  }
8709  }
8710 
8720  {
8721  if (($this->results_presentation & 16) > 0)
8722  {
8723  return TRUE;
8724  }
8725  else
8726  {
8727  return FALSE;
8728  }
8729  }
8730 
8740  {
8741  if (($this->results_presentation & 32) > 0)
8742  {
8743  return TRUE;
8744  }
8745  else
8746  {
8747  return FALSE;
8748  }
8749  }
8750 
8759  function setResultsPresentation($a_results_presentation = 3)
8760  {
8761  $this->results_presentation = $a_results_presentation;
8762  }
8763 
8772  function setShowPassDetails($a_details = 1)
8773  {
8774  if ($a_details)
8775  {
8776  $this->results_presentation = $this->results_presentation | 1;
8777  }
8778  else
8779  {
8780  if ($this->getShowPassDetails())
8781  {
8782  $this->results_presentation = $this->results_presentation ^ 1;
8783  }
8784  }
8785  }
8786 
8795  function setShowSolutionDetails($a_details = 1)
8796  {
8797  if ($a_details)
8798  {
8799  $this->results_presentation = $this->results_presentation | 2;
8800  }
8801  else
8802  {
8803  if ($this->getShowSolutionDetails())
8804  {
8805  $this->results_presentation = $this->results_presentation ^ 2;
8806  }
8807  }
8808  }
8809 
8818  function canShowSolutionPrintview($user_id = NULL)
8819  {
8820  return $this->getShowSolutionPrintview();
8821  }
8822 
8831  function setShowSolutionPrintview($a_printview = 1)
8832  {
8833  if ($a_printview)
8834  {
8835  $this->results_presentation = $this->results_presentation | 4;
8836  }
8837  else
8838  {
8839  if ($this->getShowSolutionPrintview())
8840  {
8841  $this->results_presentation = $this->results_presentation ^ 4;
8842  }
8843  }
8844  }
8845 
8854  function setShowSolutionFeedback($a_feedback = TRUE)
8855  {
8856  if ($a_feedback)
8857  {
8858  $this->results_presentation = $this->results_presentation | 8;
8859  }
8860  else
8861  {
8862  if ($this->getShowSolutionFeedback())
8863  {
8864  $this->results_presentation = $this->results_presentation ^ 8;
8865  }
8866  }
8867  }
8868 
8877  function setShowSolutionAnswersOnly($a_full = TRUE)
8878  {
8879  if ($a_full)
8880  {
8881  $this->results_presentation = $this->results_presentation | 16;
8882  }
8883  else
8884  {
8885  if ($this->getShowSolutionAnswersOnly())
8886  {
8887  $this->results_presentation = $this->results_presentation ^ 16;
8888  }
8889  }
8890  }
8891 
8900  function setShowSolutionSignature($a_signature = FALSE)
8901  {
8902  if ($a_signature)
8903  {
8904  $this->results_presentation = $this->results_presentation | 32;
8905  }
8906  else
8907  {
8908  if ($this->getShowSolutionSignature())
8909  {
8910  $this->results_presentation = $this->results_presentation ^ 32;
8911  }
8912  }
8913  }
8914 
8921  {
8922  // create a 5 character code
8923  $codestring = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
8924  mt_srand();
8925  $code = "";
8926  for ($i = 1; $i <=5; $i++)
8927  {
8928  $index = mt_rand(0, strlen($codestring)-1);
8929  $code .= substr($codestring, $index, 1);
8930  }
8931  // verify it against the database
8932  while ($this->isAccessCodeUsed($code))
8933  {
8934  $code = $this->createNewAccessCode();
8935  }
8936  return $code;
8937  }
8938 
8939  function isAccessCodeUsed($code)
8940  {
8941  global $ilDB;
8942 
8943  $query = sprintf("SELECT anonymous_id FROM tst_active WHERE test_fi = %s AND anonymous_id = %s",
8944  $ilDB->quote($this->getTestId() . ""),
8945  $ilDB->quote($code . "")
8946  );
8947  $result = $ilDB->query($query);
8948  if ($result->numRows() > 0)
8949  {
8950  return TRUE;
8951  }
8952  else
8953  {
8954  return FALSE;
8955  }
8956  }
8957 
8958  function _getUserIdFromActiveId($active_id)
8959  {
8960  global $ilDB;
8961  $query = sprintf("SELECT user_fi FROM tst_active WHERE active_id = %s",
8962  $ilDB->quote($active_id . "")
8963  );
8964  $result = $ilDB->query($query);
8965  if ($result->numRows())
8966  {
8967  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
8968  return $row["user_fi"];
8969  }
8970  else
8971  {
8972  return -1;
8973  }
8974  }
8975 
8977  {
8978  $id = $this->getTestId();
8979  if (!is_array($_SESSION["tst_access_code"]))
8980  {
8981  return "";
8982  }
8983  else
8984  {
8985  return $_SESSION["tst_access_code"]["$id"];
8986  }
8987  }
8988 
8989  function setAccessCodeSession($access_code)
8990  {
8991  $id = $this->getTestId();
8992  if (!is_array($_SESSION["tst_access_code"]))
8993  {
8994  $_SESSION["tst_access_code"] = array();
8995  }
8996  $_SESSION["tst_access_code"]["$id"] = $access_code;
8997  }
8998 
9000  {
9001  $id = $this->getTestId();
9002  unset($_SESSION["tst_access_code"]["$id"]);
9003  }
9004 
9005  function getAllowedUsers()
9006  {
9007  return $this->allowedUsers;
9008  }
9009 
9010  function setAllowedUsers($a_allowed_users)
9011  {
9012  $this->allowedUsers = $a_allowed_users;
9013  }
9014 
9016  {
9018  }
9019 
9020  function setAllowedUsersTimeGap($a_allowed_users_time_gap)
9021  {
9022  $this->allowedUsersTimeGap = $a_allowed_users_time_gap;
9023  }
9024 
9026  {
9027  global $ilDB;
9028 
9029  $nr_of_users = $this->getAllowedUsers();
9030  $time_gap = ($this->getAllowedUsersTimeGap()) ? $this->getAllowedUsersTimeGap() : 60;
9031  if (($nr_of_users > 0) && ($time_gap > 0))
9032  {
9033  $now = mktime();
9034  $time_border = $now - $time_gap;
9035  $str_time_border = strftime("%Y%m%d%H%M%S", $time_border);
9036  $query = sprintf("SELECT DISTINCT tst_times.active_fi FROM tst_times, tst_active WHERE tst_times.TIMESTAMP > %s AND tst_times.active_fi = tst_active.active_id AND tst_active.test_fi = %s",
9037  $ilDB->quote($str_time_border),
9038  $ilDB->quote($this->getTestId() . "")
9039  );
9040  $result = $ilDB->query($query);
9041  if ($result->numRows() >= $nr_of_users)
9042  {
9043  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
9045  {
9046  $this->logAction($this->lng->txtlng("assessment", "log_could_not_enter_test_due_to_simultaneous_users", ilObjAssessmentFolder::_getLogLanguage()));
9047  }
9048  return FALSE;
9049  }
9050  else
9051  {
9052  return TRUE;
9053  }
9054  }
9055  return TRUE;
9056  }
9057 
9058  function _getLastAccess($active_id)
9059  {
9060  global $ilDB;
9061 
9062  $query = sprintf("SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
9063  $ilDB->quote($active_id . "")
9064  );
9065  $result = $ilDB->query($query);
9066  if ($result->numRows())
9067  {
9068  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
9069  return $row["finished"];
9070  }
9071  return "";
9072  }
9073 
9081  function isHTML($a_text)
9082  {
9083  if (preg_match("/<[^>]*?>/", $a_text))
9084  {
9085  return TRUE;
9086  }
9087  else
9088  {
9089  return FALSE;
9090  }
9091  }
9092 
9100  function QTIMaterialToString($a_material)
9101  {
9102  $result = "";
9103  for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
9104  {
9105  $material = $a_material->getMaterial($i);
9106  if (strcmp($material["type"], "mattext") == 0)
9107  {
9108  $result .= $material["material"]->getContent();
9109  }
9110  if (strcmp($material["type"], "matimage") == 0)
9111  {
9112  $matimage = $material["material"];
9113  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
9114  {
9115  // import an mediaobject which was inserted using tiny mce
9116  if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
9117  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
9118  }
9119  }
9120  }
9121  global $ilLog;
9122  $ilLog->write(print_r($_SESSION["import_mob_xhtml"], true));
9123  return $result;
9124  }
9125 
9134  function addQTIMaterial(&$a_xml_writer, $a_material)
9135  {
9136  include_once "./Services/RTE/classes/class.ilRTE.php";
9137  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
9138 
9139  $a_xml_writer->xmlStartTag("material");
9140  $attrs = array(
9141  "texttype" => "text/plain"
9142  );
9143  if ($this->isHTML($a_material))
9144  {
9145  $attrs["texttype"] = "text/xhtml";
9146  }
9147  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
9148 
9149  $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->getId());
9150  foreach ($mobs as $mob)
9151  {
9152  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
9153  if (strpos($a_material, "mm_$mob") !== FALSE)
9154  {
9155  if (ilObjMediaObject::_exists($mob))
9156  {
9157  $mob_obj =& new ilObjMediaObject($mob);
9158  $imgattrs = array(
9159  "label" => $moblabel,
9160  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
9161  );
9162  }
9163  $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
9164  }
9165  }
9166  $a_xml_writer->xmlEndTag("material");
9167  }
9168 
9175  function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE)
9176  {
9177  include_once "./Services/Utilities/classes/class.ilUtil.php";
9178  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output);
9179  }
9180 
9189  function saveCertificateVisibility($a_value)
9190  {
9191  global $ilDB;
9192 
9193  $query = sprintf("UPDATE tst_tests SET certificate_visibility = %s WHERE test_id = %s",
9194  $ilDB->quote($a_value),
9195  $ilDB->quote($this->getTestId())
9196  );
9197  $result = $ilDB->query($query);
9198  }
9199 
9209  {
9211  }
9212 
9221  function setCertificateVisibility($a_value)
9222  {
9223  $this->certificate_visibility = $a_value;
9224  }
9225 
9234  function getAnonymity()
9235  {
9236  return $this->anonymity;
9237  }
9238 
9247  function setAnonymity($a_value = 0)
9248  {
9249  switch ($a_value)
9250  {
9251  case 1:
9252  $this->anonymity = 1;
9253  break;
9254  default:
9255  $this->anonymity = 0;
9256  break;
9257  }
9258  }
9259 
9268  function getShowCancel()
9269  {
9270  return $this->show_cancel;
9271  }
9272 
9281  function setShowCancel($a_value = 1)
9282  {
9283  switch ($a_value)
9284  {
9285  case 1:
9286  $this->show_cancel = 1;
9287  break;
9288  default:
9289  $this->show_cancel = 0;
9290  break;
9291  }
9292  }
9293 
9302  function getShowMarker()
9303  {
9304  return $this->show_marker;
9305  }
9306 
9315  function setShowMarker($a_value = 1)
9316  {
9317  switch ($a_value)
9318  {
9319  case 1:
9320  $this->show_marker = 1;
9321  break;
9322  default:
9323  $this->show_marker = 0;
9324  break;
9325  }
9326  }
9327 
9337  {
9339  }
9340 
9349  function setFixedParticipants($a_value = 1)
9350  {
9351  switch ($a_value)
9352  {
9353  case 1:
9354  $this->fixed_participants = 1;
9355  break;
9356  default:
9357  $this->fixed_participants = 0;
9358  break;
9359  }
9360  }
9361 
9371  function _lookupAnonymity($a_obj_id)
9372  {
9373  global $ilDB;
9374 
9375  $query = "SELECT anonymity FROM tst_tests ".
9376  "WHERE obj_fi = '".$a_obj_id."'";
9377  $res = $ilDB->query($query);
9378  while($row = $res->fetchRow(MDB2_FETCHMODE_ASSOC))
9379  {
9380  return $row['anonymity'];
9381  }
9382  return 0;
9383  }
9384 
9394  function _lookupRandomTestFromActiveId($active_id)
9395  {
9396  global $ilDB;
9397 
9398  $query = sprintf("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",
9399  $ilDB->quote($active_id . "")
9400  );
9401  $res = $ilDB->query($query);
9402  while($row = $res->fetchRow(MDB2_FETCHMODE_ASSOC))
9403  {
9404  return $row['random_test'];
9405  }
9406  return 0;
9407  }
9408 
9419  function userLookupFullName($user_id, $overwrite_anonymity = FALSE, $sorted_order = FALSE, $suffix = "")
9420  {
9421  if ($this->getAnonymity() && !$overwrite_anonymity)
9422  {
9423  return $this->lng->txt("unknown") . $suffix;
9424  }
9425  else
9426  {
9427  include_once './Services/User/classes/class.ilObjUser.php';
9428  $uname = ilObjUser::_lookupName($user_id);
9429  if (strlen($uname["firstname"].$uname["lastname"]) == 0) $uname["firstname"] = $this->lng->txt("deleted_user");
9430  if ($sorted_order)
9431  {
9432  return trim($uname["lastname"] . ", " . $uname["firstname"]) . $suffix;
9433  }
9434  else
9435  {
9436  return trim($uname["firstname"] . " " . $uname["lastname"]) . $suffix;
9437  }
9438  }
9439  }
9440 
9450  function getStartTestLabel($active_id)
9451  {
9452  if ($this->getNrOfTries() == 1)
9453  {
9454  return $this->lng->txt("tst_start_test");
9455  }
9456  $active_pass = $this->_getPass($active_id);
9457  $res = $this->getNrOfResultsForPass($active_id, $active_pass);
9458  if ($res == 0)
9459  {
9460  if ($active_pass == 0)
9461  {
9462  return $this->lng->txt("tst_start_test");
9463  }
9464  else
9465  {
9466  return $this->lng->txt("tst_start_new_test_pass");
9467  }
9468  }
9469  else
9470  {
9471  return $this->lng->txt("tst_resume_test");
9472  }
9473  }
9474 
9485  function &getAvailableDefaults($sortby = "name", $sortorder = "asc")
9486  {
9487  global $ilDB;
9488  global $ilUser;
9489 
9490  $query = sprintf("SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY $sortby $sortorder",
9491  $ilDB->quote($ilUser->getId() . "")
9492  );
9493  $result = $ilDB->query($query);
9494  $defaults = array();
9495  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
9496  {
9497  $defaults[$row["test_defaults_id"]] = $row;
9498  }
9499  return $defaults;
9500  }
9501 
9511  function &getTestDefaults($test_defaults_id)
9512  {
9513  global $ilDB;
9514 
9515  $query = sprintf("SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
9516  $ilDB->quote($test_defaults_id . "")
9517  );
9518  $result = $ilDB->query($query);
9519  if ($result->numRows() == 1)
9520  {
9521  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
9522  return $row;
9523  }
9524  else
9525  {
9526  return NULL;
9527  }
9528  }
9529 
9538  function deleteDefaults($test_default_id)
9539  {
9540  global $ilDB;
9541  $query = sprintf("DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
9542  $ilDB->quote($test_default_id . "")
9543  );
9544  $result = $ilDB->query($query);
9545  }
9546 
9555  function addDefaults($a_name)
9556  {
9557  global $ilDB;
9558  global $ilUser;
9559  $testsettings = array(
9560  "TitleOutput" => $this->getTitleOutput(),
9561  "PassScoring" => $this->getPassScoring(),
9562  "Introduction" => $this->getIntroduction(),
9563  "FinalStatement" => $this->getFinalStatement(),
9564  "ShowInfo" => $this->getShowInfo(),
9565  "ForceJS" => $this->getForceJS(),
9566  "CustomStyle" => $this->getCustomStyle(),
9567  "ShowFinalStatement" => $this->getShowFinalStatement(),
9568  "SequenceSettings" => $this->getSequenceSettings(),
9569  "ScoreReporting" => $this->getScoreReporting(),
9570  "InstantFeedbackSolution" => $this->getInstantFeedbackSolution(),
9571  "AnswerFeedback" => $this->getAnswerFeedback(),
9572  "AnswerFeedbackPoints" => $this->getAnswerFeedbackPoints(),
9573  "ResultsPresentation" => $this->getResultsPresentation(),
9574  "Anonymity" => $this->getAnonymity(),
9575  "ShowCancel" => $this->getShowCancel(),
9576  "ShowMarker" => $this->getShowMarker(),
9577  "ReportingDate" => $this->getReportingDate(),
9578  "NrOfTries" => $this->getNrOfTries(),
9579  "Kiosk" => $this->getKiosk(),
9580  "UsePreviousAnswers" => $this->getUsePreviousAnswers(),
9581  "ProcessingTime" => $this->getProcessingTime(),
9582  "EnableProcessingTime" => $this->getEnableProcessingTime(),
9583  "ResetProcessingTime" => $this->getResetProcessingTime(),
9584  "StartingTime" => $this->getStartingTime(),
9585  "EndingTime" => $this->getEndingTime(),
9586  "ECTSOutput" => $this->getECTSOutput(),
9587  "ECTSFX" => $this->getECTSFX(),
9588  "ECTSGrades" => $this->getECTSGrades(),
9589  "isRandomTest" => $this->isRandomTest(),
9590  "RandomQuestionCount" => $this->getRandomQuestionCount(),
9591  "CountSystem" => $this->getCountSystem(),
9592  "MCScoring" => $this->getMCScoring(),
9593  "ListOfQuestionsSettings" => $this->getListOfQuestionsSettings()
9594  );
9595  $query = sprintf("INSERT INTO tst_test_defaults (test_defaults_id, name, user_fi, defaults, marks) VALUES (NULL, %s, %s, %s, %s)",
9596  $ilDB->quote($a_name . ""),
9597  $ilDB->quote($ilUser->getId(). ""),
9598  $ilDB->quote(serialize($testsettings)),
9599  $ilDB->quote(serialize($this->mark_schema))
9600  );
9601  $result = $ilDB->query($query);
9602  }
9603 
9613  function applyDefaults($test_defaults_id)
9614  {
9615  $total = $this->evalTotalPersons();
9616  $result = FALSE;
9617  if (($this->getQuestionCount() == 0) && ($total == 0))
9618  {
9619  // only apply if there are no questions added and not user datasets exist
9620  $defaults =& $this->getTestDefaults($test_defaults_id);
9621  $testsettings = unserialize($defaults["defaults"]);
9622  include_once "./Modules/Test/classes/class.assMarkSchema.php";
9623  $this->mark_schema = unserialize($defaults["marks"]);
9624  $this->setTitleOutput($testsettings["TitleOutput"]);
9625  $this->setPassScoring($testsettings["PassScoring"]);
9626  $this->setIntroduction($testsettings["Introduction"]);
9627  $this->setFinalStatement($testsettings["FinalStatement"]);
9628  $this->setShowInfo($testsettings["ShowInfo"]);
9629  $this->setForceJS($testsettings["ForceJS"]);
9630  $this->setCustomStyle($testsettings["CustomStyle"]);
9631  $this->setShowFinalStatement($testsettings["ShowFinalStatement"]);
9632  $this->setSequenceSettings($testsettings["SequenceSettings"]);
9633  $this->setScoreReporting($testsettings["ScoreReporting"]);
9634  $this->setInstantFeedbackSolution($testsettings["InstantFeedbackSolution"]);
9635  $this->setAnswerFeedback($testsettings["AnswerFeedback"]);
9636  $this->setAnswerFeedbackPoints($testsettings["AnswerFeedbackPoints"]);
9637  $this->setResultsPresentation($testsettings["ResultsPresentation"]);
9638  $this->setAnonymity($testsettings["Anonymity"]);
9639  $this->setShowCancel($testsettings["ShowCancel"]);
9640  $this->setShowMarker($testsettings["ShowMarker"]);
9641  $this->setReportingDate($testsettings["ReportingDate"]);
9642  $this->setNrOfTries($testsettings["NrOfTries"]);
9643  $this->setUsePreviousAnswers($testsettings["UsePreviousAnswers"]);
9644  $this->setProcessingTime($testsettings["ProcessingTime"]);
9645  $this->setResetProcessingTime($testsettings["ResetProcessingTime"]);
9646  $this->setEnableProcessingTime($testsettings["EnableProcessingTime"]);
9647  $this->setStartingTime($testsettings["StartingTime"]);
9648  $this->setKiosk($testsettings["Kiosk"]);
9649  $this->setEndingTime($testsettings["EndingTime"]);
9650  $this->setECTSOutput($testsettings["ECTSOutput"]);
9651  $this->setECTSFX($testsettings["ECTSFX"]);
9652  $this->setECTSGrades($testsettings["ECTSGrades"]);
9653  $this->setRandomTest($testsettings["isRandomTest"]);
9654  $this->setRandomQuestionCount($testsettings["RandomQuestionCount"]);
9655  $this->setCountSystem($testsettings["CountSystem"]);
9656  $this->setMCScoring($testsettings["MCScoring"]);
9657  $this->setListOfQuestionsSettings($testsettings["ListOfQuestionsSettings"]);
9658  $this->saveToDb();
9659  $result = TRUE;
9660  }
9661  return $result;
9662  }
9663 
9673  function processPrintoutput2FO($print_output)
9674  {
9675  if (extension_loaded("tidy"))
9676  {
9677  $config = array(
9678  "indent" => false,
9679  "output-xml" => true,
9680  "numeric-entities" => true
9681  );
9682  $tidy = new tidy();
9683  $tidy->parseString($print_output, $config, 'utf8');
9684  $tidy->cleanRepair();
9685  $print_output = tidy_get_output($tidy);
9686  $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output);
9687  }
9688  else
9689  {
9690  $print_output = str_replace("&nbsp;", "&#160;", $print_output);
9691  $print_output = str_replace("&otimes;", "X", $print_output);
9692  }
9693 
9694  $xsl = file_get_contents("./Modules/Test/xml/question2fo.xsl");
9695  $args = array( '/_xml' => $print_output, '/_xsl' => $xsl );
9696  $xh = xslt_create();
9697  $params = array();
9698  $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", NULL, $args, $params);
9699  xslt_error($xh);
9700  xslt_free($xh);
9701  return $output;
9702  }
9703 
9710  public function deliverPDFfromFO($fo, $title = null)
9711  {
9712  include_once "./Services/Utilities/classes/class.ilUtil.php";
9713  $fo_file = ilUtil::ilTempnam() . ".fo";
9714  $fp = fopen($fo_file, "w"); fwrite($fp, $fo); fclose($fp);
9715  include_once "./Services/Transformation/classes/class.ilFO2PDF.php";
9716  $fo2pdf = new ilFO2PDF();
9717  $fo2pdf->setFOString($fo);
9718  $result = $fo2pdf->send();
9719  $filename = (strlen($title)) ? $title : $this->getTitle();
9720  ilUtil::deliverData($result, ilUtil::getASCIIFilename($filename) . ".pdf", "application/pdf", false, true);
9721  }
9722 
9734  static function getManualFeedback($active_id, $question_id, $pass)
9735  {
9736  global $ilDB;
9737  $feedback = "";
9738  $query = sprintf("SELECT feedback FROM tst_manual_feedback WHERE active_fi = %s AND question_fi = %s AND pass = %s",
9739  $ilDB->quote($active_id . ""),
9740  $ilDB->quote($question_id . ""),
9741  $ilDB->quote($pass . "")
9742  );
9743  $result = $ilDB->query($query);
9744  if ($result->numRows())
9745  {
9746  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
9747  include_once("./Services/RTE/classes/class.ilRTE.php");
9748  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
9749  }
9750  return $feedback;
9751  }
9752 
9765  function saveManualFeedback($active_id, $question_id, $pass, $feedback)
9766  {
9767  global $ilDB;
9768 
9769  $query = sprintf("DELETE FROM tst_manual_feedback WHERE active_fi = %s AND question_fi = %s AND pass = %s",
9770  $ilDB->quote($active_id . ""),
9771  $ilDB->quote($question_id . ""),
9772  $ilDB->quote($pass . "")
9773  );
9774  $result = $ilDB->query($query);
9775 
9776  if (strlen($feedback))
9777  {
9778  $query = sprintf("INSERT INTO tst_manual_feedback (active_fi, question_fi, pass, feedback) VALUES (%s, %s, %s, %s)",
9779  $ilDB->quote($active_id . ""),
9780  $ilDB->quote($question_id . ""),
9781  $ilDB->quote($pass . ""),
9782  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($feedback, 0) . "")
9783  );
9784  $result = $ilDB->query($query);
9785  }
9786  if (PEAR::isError($result))
9787  {
9788  global $ilias;
9789  $ilias->raiseError($result->getMessage());
9790  }
9791  else
9792  {
9793  return TRUE;
9794  }
9795  }
9796 
9805  {
9806  global $ilUser;
9807  if (strcmp($_GET["tst_javascript"], "0") == 0) return FALSE;
9808  if ($this->getForceJS()) return TRUE;
9809  $assessmentSetting = new ilSetting("assessment");
9810  return ($ilUser->getPref("tst_javascript") === FALSE) ? $assessmentSetting->get("use_javascript") : $ilUser->getPref("tst_javascript");
9811  }
9812 
9819  function &createTestSession()
9820  {
9821  global $ilUser;
9822 
9823  include_once "./Modules/Test/classes/class.ilTestSession.php";
9824  $testSession = FALSE;
9825  $testSession = new ilTestSession();
9826  $testSession->setTestId($this->getTestId());
9827  $testSession->setUserId($ilUser->getId());
9828  $testSession->setAnonymousId($_SESSION["tst_access_code"][$this->getTestId()]);
9829  $testSession->saveToDb();
9830  $this->testSession =& $testSession;
9831  return $this->testSession;
9832  }
9833 
9841  function &setTestSession($active_id = "")
9842  {
9843  if (is_object($this->testSession) && ($this->testSession->getActiveId() > 0)) return $this->testSession;
9844 
9845  global $ilUser;
9846 
9847  include_once "./Modules/Test/classes/class.ilTestSession.php";
9848  $testSession = FALSE;
9849  if ($active_id > 0)
9850  {
9851  $testSession = new ilTestSession($active_id);
9852  }
9853  else
9854  {
9855  $testSession = new ilTestSession();
9856  $testSession->loadTestSession($this->getTestId(), $ilUser->getId(), $_SESSION["tst_access_code"][$this->getTestId()]);
9857  }
9858  $this->testSession =& $testSession;
9859  return $this->testSession;
9860  }
9861 
9868  function &getTestSession($active_id = "")
9869  {
9870  if (is_object($this->testSession) && ($this->testSession->getActiveId() > 0)) return $this->testSession;
9871  return $this->setTestSession($active_id);
9872  }
9873 
9874  function &createTestSequence($active_id, $pass, $shuffle)
9875  {
9876  include_once "./Modules/Test/classes/class.ilTestSequence.php";
9877  $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
9878  if (!$this->testSequence->hasSequence())
9879  {
9880  $this->testSequence->createNewSequence($this->getQuestionCount(), $shuffle);
9881  $this->testSequence->saveToDb();
9882  }
9883  }
9884 
9885  function &getTestSequence($active_id = "", $pass = "")
9886  {
9887  if (is_object($this->testSequence) && ($this->testSequence->getActiveId() > 0)) return $this->testSequence;
9888 
9889  include_once "./Modules/Test/classes/class.ilTestSequence.php";
9890  if (($active_id > 0) && (strlen($pass)))
9891  {
9892  $this->testSequence = new ilTestSequence($active_id, $pass, $this->isRandomTest());
9893  }
9894  else
9895  {
9896  $this->testSequence = new ilTestSequence($this->getTestSession()->getActiveId(), $this->getTestSession()->getPass(), $this->isRandomTest());
9897  }
9898  return $this->testSequence;
9899  }
9900 
9902  {
9903  if ($this->getTestSession()->getActiveId() > 0)
9904  {
9905  $result = $this->getTestResult($this->getTestSession()->getActiveId(), $this->getTestSession()->getPass(), TRUE);
9906  foreach ($result as $sequence => $question)
9907  {
9908  if (is_numeric($sequence))
9909  {
9910  if ($question["reached"] == $question["max"])
9911  {
9912  $this->getTestSequence()->hideQuestion($question["qid"]);
9913  }
9914  }
9915  }
9916  $this->getTestSequence()->saveToDb();
9917  }
9918  }
9919 
9928  function getDetailedTestResults($participants)
9929  {
9930  $results = array();
9931  if (count($participants))
9932  {
9933  foreach ($participants as $active_id => $user_rec)
9934  {
9935  $row = array();
9936  $reached_points = 0;
9937  $max_points = 0;
9938  foreach ($this->questions as $value)
9939  {
9940  $question =& ilObjTest::_instanciateQuestion($value);
9941  if (is_object($question))
9942  {
9943  $max_points += $question->getMaximumPoints();
9944  $reached_points += $question->getReachedPoints($active_id);
9945  if ($max_points > 0)
9946  {
9947  $percentvalue = $reached_points / $max_points;
9948  if ($percentvalue < 0) $percentvalue = 0.0;
9949  }
9950  else
9951  {
9952  $percentvalue = 0;
9953  }
9954  if ($this->getAnonymity())
9955  {
9956  $user_rec->firstname = "";
9957  $user_rec->lastname = $this->lng->txt("unknown");
9958  }
9959  $row = array(
9960  "user_id"=>$user_rec->usr_id,
9961  "matriculation" => $user_rec->matriculation,
9962  "lastname" => $user_rec->lastname,
9963  "firstname" => $user_rec->firstname,
9964  "login"=>$user_rec->login,
9965  "question_id" => $question->getId(),
9966  "question_title" => $question->getTitle(),
9967  "reached_points" => $reached_points,
9968  "max_points" => $max_points
9969  );
9970  $results[] = $row;
9971  }
9972  }
9973  }
9974  }
9975  return $results;
9976  }
9977 
9982  {
9983  global $ilDB;
9984 
9985  $set = $ilDB->query("SELECT t.obj_fi AS obj_id FROM tst_test_question AS q, tst_tests AS t WHERE".
9986  " q.test_fi = t.test_id AND q.question_fi = ".$ilDB->quote($a_q_id));
9987  $rec = $set->fetchRow(DB_FETCHMODE_ASSOC);
9988  return $rec["obj_id"];
9989  }
9990 
9997  function isPluginActive($a_pname)
9998  {
9999  global $ilPluginAdmin;
10000  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
10001  {
10002  return TRUE;
10003  }
10004  else
10005  {
10006  return FALSE;
10007  }
10008  }
10009 
10016  {
10017  $assessmentSetting = new ilSetting("assessment");
10018  $assessmentSetting->set("evalFields_" . $this->getId(), serialize($fields));
10019  }
10020 
10027  {
10028  $assessmentSetting = new ilSetting("assessment");
10029  $found = $assessmentSetting->get("evalFields_" . $this->getId());
10030  $fields = array();
10031  if (strlen($found)) $fields = unserialize($found);
10032  if (is_array($fields)) return $fields; else return array();
10033  }
10034 
10042  function canShowCertificate($user_id, $active_id)
10043  {
10044  if ($this->canShowTestResults($user_id))
10045  {
10046  $counted_pass = ilObjTest::_getResultPass($active_id);
10047  $result_array =& $this->getTestResult($active_id, $counted_pass);
10048 
10049  include_once "./Modules/Test/classes/class.ilTestCertificate.php";
10050  $cert = new ilTestCertificate($this);
10051  if ($cert->isComplete())
10052  {
10053  $vis = $this->getCertificateVisibility();
10054  $showcert = FALSE;
10055  switch ($vis)
10056  {
10057  case 0:
10058  $showcert = TRUE;
10059  break;
10060  case 1:
10061  if ($result_array["test"]["passed"] == 1)
10062  {
10063  $showcert = TRUE;
10064  }
10065  break;
10066  case 2:
10067  $showcert = FALSE;
10068  break;
10069  }
10070  if ($showcert)
10071  {
10072  return TRUE;
10073  }
10074  else
10075  {
10076  return FALSE;
10077  }
10078  }
10079  else
10080  {
10081  return FALSE;
10082  }
10083  }
10084  else
10085  {
10086  return FALSE;
10087  }
10088  }
10089 
10096  {
10097  global $ilDB;
10098  $query = sprintf("SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass FROM tst_test_result, tst_active, qpl_questions WHERE tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s AND tst_test_result.question_fi = qpl_questions.question_id AND qpl_questions.original_id = %s",
10099  $ilDB->quote($test_id),
10100  $ilDB->quote($question_id)
10101  );
10102  $result = $ilDB->query($query);
10103  $foundusers = array();
10104  while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
10105  {
10106  if (!array_key_exists($row["active_fi"], $foundusers))
10107  {
10108  $foundusers[$row["active_fi"]] = array();
10109  }
10110  array_push($foundusers[$row["active_fi"]], array("pass" => $row["pass"], "qid" => $row["question_fi"]));
10111  }
10112  return $foundusers;
10113  }
10114 
10120  public function hasPDFProcessing()
10121  {
10122  global $ilias;
10123  if ((strlen($ilias->getSetting("rpc_server_host"))) && (strlen($ilias->getSetting("rpc_server_port"))))
10124  {
10125  return TRUE;
10126  }
10127  else
10128  {
10129  return FALSE;
10130  }
10131  }
10132 
10138  public function getAggregatedResultsData()
10139  {
10140  $data =& $this->getCompleteEvaluationData();
10141  $foundParticipants =& $data->getParticipants();
10142  $results = array("overview" => array(), "questions" => array());
10143  if (count($foundParticipants))
10144  {
10145  $results["overview"][$this->lng->txt("tst_eval_total_persons")] = count($foundParticipants);
10146  $total_finished = $this->evalTotalFinished();
10147  $results["overview"][$this->lng->txt("tst_eval_total_finished")] = $total_finished;
10148  $average_time = $this->evalTotalStartedAverageTime();
10149  $diff_seconds = $average_time;
10150  $diff_hours = floor($diff_seconds/3600);
10151  $diff_seconds -= $diff_hours * 3600;
10152  $diff_minutes = floor($diff_seconds/60);
10153  $diff_seconds -= $diff_minutes * 60;
10154  $results["overview"][$this->lng->txt("tst_eval_total_finished_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10155  $total_passed = 0;
10156  $total_passed_reached = 0;
10157  $total_passed_max = 0;
10158  $total_passed_time = 0;
10159  foreach ($foundParticipants as $userdata)
10160  {
10161  if ($userdata->getPassed())
10162  {
10163  $total_passed++;
10164  $total_passed_reached += $userdata->getReached();
10165  $total_passed_max += $userdata->getMaxpoints();
10166  $total_passed_time += $userdata->getTimeOfWork();
10167  }
10168  }
10169  $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
10170  $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
10171  $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
10172  $results["overview"][$this->lng->txt("tst_eval_total_passed")] = $total_passed;
10173  $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);
10174  $average_time = $average_passed_time;
10175  $diff_seconds = $average_time;
10176  $diff_hours = floor($diff_seconds/3600);
10177  $diff_seconds -= $diff_hours * 3600;
10178  $diff_minutes = floor($diff_seconds/60);
10179  $diff_seconds -= $diff_minutes * 60;
10180  $results["overview"][$this->lng->txt("tst_eval_total_passed_average_time")] = sprintf("%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
10181  }
10182 
10183  foreach ($data->getQuestionTitles() as $question_id => $question_title)
10184  {
10185  $answered = 0;
10186  $reached = 0;
10187  $max = 0;
10188  foreach ($foundParticipants as $userdata)
10189  {
10190  for ($i = 0; $i <= $userdata->getLastPass(); $i++)
10191  {
10192  if (is_object($userdata->getPass($i)))
10193  {
10194  $question =& $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
10195  if (is_array($question))
10196  {
10197  $answered++;
10198  $reached += $question["reached"];
10199  $max += $question["points"];
10200  }
10201  }
10202  }
10203  }
10204  $percent = $max ? $reached/$max * 100.0 : 0;
10205  $counter++;
10206  $results["questions"][$question_id] = array(
10207  $question_title,
10208  sprintf("%.2f", $answered ? $reached / $answered : 0) . " " . strtolower($this->lng->txt("of")) . " " . sprintf("%.2f", $answered ? $max / $answered : 0),
10209  sprintf("%.2f", $percent) . "%",
10210  $answered,
10211  sprintf("%.2f", $answered ? $reached / $answered : 0),
10212  sprintf("%.2f", $answered ? $max / $answered : 0),
10213  $percent / 100.0
10214  );
10215  }
10216  return $results;
10217  }
10218 } // END class.ilObjTest
10219 
10220 ?>