ILIAS  Release_4_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assQuestion.php
Go to the documentation of this file.
1 <?php
2  /*
3  +----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2001 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 
24 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
25 
37 {
43  protected $id;
44 
50  protected $title;
51 
57  protected $comment;
58 
64  protected $owner;
65 
71  protected $author;
72 
78  protected $question;
79 
85  protected $points;
86 
92  protected $est_working_time;
93 
99  protected $shuffle;
100 
106  protected $test_id;
107 
113  protected $obj_id;
114 
120  protected $ilias;
121 
127  protected $tpl;
128 
134  protected $lng;
135 
141  protected $outputType;
142 
149 
155  protected $original_id;
156 
162  protected $page;
163 
167  private $nr_of_tries;
168 
172  private $arrData;
173 
184  function __construct(
185  $title = "",
186  $comment = "",
187  $author = "",
188  $owner = -1,
189  $question = ""
190  )
191  {
192  global $ilias;
193  global $lng;
194  global $tpl;
195 
196  $this->ilias =& $ilias;
197  $this->lng =& $lng;
198  $this->tpl =& $tpl;
199 
200  $this->original_id = null;
201  $this->title = $title;
202  $this->comment = $comment;
203  $this->page = null;
204  $this->author = $author;
205  $this->setQuestion($question);
206  if (!$this->author)
207  {
208  $this->author = $this->ilias->account->fullname;
209  }
210  $this->owner = $owner;
211  if ($this->owner <= 0)
212  {
213  $this->owner = $this->ilias->account->id;
214  }
215  $this->id = -1;
216  $this->test_id = -1;
217  $this->suggested_solutions = array();
218  $this->shuffle = 1;
219  $this->nr_of_tries = "";
220  $this->setEstimatedWorkingTime(0,1,0);
221  $this->outputType = OUTPUT_HTML;
222  $this->arrData = array();
223  }
224 
236  function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
237  {
238  include_once "./Modules/TestQuestionPool/classes/import/qti12/class." . $this->getQuestionType() . "Import.php";
239  $classname = $this->getQuestionType() . "Import";
240  $import = new $classname($this);
241  $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
242  }
243 
250  function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
251  {
252  include_once "./Modules/TestQuestionPool/classes/export/qti12/class." . $this->getQuestionType() . "Export.php";
253  $classname = $this->getQuestionType() . "Export";
254  $export = new $classname($this);
255  return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
256  }
257 
264  function isComplete()
265  {
266  return false;
267  }
268 
276  function questionTitleExists($questionpool_id, $title)
277  {
278  global $ilDB;
279 
280  $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE obj_fi = %s AND title = %s",
281  array('integer','text'),
282  array($questionpool_id, $title)
283  );
284  return ($result->numRows() == 1) ? TRUE : FALSE;
285  }
286 
294  function setTitle($title = "")
295  {
296  $this->title = $title;
297  }
298 
306  function setId($id = -1)
307  {
308  $this->id = $id;
309  }
310 
318  function setTestId($id = -1)
319  {
320  $this->test_id = $id;
321  }
322 
330  function setComment($comment = "")
331  {
332  $this->comment = $comment;
333  }
334 
343  {
344  $this->outputType = $outputType;
345  }
346 
347 
355  function setShuffle($shuffle = true)
356  {
357  if ($shuffle)
358  {
359  $this->shuffle = 1;
360  }
361  else
362  {
363  $this->shuffle = 0;
364  }
365  }
366 
376  function setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
377  {
378  $this->est_working_time = array("h" => (int)$hour, "m" => (int)$min, "s" => (int)$sec);
379  }
380 
388  function keyInArray($searchkey, $array)
389  {
390  if ($searchKey)
391  {
392  foreach ($array as $key => $value)
393  {
394  if (strcmp($key, $searchkey)==0)
395  {
396  return true;
397  }
398  }
399  }
400  return false;
401  }
402 
410  function setAuthor($author = "")
411  {
412  if (!$author)
413  {
414  $author = $this->ilias->account->fullname;
415  }
416  $this->author = $author;
417  }
418 
426  function setOwner($owner = "")
427  {
428  $this->owner = $owner;
429  }
430 
438  function getTitle()
439  {
440  return $this->title;
441  }
442 
450  function getId()
451  {
452  return $this->id;
453  }
454 
462  function getShuffle()
463  {
464  return $this->shuffle;
465  }
466 
474  function getTestId()
475  {
476  return $this->test_id;
477  }
478 
486  function getComment()
487  {
488  return $this->comment;
489  }
490 
498  function getOutputType()
499  {
500  return $this->outputType;
501  }
502 
510  {
511  return FALSE;
512  }
513 
522  {
523  if (!$this->est_working_time)
524  {
525  $this->est_working_time = array("h" => 0, "m" => 0, "s" => 0);
526  }
528  }
529 
537  function getAuthor()
538  {
539  return $this->author;
540  }
541 
549  function getOwner()
550  {
551  return $this->owner;
552  }
553 
561  function getObjId()
562  {
563  return $this->obj_id;
564  }
565 
573  function setObjId($obj_id = 0)
574  {
575  $this->obj_id = $obj_id;
576  }
577 
584  function _getMaximumPoints($question_id)
585  {
586  global $ilDB;
587 
588  $points = 0;
589  $result = $ilDB->queryF("SELECT points FROM qpl_questions WHERE question_id = %s",
590  array('integer'),
591  array($question_id)
592  );
593  if ($result->numRows() == 1)
594  {
595  $row = $ilDB->fetchAssoc($result);
596  $points = $row["points"];
597  }
598  return $points;
599  }
600 
607  function &_getQuestionInfo($question_id)
608  {
609  global $ilDB;
610 
611  $result = $ilDB->queryF("SELECT qpl_questions.*, qpl_qst_type.type_tag FROM qpl_qst_type, qpl_questions WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
612  array('integer'),
613  array($question_id)
614  );
615  if ($result->numRows())
616  {
617  return $ilDB->fetchAssoc($result);
618  }
619  else return array();
620  }
621 
628  public static function _getSuggestedSolutionCount($question_id)
629  {
630  global $ilDB;
631 
632  $result = $ilDB->queryF("SELECT suggested_solution_id FROM qpl_sol_sug WHERE question_fi = %s",
633  array('integer'),
634  array($question_id)
635  );
636  return $result->numRows();
637  }
638 
645  public static function _getSuggestedSolutionOutput($question_id)
646  {
648  if (!is_object($question)) return "";
649  return $question->getSuggestedSolutionOutput();
650  }
651 
652  public function getSuggestedSolutionOutput()
653  {
654  $output = array();
655  foreach ($this->suggested_solutions as $solution)
656  {
657  switch ($solution["type"])
658  {
659  case "lm":
660  case "st":
661  case "pg":
662  case "git":
663  array_push($output, '<a href="' . assQuestion::_getInternalLinkHref($solution["internal_link"]) . '">' . $this->lng->txt("solution_hint") . '</a>');
664  break;
665  case "file":
666  array_push($output, '<a href="' . $this->getSuggestedSolutionPathWeb() . $solution["value"]["name"] . '">' . ((strlen($solution["value"]["filenme"])) ? ilUtil::prepareFormOutput($solution["value"]["filenme"]) : $this->lng->txt("solution_hint")) . '</a>');
667  break;
668  case "text":
669  array_push($output, $this->prepareTextareaOutput($solution["value"]));
670  break;
671  }
672  }
673  return join($output, "<br />");
674  }
675 
684  function &_getSuggestedSolution($question_id, $subquestion_index = 0)
685  {
686  global $ilDB;
687 
688  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
689  array('integer','integer'),
690  array($question_id, $subquestion_index)
691  );
692  if ($result->numRows() == 1)
693  {
694  $row = $ilDB->fetchAssoc($result);
695  return array(
696  "internal_link" => $row["internal_link"],
697  "import_id" => $row["import_id"]
698  );
699  }
700  else
701  {
702  return array();
703  }
704  }
705 
711  public function getSuggestedSolutions()
712  {
714  }
715 
723  function _getReachedPoints($active_id, $question_id, $pass = NULL)
724  {
725  global $ilDB;
726 
727  $points = 0;
728  if (is_null($pass))
729  {
730  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
731  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
732  }
733  $result = $ilDB->queryF("SELECT * FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
734  array('integer','integer','integer'),
735  array($active_id, $question_id, $pass)
736  );
737  if ($result->numRows() == 1)
738  {
739  $row = $ilDB->fetchAssoc($result);
740  $points = $row["points"];
741  }
742  return $points;
743  }
744 
753  function getReachedPoints($active_id, $pass = NULL)
754  {
755  return round($this->_getReachedPoints($active_id, $this->getId(), $pass), 2);
756  }
757 
764  function getMaximumPoints()
765  {
766  return $this->points;
767  }
768 
775  public function calculateResultsFromSolution($active_id, $pass = NULL)
776  {
777  global $ilDB;
778  global $ilUser;
779  if (is_null($pass))
780  {
781  include_once "./Modules/Test/classes/class.ilObjTest.php";
782  $pass = ilObjTest::_getPass($active_id);
783  }
784  $reached_points = $this->calculateReachedPoints($active_id, $pass);
785  if (is_null($reached_points)) $reached_points = 0;
786 
787  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
788  array("integer", "integer", "integer"),
789  array(
790  $active_id,
791  $this->getId(),
792  $pass
793  )
794  );
795 
796  $next_id = $ilDB->nextId("tst_test_result");
797  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_test_result (test_result_id, active_fi, question_fi, pass, points, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
798  array("integer","integer", "integer", "integer", "float", "integer"),
799  array(
800  $next_id,
801  $active_id,
802  $this->getId(),
803  $pass,
804  $reached_points,
805  time()
806  )
807  );
808  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
810  {
811  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_user_answered_question", ilObjAssessmentFolder::_getLogLanguage()), $reached_points), $active_id, $this->getId());
812  }
813 
814  // update test pass results
815  $this->_updateTestPassResults($active_id, $pass);
816 
817  // Update objective status
818  include_once 'Modules/Course/classes/class.ilCourseObjectiveResult.php';
819  ilCourseObjectiveResult::_updateObjectiveResult($ilUser->getId(),$active_id,$this->getId());
820 
821  }
822 
829  function saveWorkingData($active_id, $pass = NULL)
830  {
831  $this->calculateResultsFromSolution($active_id, $pass);
832  }
833 
834  function _updateTestResultCache($active_id)
835  {
836  global $ilDB;
837 
838  include_once "./Modules/Test/classes/class.ilObjTest.php";
839  $pass = ilObjTest::_getResultPass($active_id);
840 
841  $result = $ilDB->queryF("SELECT tst_pass_result.* FROM tst_pass_result WHERE active_fi = %s AND pass = %s",
842  array('integer','integer'),
843  array($active_id, $pass)
844  );
845  $row = $ilDB->fetchAssoc($result);
846  $max = $row['maxpoints'];
847  $reached = $row['points'];
848  include_once "./Modules/Test/classes/class.assMarkSchema.php";
849  $percentage = (!$max) ? 0 : ($reached / $max) * 100.0;
850  $mark = ASS_MarkSchema::_getMatchingMarkFromActiveId($active_id, $percentage);
851  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_result_cache WHERE active_fi = %s",
852  array('integer'),
853  array($active_id)
854  );
855  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_result_cache (active_fi, pass, max_points, reached_points, mark_short, mark_official, passed, failed, tstamp) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)",
856  array(
857  'integer',
858  'integer',
859  'float',
860  'float',
861  'text',
862  'text',
863  'integer',
864  'integer',
865  'integer'
866  ),
867  array(
868  $active_id,
869  strlen($pass) ? $pass : 0,
870  strlen($max) ? $max : 0,
871  strlen($reached) ? $reached : 0,
872  strlen($mark["short_name"]) ? $mark["short_name"] : " ",
873  strlen($mark["official_name"]) ? $mark["official_name"] : " ",
874  ($mark["passed"]) ? 1 : 0,
875  (!$mark["passed"]) ? 1 : 0,
876  time()
877  )
878  );
879  }
880 
881  function _updateTestPassResults($active_id, $pass)
882  {
883  global $ilDB;
884  include_once "./Modules/Test/classes/class.ilObjTest.php";
887  // update test pass results
888  $result = $ilDB->queryF("SELECT SUM(points) reachedpoints, COUNT(question_fi) answeredquestions FROM tst_test_result WHERE active_fi = %s AND pass = %s",
889  array('integer','integer'),
890  array($active_id, $pass)
891  );
892  if ($result->numRows() > 0)
893  {
894  $row = $ilDB->fetchAssoc($result);
895  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_pass_result WHERE active_fi = %s AND pass = %s",
896  array('integer','integer'),
897  array($active_id, $pass)
898  );
899  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_pass_result (active_fi, pass, points, maxpoints, questioncount, answeredquestions, workingtime, tstamp) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)",
900  array(
901  'integer',
902  'integer',
903  'float',
904  'float',
905  'integer',
906  'integer',
907  'integer',
908  'integer'
909  ),
910  array(
911  $active_id,
912  strlen($pass) ? $pass : 0,
913  ($row["reachedpoints"]) ? $row["reachedpoints"] : 0,
914  $data["points"],
915  $data["count"],
916  $row["answeredquestions"],
917  $time,
918  time()
919  )
920  );
921  }
923  return array(
924  'active_fi' => $active_id,
925  'pass' => $pass,
926  'points' => ($row["reachedpoints"]) ? $row["reachedpoints"] : 0,
927  'maxpoints' => $data["points"],
928  'questioncount' => $data["count"],
929  'answeredquestions' => $row["answeredquestions"],
930  'workingtime' => $time,
931  'tstamp' => time()
932  );
933  }
934 
942  function logAction($logtext = "", $active_id = "", $question_id = "")
943  {
944  global $ilUser;
945 
946  $original_id = "";
947  if (strcmp($question_id, "") != 0)
948  {
949  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
951  }
952  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
953  include_once "./Modules/Test/classes/class.ilObjTest.php";
954  ilObjAssessmentFolder::_addLog($ilUser->id, ilObjTest::_getObjectIDFromActiveID($active_id), $logtext, $question_id, $original_id);
955  }
956 
964  function _logAction($logtext = "", $active_id = "", $question_id = "")
965  {
966  global $ilUser;
967 
968  $original_id = "";
969  if (strcmp($question_id, "") != 0)
970  {
971  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
973  }
974  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
975  include_once "./Modules/Test/classes/class.ilObjTest.php";
976  ilObjAssessmentFolder::_addLog($ilUser->id, ilObjTest::_getObjectIDFromActiveID($active_id), $logtext, $question_id, $original_id);
977  }
978 
987  {
988  $mediatempdir = CLIENT_WEB_DIR . "/assessment/temp";
989  if (!@is_dir($mediatempdir)) ilUtil::createDirectory($mediatempdir);
990  $temp_name = tempnam($mediatempdir, $name . "_____");
991  $temp_name = str_replace("\\", "/", $temp_name);
992  @unlink($temp_name);
993  if (!ilUtil::moveUploadedFile($file, $name, $temp_name))
994  {
995  return FALSE;
996  }
997  else
998  {
999  return $temp_name;
1000  }
1001  }
1002 
1009  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/solution/";
1010  }
1011 
1018  function getJavaPath() {
1019  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/java/";
1020  }
1021 
1028  function getImagePath()
1029  {
1030  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/images/";
1031  }
1032 
1039  function getFlashPath()
1040  {
1041  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/flash/";
1042  }
1043 
1050  function getJavaPathWeb()
1051  {
1052  include_once "./Services/Utilities/classes/class.ilUtil.php";
1053  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/java/";
1055  }
1056 
1063  {
1064  include_once "./Services/Utilities/classes/class.ilUtil.php";
1065  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/solution/";
1067  }
1068 
1075  function getImagePathWeb()
1076  {
1077  include_once "./Services/Utilities/classes/class.ilUtil.php";
1078  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/images/";
1080  }
1081 
1088  function getFlashPathWeb()
1089  {
1090  include_once "./Services/Utilities/classes/class.ilUtil.php";
1091  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/flash/";
1093  }
1094 
1102  function &getSolutionValues($active_id, $pass = NULL)
1103  {
1104  global $ilDB;
1105 
1106  $values = array();
1107 
1108  if (is_null($pass))
1109  {
1110  $pass = $this->getSolutionMaxPass($active_id);
1111  }
1112 
1113  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s ORDER BY solution_id",
1114  array('integer','integer','integer'),
1115  array($active_id, $this->getId(), $pass)
1116  );
1117  while ($row = $ilDB->fetchAssoc($result))
1118  {
1119  array_push($values, $row);
1120  }
1121 
1122  return $values;
1123  }
1124 
1131  function isInUse($question_id = "")
1132  {
1133  global $ilDB;
1134 
1135  if ($question_id < 1) $question_id = $this->getId();
1136  $result = $ilDB->queryF("SELECT COUNT(qpl_questions.question_id) question_count FROM qpl_questions, tst_test_question WHERE qpl_questions.original_id = %s AND qpl_questions.question_id = tst_test_question.question_fi",
1137  array('integer'),
1138  array($question_id)
1139  );
1140  $row = $ilDB->fetchAssoc($result);
1141  $count = $row["question_count"];
1142 
1143  $result = $ilDB->queryF("SELECT DISTINCT tst_active.test_fi, qpl_questions.question_id FROM qpl_questions, tst_test_rnd_qst, tst_active WHERE qpl_questions.original_id = %s AND qpl_questions.question_id = tst_test_rnd_qst.question_fi AND tst_test_rnd_qst.active_fi = tst_active.active_id",
1144  array('integer'),
1145  array($question_id)
1146  );
1147  $count += $result->numRows();
1148 
1149  return $count;
1150  }
1151 
1158  function isClone($question_id = "")
1159  {
1160  global $ilDB;
1161 
1162  if ($question_id < 1) $question_id = $this->id;
1163  $result = $ilDB->queryF("SELECT original_id FROM qpl_questions WHERE question_id = %s",
1164  array('integer'),
1165  array($question_id)
1166  );
1167  $row = $ilDB->fetchAssoc($result);
1168  return ($row["original_id"] > 0) ? TRUE : FALSE;
1169  }
1170 
1177  function pcArrayShuffle($array)
1178  {
1179  $keys = array_keys($array);
1180  shuffle($keys);
1181  $result = array();
1182  foreach ($keys as $key)
1183  {
1184  $result[$key] = $array[$key];
1185  }
1186  return $result;
1187  }
1188 
1194  function getQuestionTypeFromDb($question_id)
1195  {
1196  global $ilDB;
1197 
1198  $result = $ilDB->queryF("SELECT qpl_qst_type.type_tag FROM qpl_qst_type, qpl_questions WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
1199  array('integer'),
1200  array($question_id)
1201  );
1202  $data = $ilDB->fetchAssoc($result);
1203  return $data["type_tag"];
1204  }
1205 
1213  {
1214  return "";
1215  }
1216 
1224  {
1225  return "";
1226  }
1227 
1234  function deleteAnswers($question_id)
1235  {
1236  global $ilDB;
1237  $answer_table_name = $this->getAnswerTableName();
1238  if (is_array($answer_table_name))
1239  {
1240  foreach ($answer_table_name as $table)
1241  {
1242  if (strlen($table))
1243  {
1244  $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1245  array('integer'),
1246  array($question_id)
1247  );
1248  }
1249  }
1250  }
1251  else
1252  {
1253  if (strlen($answer_table_name))
1254  {
1255  $affectedRows = $ilDB->manipulateF("DELETE FROM $answer_table_name WHERE question_fi = %s",
1256  array('integer'),
1257  array($question_id)
1258  );
1259  }
1260  }
1261  }
1262 
1269  function deleteAdditionalTableData($question_id)
1270  {
1271  global $ilDB;
1272  $additional_table_name = $this->getAdditionalTableName();
1273  if (is_array($additional_table_name))
1274  {
1275  foreach ($additional_table_name as $table)
1276  {
1277  if (strlen($table))
1278  {
1279  $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1280  array('integer'),
1281  array($question_id)
1282  );
1283  }
1284  }
1285  }
1286  else
1287  {
1288  if (strlen($additional_table_name))
1289  {
1290  $affectedRows = $ilDB->manipulateF("DELETE FROM $additional_table_name WHERE question_fi = %s",
1291  array('integer'),
1292  array($question_id)
1293  );
1294  }
1295  }
1296  }
1297 
1304  protected function deletePageOfQuestion($question_id)
1305  {
1306  include_once "./Services/COPage/classes/class.ilPageObject.php";
1307  $page = new ilPageObject("qpl", $question_id);
1308  $page->delete();
1309  return true;
1310  }
1311 
1318  public function delete($question_id)
1319  {
1320  global $ilDB, $ilLog;
1321 
1322  if ($question_id < 1) return true; // nothing to do
1323 
1324  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1325  array('integer'),
1326  array($question_id)
1327  );
1328  if ($result->numRows() == 1)
1329  {
1330  $row = $ilDB->fetchAssoc($result);
1331  $obj_id = $row["obj_fi"];
1332  }
1333  else
1334  {
1335  return true; // nothing to do
1336  }
1337  try
1338  {
1339  $this->deletePageOfQuestion($question_id);
1340  }
1341  catch (Exception $e)
1342  {
1343  $ilLog->write("EXCEPTION: Could not delete page of question $question_id: $e");
1344  return false;
1345  }
1346 
1347  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_questions WHERE question_id = %s",
1348  array('integer'),
1349  array($question_id)
1350  );
1351  if ($affectedRows == 0) return false;
1352 
1353  try
1354  {
1355  $this->deleteAdditionalTableData($question_id);
1356  $this->deleteAnswers($question_id);
1357  }
1358  catch (Exception $e)
1359  {
1360  $ilLog->write("EXCEPTION: Could not delete additional table data of question $question_id: $e");
1361  return false;
1362  }
1363 
1364  try
1365  {
1366  // delete the question in the tst_test_question table (list of test questions)
1367  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_question WHERE question_fi = %s",
1368  array('integer'),
1369  array($question_id)
1370  );
1371  }
1372  catch (Exception $e)
1373  {
1374  $ilLog->write("EXCEPTION: Could not delete delete question $question_id from a test: $e");
1375  return false;
1376  }
1377 
1378  try
1379  {
1380  // delete suggested solutions contained in the question
1381  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
1382  array('integer'),
1383  array($question_id)
1384  );
1385  }
1386  catch (Exception $e)
1387  {
1388  $ilLog->write("EXCEPTION: Could not delete suggested solutions of question $question_id: $e");
1389  return false;
1390  }
1391 
1392  try
1393  {
1394  $directory = CLIENT_WEB_DIR . "/assessment/" . $obj_id . "/$question_id";
1395  if (preg_match("/\d+/", $obj_id) and preg_match("/\d+/", $question_id) and is_dir($directory))
1396  {
1397  include_once "./Services/Utilities/classes/class.ilUtil.php";
1398  ilUtil::delDir($directory);
1399  }
1400  }
1401  catch (Exception $e)
1402  {
1403  $ilLog->write("EXCEPTION: Could not delete question file directory $directory of question $question_id: $e");
1404  return false;
1405  }
1406 
1407  try
1408  {
1409  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1410  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $question_id);
1411  // remaining usages are not in text anymore -> delete them
1412  // and media objects (note: delete method of ilObjMediaObject
1413  // checks whether object is used in another context; if yes,
1414  // the object is not deleted!)
1415  foreach($mobs as $mob)
1416  {
1417  ilObjMediaObject::_removeUsage($mob, "qpl:html", $question_id);
1418  if (ilObjMediaObject::_exists($mob))
1419  {
1420  $mob_obj =& new ilObjMediaObject($mob);
1421  $mob_obj->delete();
1422  }
1423  }
1424  }
1425  catch (Exception $e)
1426  {
1427  $ilLog->write("EXCEPTION: Error deleting the media objects of question $question_id: $e");
1428  return false;
1429  }
1430 
1431  try
1432  {
1433  // update question count of question pool
1434  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1436  }
1437  catch (Exception $e)
1438  {
1439  $ilLog->write("EXCEPTION: Error updating the question pool question count of question pool " . $this->getObjId() . " when deleting question $question_id: $e");
1440  return false;
1441  }
1442  return true;
1443  }
1444 
1448  function getTotalAnswers()
1449  {
1450  return $this->_getTotalAnswers($this->id);
1451  }
1452 
1459  function _getTotalAnswers($a_q_id)
1460  {
1461  global $ilDB;
1462 
1463  // get all question references to the question id
1464  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
1465  array('integer','integer'),
1466  array($a_q_id, $a_q_id)
1467  );
1468  if ($result->numRows() == 0)
1469  {
1470  return 0;
1471  }
1472  $found_id = array();
1473  while ($row = $ilDB->fetchAssoc($result))
1474  {
1475  array_push($found_id, $row["question_id"]);
1476  }
1477 
1478  $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
1479 
1480  return $result->numRows();
1481  }
1482 
1483 
1490  function _getTotalRightAnswers($a_q_id)
1491  {
1492  global $ilDB;
1493  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
1494  array('integer','integer'),
1495  array($a_q_id, $a_q_id)
1496  );
1497  if ($result->numRows() == 0)
1498  {
1499  return 0;
1500  }
1501  $found_id = array();
1502  while ($row = $ilDB->fetchAssoc($result))
1503  {
1504  array_push($found_id, $row["question_id"]);
1505  }
1506  $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
1507  $answers = array();
1508  while ($row = $ilDB->fetchAssoc($result))
1509  {
1510  $reached = $row["points"];
1511  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1512  $max = assQuestion::_getMaximumPoints($row["question_fi"]);
1513  array_push($answers, array("reached" => $reached, "max" => $max));
1514  }
1515  $max = 0.0;
1516  $reached = 0.0;
1517  foreach ($answers as $key => $value)
1518  {
1519  $max += $value["max"];
1520  $reached += $value["reached"];
1521  }
1522  if ($max > 0)
1523  {
1524  return $reached / $max;
1525  }
1526  else
1527  {
1528  return 0;
1529  }
1530  }
1531 
1537  function _getTitle($a_q_id)
1538  {
1539  global $ilDB;
1540  $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE question_id = %s",
1541  array('integer'),
1542  array($a_q_id)
1543  );
1544  if ($result->numRows() == 1)
1545  {
1546  $row = $ilDB->fetchAssoc($result);
1547  return $row["title"];
1548  }
1549  else
1550  {
1551  return "";
1552  }
1553  }
1554 
1560  function _getQuestionText($a_q_id)
1561  {
1562  global $ilDB;
1563  $result = $ilDB->queryF("SELECT question_text FROM qpl_questions WHERE question_id = %s",
1564  array('integer'),
1565  array($a_q_id)
1566  );
1567  if ($result->numRows() == 1)
1568  {
1569  $row = $ilDB->fetchAssoc($result);
1570  return $row["question_text"];
1571  }
1572  else
1573  {
1574  return "";
1575  }
1576  }
1577 
1578 
1580  {
1581  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1582  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $a_q_id);
1583  foreach ($mobs as $mob)
1584  {
1585  ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->getId());
1586  }
1587  }
1588 
1590  {
1591  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1592  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1593  foreach ($mobs as $mob)
1594  {
1595  ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->original_id);
1596  }
1597  }
1598 
1602  function createPageObject()
1603  {
1604  $qpl_id = $this->getObjId();
1605 
1606  include_once "./Services/COPage/classes/class.ilPageObject.php";
1607  $this->page = new ilPageObject("qpl", 0);
1608  $this->page->setId($this->getId());
1609  $this->page->setParentId($qpl_id);
1610  $this->page->setXMLContent("<PageObject><PageContent>".
1611  "<Question QRef=\"il__qst_".$this->getId()."\"/>".
1612  "</PageContent></PageObject>");
1613  $this->page->create();
1614  }
1615 
1616  function copyPageOfQuestion($a_q_id)
1617  {
1618  if ($a_q_id > 0)
1619  {
1620  include_once "./Services/COPage/classes/class.ilPageObject.php";
1621  $page = new ilPageObject("qpl", $a_q_id);
1622 
1623  $xml = str_replace("il__qst_".$a_q_id, "il__qst_".$this->id, $page->getXMLContent());
1624  $this->page->setXMLContent($xml);
1625  $this->page->saveMobUsage($xml);
1626  $this->page->updateFromXML();
1627  }
1628  }
1629 
1631  {
1632  include_once "./Services/COPage/classes/class.ilPageObject.php";
1633  $page = new ilPageObject("qpl", $this->id);
1634  return $page->getXMLContent();
1635  }
1636 
1644  function _getQuestionType($question_id)
1645  {
1646  global $ilDB;
1647 
1648  if ($question_id < 1) return "";
1649  $result = $ilDB->queryF("SELECT type_tag FROM qpl_questions, qpl_qst_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
1650  array('integer'),
1651  array($question_id)
1652  );
1653  if ($result->numRows() == 1)
1654  {
1655  $data = $ilDB->fetchAssoc($result);
1656  return $data["type_tag"];
1657  }
1658  else
1659  {
1660  return "";
1661  }
1662  }
1663 
1671  function _getQuestionTitle($question_id)
1672  {
1673  global $ilDB;
1674 
1675  if ($question_id < 1) return "";
1676 
1677  $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE qpl_questions.question_id = %s",
1678  array('integer'),
1679  array($question_id)
1680  );
1681  if ($result->numRows() == 1)
1682  {
1683  $data = $ilDB->fetchAssoc($result);
1684  return $data["title"];
1685  }
1686  else
1687  {
1688  return "";
1689  }
1690  }
1691 
1693  {
1694  $this->original_id = $original_id;
1695  }
1696 
1697  function getOriginalId()
1698  {
1699  return $this->original_id;
1700  }
1701 
1708  function loadFromDb($question_id)
1709  {
1710  global $ilDB;
1711 
1712  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
1713  array('integer'),
1714  array($this->getId())
1715  );
1716  $this->suggested_solutions = array();
1717  if ($result->numRows())
1718  {
1719  include_once("./Services/RTE/classes/class.ilRTE.php");
1720  while ($row = $ilDB->fetchAssoc($result))
1721  {
1722  $value = (is_array(unserialize($row["value"]))) ? unserialize($row["value"]) : ilRTE::_replaceMediaObjectImageSrc($row["value"], 1);
1723  $this->suggested_solutions[$row["subquestion_index"]] = array(
1724  "type" => $row["type"],
1725  "value" => $value,
1726  "internal_link" => $row["internal_link"],
1727  "import_id" => $row["import_id"]
1728  );
1729  }
1730  }
1731  }
1732 
1739  public function createNewQuestion()
1740  {
1741  global $ilDB, $ilUser;
1742 
1743  $complete = "0";
1744  $estw_time = $this->getEstimatedWorkingTime();
1745  $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
1746  $obj_id = ($this->getObjId() <= 0) ? (ilObject::_lookupObjId((strlen($_GET["ref_id"])) ? $_GET["ref_id"] : $_POST["sel_qpl"])) : $this->getObjId();
1747  if ($obj_id > 0)
1748  {
1749  $next_id = $ilDB->nextId('qpl_questions');
1750  $affectedRows = $ilDB->insert("qpl_questions", array(
1751  "question_id" => array("integer", $next_id),
1752  "question_type_fi" => array("integer", $this->getQuestionTypeID()),
1753  "obj_fi" => array("integer", $obj_id),
1754  "title" => array("text", NULL),
1755  "description" => array("text", NULL),
1756  "author" => array("text", $this->getAuthor()),
1757  "owner" => array("integer", $ilUser->getId()),
1758  "question_text" => array("clob", NULL),
1759  "points" => array("float", 0),
1760  "nr_of_tries" => array("integer", 1),
1761  "working_time" => array("text", $estw_time),
1762  "complete" => array("text", $complete),
1763  "created" => array("integer", time()),
1764  "original_id" => array("integer", NULL),
1765  "tstamp" => array("integer", 0)
1766  ));
1767  $this->setId($next_id);
1768  // create page object of question
1769  $this->createPageObject();
1770  }
1771  return $this->getId();
1772  }
1773 
1774  public function saveQuestionDataToDb($original_id = "")
1775  {
1776  global $ilDB;
1777 
1778  $estw_time = $this->getEstimatedWorkingTime();
1779  $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
1780 
1781  // cleanup RTE images which are not inserted into the question text
1782  include_once("./Services/RTE/classes/class.ilRTE.php");
1783  if ($this->getId() == -1)
1784  {
1785  // Neuen Datensatz schreiben
1786  $next_id = $ilDB->nextId('qpl_questions');
1787  $affectedRows = $ilDB->insert("qpl_questions", array(
1788  "question_id" => array("integer", $next_id),
1789  "question_type_fi" => array("integer", $this->getQuestionTypeID()),
1790  "obj_fi" => array("integer", $this->getObjId()),
1791  "title" => array("text", $this->getTitle()),
1792  "description" => array("text", $this->getComment()),
1793  "author" => array("text", $this->getAuthor()),
1794  "owner" => array("integer", $this->getOwner()),
1795  "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
1796  "points" => array("float", $this->getMaximumPoints()),
1797  "working_time" => array("text", $estw_time),
1798  "nr_of_tries" => array("integer", (strlen($this->getNrOfTries())) ? $this->getNrOfTries() : 1),
1799  "created" => array("integer", time()),
1800  "original_id" => array("integer", ($original_id) ? $original_id : NULL),
1801  "tstamp" => array("integer", time())
1802  ));
1803  $this->setId($next_id);
1804  // create page object of question
1805  $this->createPageObject();
1806  }
1807  else
1808  {
1809  // Vorhandenen Datensatz aktualisieren
1810  $affectedRows = $ilDB->update("qpl_questions", array(
1811  "obj_fi" => array("integer", $this->getObjId()),
1812  "title" => array("text", $this->getTitle()),
1813  "description" => array("text", $this->getComment()),
1814  "author" => array("text", $this->getAuthor()),
1815  "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
1816  "points" => array("float", $this->getMaximumPoints()),
1817  "nr_of_tries" => array("integer", (strlen($this->getNrOfTries())) ? $this->getNrOfTries() : 1),
1818  "working_time" => array("text", $estw_time),
1819  "tstamp" => array("integer", time())
1820  ), array(
1821  "question_id" => array("integer", $this->getId())
1822  ));
1823  }
1824  }
1825 
1832  function saveToDb($original_id = "")
1833  {
1834  global $ilDB;
1835 
1836  $this->updateSuggestedSolutions();
1837 
1838  // remove unused media objects from ILIAS
1839  $this->cleanupMediaObjectUsage();
1840 
1841  $complete = "0";
1842  if ($this->isComplete())
1843  {
1844  $complete = "1";
1845  }
1846 
1847  // update the question time stamp and completion status
1848  $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET tstamp = %s, owner = %s, complete = %s WHERE question_id = %s",
1849  array('integer','integer', 'integer','text'),
1850  array(time(), ($this->getOwner() <= 0) ? $this->ilias->account->id : $this->getOwner(), $complete, $this->getId())
1851  );
1852 
1853  // update question count of question pool
1854  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1856  }
1857 
1861  protected function onDuplicate($source_question_id)
1862  {
1863  $this->duplicateSuggestedSolutionFiles($source_question_id);
1864  }
1865 
1869  protected function onCopy($source_questionpool_id, $source_question_id)
1870  {
1871  $this->copySuggestedSolutionFiles($source_questionpool_id, $source_question_id);
1872  }
1873 
1877  public function deleteSuggestedSolutions()
1878  {
1879  global $ilDB;
1880  // delete the links in the qpl_sol_sug table
1881  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
1882  array('integer'),
1883  array($this->getId())
1884  );
1885  // delete the links in the int_link table
1886  include_once "./Services/COPage/classes/class.ilInternalLink.php";
1888  $this->suggested_solutions = array();
1890  }
1891 
1899  function getSuggestedSolution($subquestion_index = 0)
1900  {
1901  if (array_key_exists($subquestion_index, $this->suggested_solutions))
1902  {
1903  return $this->suggested_solutions[$subquestion_index];
1904  }
1905  else
1906  {
1907  return array();
1908  }
1909  }
1910 
1919  function getSuggestedSolutionTitle($subquestion_index = 0)
1920  {
1921  if (array_key_exists($subquestion_index, $this->suggested_solutions))
1922  {
1923  $title = $this->suggested_solutions[$subquestion_index]["internal_link"];
1924  // TO DO: resolve internal link an get link type and title
1925  }
1926  else
1927  {
1928  $title = "";
1929  }
1930  return $title;
1931  }
1932 
1942  function setSuggestedSolution($solution_id = "", $subquestion_index = 0, $is_import = false)
1943  {
1944  if (strcmp($solution_id, "") != 0)
1945  {
1946  $import_id = "";
1947  if ($is_import)
1948  {
1949  $import_id = $solution_id;
1950  $solution_id = $this->_resolveInternalLink($import_id);
1951  }
1952  $this->suggested_solutions[$subquestion_index] = array(
1953  "internal_link" => $solution_id,
1954  "import_id" => $import_id
1955  );
1956  }
1957  }
1958 
1962  protected function duplicateSuggestedSolutionFiles($question_id)
1963  {
1964  global $ilLog;
1965 
1966  foreach ($this->suggested_solutions as $index => $solution)
1967  {
1968  if (strcmp($solution["type"], "file") == 0)
1969  {
1970  $filepath = $this->getSuggestedSolutionPath();
1971  $filepath_original = str_replace("/$this->id/solution", "/$question_id/solution", $filepath);
1972  if (!file_exists($filepath))
1973  {
1974  ilUtil::makeDirParents($filepath);
1975  }
1976  $filename = $solution["value"]["name"];
1977  if (strlen($filename))
1978  {
1979  if (!copy($filepath_original . $filename, $filepath . $filename))
1980  {
1981  $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
1982  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
1983  }
1984  }
1985  }
1986  }
1987  }
1988 
1993  {
1994  global $ilLog;
1995 
1996  $filepath = $this->getSuggestedSolutionPath();
1997  $filepath_original = str_replace("/$this->id/solution", "/$original_id/solution", $filepath);
1998  ilUtil::delDir($filepath_original);
1999  foreach ($this->suggested_solutions as $index => $solution)
2000  {
2001  if (strcmp($solution["type"], "file") == 0)
2002  {
2003  if (!file_exists($filepath_original))
2004  {
2005  ilUtil::makeDirParents($filepath_original);
2006  }
2007  $filename = $solution["value"]["name"];
2008  if (strlen($filename))
2009  {
2010  if (!@copy($filepath . $filename, $filepath_original . $filename))
2011  {
2012  $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
2013  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2014  }
2015  }
2016  }
2017  }
2018  }
2019 
2020  protected function copySuggestedSolutionFiles($source_questionpool_id, $source_question_id)
2021  {
2022  global $ilLog;
2023 
2024  foreach ($this->suggested_solutions as $index => $solution)
2025  {
2026  if (strcmp($solution["type"], "file") == 0)
2027  {
2028  $filepath = $this->getSuggestedSolutionPath();
2029  $filepath_original = str_replace("/$this->obj_id/$this->id/solution", "/$source_questionpool_id/$source_question_id/solution", $filepath);
2030  if (!file_exists($filepath))
2031  {
2032  ilUtil::makeDirParents($filepath);
2033  }
2034  $filename = $solution["value"]["name"];
2035  if (strlen($filename))
2036  {
2037  if (!copy($filepath_original . $filename, $filepath . $filename))
2038  {
2039  $ilLog->write("File could not be copied!!!!", $ilLog->ERROR);
2040  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2041  }
2042  }
2043  }
2044  }
2045  }
2046 
2051  {
2052  global $ilDB;
2053 
2054  $id = (strlen($original_id) && is_numeric($original_id)) ? $original_id : $this->getId();
2055  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2056  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
2057  array('integer'),
2058  array($id)
2059  );
2061  include_once("./Services/RTE/classes/class.ilRTE.php");
2062  foreach ($this->suggested_solutions as $index => $solution)
2063  {
2064  $next_id = $ilDB->nextId('qpl_sol_sug');
2065  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_sol_sug (suggested_solution_id, question_fi, type, value, internal_link, import_id, subquestion_index, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
2066  array("integer","integer", "text", "text", "text", "text", "integer","integer"),
2067  array(
2068  $next_id,
2069  $id,
2070  $solution["type"],
2071  ilRTE::_replaceMediaObjectImageSrc((is_array($solution["value"])) ? serialize($solution["value"]) : $solution["value"], 0),
2072  $solution["internal_link"],
2073  NULL,
2074  $index,
2075  time()
2076  )
2077  );
2078  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
2079  {
2080  ilInternalLink::_saveLink("qst", $id, $matches[2], $matches[3], $matches[1]);
2081  }
2082  }
2083  if (strlen($original_id) && is_numeric($original_id)) $this->syncSuggestedSolutionFiles($id);
2084  $this->cleanupMediaObjectUsage();
2085  }
2086 
2096  function saveSuggestedSolution($type, $solution_id = "", $subquestion_index = 0, $value = "")
2097  {
2098  global $ilDB;
2099 
2100  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
2101  array("integer", "integer"),
2102  array(
2103  $this->getId(),
2104  $subquestion_index
2105  )
2106  );
2107 
2108  $next_id = $ilDB->nextId('qpl_sol_sug');
2109  include_once("./Services/RTE/classes/class.ilRTE.php");
2110  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_sol_sug (suggested_solution_id, question_fi, type, value, internal_link, import_id, subquestion_index, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
2111  array("integer","integer", "text", "text", "text", "text", "integer","integer"),
2112  array(
2113  $next_id,
2114  $this->getId(),
2115  $type,
2116  ilRTE::_replaceMediaObjectImageSrc((is_array($value)) ? serialize($value) : $value, 0),
2117  $solution_id,
2118  NULL,
2119  $subquestion_index,
2120  time()
2121  )
2122  );
2123  if ($affectedRows == 1)
2124  {
2125  $this->suggested_solutions["subquestion_index"] = array(
2126  "type" => $type,
2127  "value" => $value,
2128  "internal_link" => $solution_id,
2129  "import_id" => ""
2130  );
2131  }
2132  $this->cleanupMediaObjectUsage();
2133  }
2134 
2135  function _resolveInternalLink($internal_link)
2136  {
2137  if (preg_match("/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches))
2138  {
2139  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2140  include_once "./Modules/LearningModule/classes/class.ilLMObject.php";
2141  include_once "./Modules/Glossary/classes/class.ilGlossaryTerm.php";
2142  switch ($matches[2])
2143  {
2144  case "lm":
2145  $resolved_link = ilLMObject::_getIdForImportId($internal_link);
2146  break;
2147  case "pg":
2148  $resolved_link = ilInternalLink::_getIdForImportId("PageObject", $internal_link);
2149  break;
2150  case "st":
2151  $resolved_link = ilInternalLink::_getIdForImportId("StructureObject", $internal_link);
2152  break;
2153  case "git":
2154  $resolved_link = ilInternalLink::_getIdForImportId("GlossaryItem", $internal_link);
2155  break;
2156  case "mob":
2157  $resolved_link = ilInternalLink::_getIdForImportId("MediaObject", $internal_link);
2158  break;
2159  }
2160  if (strcmp($resolved_link, "") == 0)
2161  {
2162  $resolved_link = $internal_link;
2163  }
2164  }
2165  else
2166  {
2167  $resolved_link = $internal_link;
2168  }
2169  return $resolved_link;
2170  }
2171 
2172  function _resolveIntLinks($question_id)
2173  {
2174  global $ilDB;
2175  $resolvedlinks = 0;
2176  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2177  array('integer'),
2178  array($question_id)
2179  );
2180  if ($result->numRows())
2181  {
2182  while ($row = $ilDB->fetchAssoc($result))
2183  {
2184  $internal_link = $row["internal_link"];
2185  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2186  $resolved_link = assQuestion::_resolveInternalLink($internal_link);
2187  if (strcmp($internal_link, $resolved_link) != 0)
2188  {
2189  // internal link was resolved successfully
2190  $affectedRows = $ilDB->manipulateF("UPDATE qpl_sol_sug SET internal_link = %s WHERE suggested_solution_id = %s",
2191  array('text','integer'),
2192  array($resolved_link, $row["suggested_solution_id"])
2193  );
2194  $resolvedlinks++;
2195  }
2196  }
2197  }
2198  if ($resolvedlinks)
2199  {
2200  // there are resolved links -> reenter theses links to the database
2201 
2202  // delete all internal links from the database
2203  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2204  ilInternalLink::_deleteAllLinksOfSource("qst", $question_id);
2205 
2206  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2207  array('integer'),
2208  array($question_id)
2209  );
2210  if ($result->numRows())
2211  {
2212  while ($row = $ilDB->fetchAssoc($result))
2213  {
2214  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $row["internal_link"], $matches))
2215  {
2216  ilInternalLink::_saveLink("qst", $question_id, $matches[2], $matches[3], $matches[1]);
2217  }
2218  }
2219  }
2220  }
2221  }
2222 
2223  function _getInternalLinkHref($target = "")
2224  {
2225  global $ilDB;
2226  $linktypes = array(
2227  "lm" => "LearningModule",
2228  "pg" => "PageObject",
2229  "st" => "StructureObject",
2230  "git" => "GlossaryItem",
2231  "mob" => "MediaObject"
2232  );
2233  $href = "";
2234  if (preg_match("/il__(\w+)_(\d+)/", $target, $matches))
2235  {
2236  $type = $matches[1];
2237  $target_id = $matches[2];
2238  include_once "./Services/Utilities/classes/class.ilUtil.php";
2239  switch($linktypes[$matches[1]])
2240  {
2241  case "LearningModule":
2242  $href = "./goto.php?target=" . $type . "_" . $target_id;
2243  break;
2244  case "PageObject":
2245  case "StructureObject":
2246  $href = "./goto.php?target=" . $type . "_" . $target_id;
2247  break;
2248  case "GlossaryItem":
2249  $href = "./goto.php?target=" . $type . "_" . $target_id;
2250  break;
2251  case "MediaObject":
2252  $href = "./ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[$type] . "&cmd=media&ref_id=".$_GET["ref_id"]."&mob_id=".$target_id;
2253  break;
2254  }
2255  }
2256  return $href;
2257  }
2258 
2266  function _getOriginalId($question_id)
2267  {
2268  global $ilDB;
2269  $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE question_id = %s",
2270  array('integer'),
2271  array($question_id)
2272  );
2273  if ($result->numRows() > 0)
2274  {
2275  $row = $ilDB->fetchAssoc($result);
2276  if ($row["original_id"] > 0)
2277  {
2278  return $row["original_id"];
2279  }
2280  else
2281  {
2282  return $row["question_id"];
2283  }
2284  }
2285  else
2286  {
2287  return "";
2288  }
2289  }
2290 
2291  function syncWithOriginal()
2292  {
2293  global $ilDB;
2294 
2295  if ($this->getOriginalId())
2296  {
2297  $id = $this->getId();
2298  $original = $this->getOriginalId();
2299 
2300  $this->setId($this->getOriginalId());
2301  $this->setOriginalId(NULL);
2302  $this->saveToDb();
2303  $this->deletePageOfQuestion($original);
2304  $this->createPageObject();
2305  $this->copyPageOfQuestion($id);
2306 
2307  $this->setId($id);
2308  $this->setOriginalId($original);
2309  $this->updateSuggestedSolutions($original);
2310  $this->syncFeedbackGeneric();
2312  }
2313  }
2314 
2315  function createRandomSolution($test_id, $user_id)
2316  {
2317  }
2318 
2326  function _questionExists($question_id)
2327  {
2328  global $ilDB;
2329 
2330  if ($question_id < 1)
2331  {
2332  return false;
2333  }
2334 
2335  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE question_id = %s",
2336  array('integer'),
2337  array($question_id)
2338  );
2339  if ($result->numRows() == 1)
2340  {
2341  return true;
2342  }
2343  else
2344  {
2345  return false;
2346  }
2347  }
2348 
2356  function &_instanciateQuestion($question_id)
2357  {
2358  if (strcmp($question_id, "") != 0)
2359  {
2360  $question_type = assQuestion::_getQuestionType($question_id);
2361  if (!strlen($question_type)) return null;
2362  assQuestion::_includeClass($question_type);
2363  $question = new $question_type();
2364  $question->loadFromDb($question_id);
2365  return $question;
2366  }
2367  }
2368 
2375  function getPoints()
2376  {
2377  if (strcmp($this->points, "") == 0)
2378  {
2379  return 0;
2380  }
2381  else
2382  {
2383  return $this->points;
2384  }
2385  }
2386 
2387 
2394  function setPoints($a_points)
2395  {
2396  $this->points = $a_points;
2397  }
2398 
2405  function getSolutionMaxPass($active_id)
2406  {
2407  return $this->_getSolutionMaxPass($this->getId(), $active_id);
2408  }
2409 
2416  function _getSolutionMaxPass($question_id, $active_id)
2417  {
2418 /* include_once "./Modules/Test/classes/class.ilObjTest.php";
2419  $pass = ilObjTest::_getPass($active_id);
2420  return $pass;*/
2421 
2422  // the following code was the old solution which added the non answered
2423  // questions of a pass from the answered questions of the previous pass
2424  // with the above solution, only the answered questions of the last pass are counted
2425  global $ilDB;
2426 
2427  $result = $ilDB->queryF("SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
2428  array('integer','integer'),
2429  array($active_id, $question_id)
2430  );
2431  if ($result->numRows() == 1)
2432  {
2433  $row = $ilDB->fetchAssoc($result);
2434  return $row["maxpass"];
2435  }
2436  else
2437  {
2438  return 0;
2439  }
2440  }
2441 
2450  function _isWriteable($question_id, $user_id)
2451  {
2452  global $ilDB;
2453 
2454  if (($question_id < 1) || ($user_id < 1))
2455  {
2456  return false;
2457  }
2458 
2459  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
2460  array('integer'),
2461  array($question_id)
2462  );
2463  if ($result->numRows() == 1)
2464  {
2465  $row = $ilDB->fetchAssoc($result);
2466  $qpl_object_id = $row["obj_fi"];
2467  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
2468  return ilObjQuestionPool::_isWriteable($qpl_object_id, $user_id);
2469  }
2470  else
2471  {
2472  return false;
2473  }
2474  }
2475 
2482  function _isUsedInRandomTest($question_id = "")
2483  {
2484  global $ilDB;
2485 
2486  if ($question_id < 1) return 0;
2487  $result = $ilDB->queryF("SELECT test_random_question_id FROM tst_test_rnd_qst WHERE question_fi = %s",
2488  array('integer'),
2489  array($question_id)
2490  );
2491  return $result->numRows();
2492  }
2493 
2503  function calculateReachedPoints($active_id, $pass = NULL, $points = 0)
2504  {
2505  include_once "./Modules/Test/classes/class.ilObjTest.php";
2506  $count_system = ilObjTest::_getCountSystem($active_id);
2507  if ($count_system == 1)
2508  {
2509  if ($points != $this->getMaximumPoints())
2510  {
2511  $points = 0;
2512  }
2513  }
2514  $score_cutting = ilObjTest::_getScoreCutting($active_id);
2515  if ($score_cutting == 0)
2516  {
2517  if ($points < 0)
2518  {
2519  $points = 0;
2520  }
2521  }
2522  return $points;
2523  }
2524 
2533  public static function _isWorkedThrough($active_id, $question_id, $pass = NULL)
2534  {
2535  global $ilDB;
2536 
2537  $points = 0;
2538  if (is_null($pass))
2539  {
2540  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2541  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
2542  }
2543  $result = $ilDB->queryF("SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
2544  array('integer','integer','integer'),
2545  array($active_id, $question_id, $pass)
2546  );
2547  if ($result->numRows())
2548  {
2549  return TRUE;
2550  }
2551  else
2552  {
2553  return FALSE;
2554  }
2555  }
2556 
2564  public static function _areAnswered($a_user_id,$a_question_ids)
2565  {
2566  global $ilDB;
2567 
2568  $res = $ilDB->queryF("SELECT DISTINCT(question_fi) FROM tst_test_result JOIN tst_active ".
2569  "ON (active_id = active_fi) ".
2570  "WHERE " . $ilDB->in('question_fi', $a_question_ids, false, 'integer') .
2571  " AND user_fi = %s",
2572  array('integer'),
2573  array($a_user_id)
2574  );
2575  return ($res->numRows() == count($a_question_ids)) ? true : false;
2576  }
2577 
2585  function isHTML($a_text)
2586  {
2587  if (preg_match("/<[^>]*?>/", $a_text))
2588  {
2589  return TRUE;
2590  }
2591  else
2592  {
2593  return FALSE;
2594  }
2595  }
2596 
2603  function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE)
2604  {
2605  include_once "./Services/Utilities/classes/class.ilUtil.php";
2606  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output);
2607  }
2608 
2616  function QTIMaterialToString($a_material)
2617  {
2618  $result = "";
2619  for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
2620  {
2621  $material = $a_material->getMaterial($i);
2622  if (strcmp($material["type"], "mattext") == 0)
2623  {
2624  $result .= $material["material"]->getContent();
2625  }
2626  if (strcmp($material["type"], "matimage") == 0)
2627  {
2628  $matimage = $material["material"];
2629  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
2630  {
2631  // import an mediaobject which was inserted using tiny mce
2632  if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
2633  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
2634  }
2635  }
2636  }
2637  return $result;
2638  }
2639 
2648  function addQTIMaterial(&$a_xml_writer, $a_material, $close_material_tag = TRUE, $add_mobs = TRUE)
2649  {
2650  include_once "./Services/RTE/classes/class.ilRTE.php";
2651  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
2652 
2653  $a_xml_writer->xmlStartTag("material");
2654  $attrs = array(
2655  "texttype" => "text/plain"
2656  );
2657  if ($this->isHTML($a_material))
2658  {
2659  $attrs["texttype"] = "text/xhtml";
2660  }
2661  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
2662  if ($add_mobs)
2663  {
2664  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
2665  foreach ($mobs as $mob)
2666  {
2667  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
2668  if (strpos($a_material, "mm_$mob") !== FALSE)
2669  {
2670  if (ilObjMediaObject::_exists($mob))
2671  {
2672  $mob_obj =& new ilObjMediaObject($mob);
2673  $imgattrs = array(
2674  "label" => $moblabel,
2675  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
2676  );
2677  }
2678  $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
2679  }
2680  }
2681  }
2682  if ($close_material_tag) $a_xml_writer->xmlEndTag("material");
2683  }
2684 
2685  function createNewImageFileName($image_filename)
2686  {
2687  $extension = "";
2688  if (preg_match("/.*\.(png|jpg|gif|jpeg)$/i", $image_filename, $matches))
2689  {
2690  $extension = "." . $matches[1];
2691  }
2692  $image_filename = md5($image_filename) . $extension;
2693  return $image_filename;
2694  }
2695 
2706  function _setReachedPoints($active_id, $question_id, $points, $maxpoints, $pass = NULL, $manualscoring = FALSE)
2707  {
2708  global $ilDB;
2709 
2710  if ($points <= $maxpoints)
2711  {
2712  if (is_null($pass))
2713  {
2714  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
2715  }
2716 
2717  // retrieve the already given points
2718  $old_points = 0;
2719  $result = $ilDB->queryF("SELECT points FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
2720  array('integer','integer','integer'),
2721  array($active_id, $question_id, $pass)
2722  );
2723  $manual = ($manualscoring) ? 1 : 0;
2724  if ($result->numRows())
2725  {
2726  $row = $ilDB->fetchAssoc($result);
2727  $old_points = $row["points"];
2728  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_result SET points = %s, manual = %s, tstamp = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
2729  array('float', 'integer', 'integer', 'integer', 'integer', 'integer'),
2730  array($points, $manual, time(), $active_id, $question_id, $pass)
2731  );
2732  }
2733  else
2734  {
2735  $next_id = $ilDB->nextId('tst_test_result');
2736  $affectedRows = $ilDB->manipulateF("INSERT INTO tst_test_result (test_result_id, active_fi, question_fi, points, pass, manual, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s)",
2737  array('integer', 'integer','integer', 'float', 'integer', 'integer','integer'),
2738  array($next_id, $active_id, $question_id, $points, $pass, $manual, time())
2739  );
2740  }
2742  // finally update objective result
2743  include_once "./Modules/Test/classes/class.ilObjTest.php";
2744  include_once './Modules/Course/classes/class.ilCourseObjectiveResult.php';
2746 
2747  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
2749  {
2750  global $lng, $ilUser;
2751  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
2752  $username = ilObjTestAccess::_getParticipantData($active_id);
2753  assQuestion::_logAction(sprintf($lng->txtlng("assessment", "log_answer_changed_points", ilObjAssessmentFolder::_getLogLanguage()), $username, $old_points, $points, $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")"), $active_id, $question_id);
2754  }
2755 
2756  return TRUE;
2757  }
2758  else
2759  {
2760  return FALSE;
2761  }
2762  }
2763 
2771  function getQuestion()
2772  {
2773  return $this->question;
2774  }
2775 
2783  function setQuestion($question = "")
2784  {
2785  $this->question = $question;
2786  }
2787 
2794  function getQuestionType()
2795  {
2796  // must be overwritten in every parent class
2797  return "";
2798  }
2799 
2809  {
2810  global $ilDB;
2811 
2812  $result = $ilDB->queryF("SELECT question_type_id FROM qpl_qst_type WHERE type_tag = %s",
2813  array('text'),
2814  array($this->getQuestionType())
2815  );
2816  if ($result->numRows() == 1)
2817  {
2818  $row = $ilDB->fetchAssoc($result);
2819  return $row["question_type_id"];
2820  }
2821  return 0;
2822  }
2823 
2833  function saveFeedbackGeneric($correctness, $feedback)
2834  {
2835  global $ilDB;
2836 
2837  switch ($correctness)
2838  {
2839  case 0:
2840  $correctness = 0;
2841  break;
2842  case 1:
2843  default:
2844  $correctness = 1;
2845  break;
2846  }
2847  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_generic WHERE question_fi = %s AND correctness = %s",
2848  array('integer', 'text'),
2849  array($this->getId(), $correctness)
2850  );
2851  if (strlen($feedback))
2852  {
2853  include_once("./Services/RTE/classes/class.ilRTE.php");
2854  $next_id = $ilDB->nextId('qpl_fb_generic');
2855  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_generic (feedback_id, question_fi, correctness, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
2856  array('integer','integer','text','text','integer'),
2857  array($next_id, $this->getId(), $correctness, ilRTE::_replaceMediaObjectImageSrc($feedback, 0), time())
2858  );
2859  }
2860  }
2861 
2871  function getFeedbackGeneric($correctness)
2872  {
2873  global $ilDB;
2874 
2875  $feedback = "";
2876  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s AND correctness = %s",
2877  array('integer', 'text'),
2878  array($this->getId(), $correctness)
2879  );
2880  if ($result->numRows())
2881  {
2882  $row = $ilDB->fetchAssoc($result);
2883  include_once("./Services/RTE/classes/class.ilRTE.php");
2884  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
2885  }
2886  return $feedback;
2887  }
2888 
2896  {
2897  global $ilDB;
2898 
2899  $feedback = "";
2900  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s",
2901  array('integer'),
2902  array($original_id)
2903  );
2904  if ($result->numRows())
2905  {
2906  while ($row = $ilDB->fetchAssoc($result))
2907  {
2908  $next_id = $ilDB->nextId('qpl_fb_generic');
2909  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_generic (feedback_id, question_fi, correctness, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
2910  array('integer','integer','text','text','integer'),
2911  array($next_id, $this->getId(), $row["correctness"], $row["feedback"], time())
2912  );
2913  }
2914  }
2915  }
2916 
2918  {
2919  global $ilDB;
2920 
2921  $feedback = "";
2922 
2923  // delete generic feedback of the original
2924  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_generic WHERE question_fi = %s",
2925  array('integer'),
2926  array($this->original_id)
2927  );
2928 
2929  // get generic feedback of the actual question
2930  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s",
2931  array('integer'),
2932  array($this->getId())
2933  );
2934 
2935  // save generic feedback to the original
2936  if ($result->numRows())
2937  {
2938  while ($row = $ilDB->fetchAssoc($result))
2939  {
2940  $next_id = $ilDB->nextId('qpl_fb_generic');
2941  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_generic (feedback_id, question_fi, correctness, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
2942  array('integer','integer','text','text','integer'),
2943  array($next_id, $this->original_id, $row["correctness"], $row["feedback"], time())
2944  );
2945  }
2946  }
2947  }
2948 
2954  {
2955  // must be called in parent classes. add additional RTE text in the parent
2956  // classes and call this method to add the standard RTE text
2957  $collected = $this->getQuestion();
2958  $collected .= $this->getFeedbackGeneric(0);
2959  $collected .= $this->getFeedbackGeneric(1);
2960  foreach ($this->suggested_solutions as $solution_array)
2961  {
2962  $collected .= $solution_array["value"];
2963  }
2964  return $collected;
2965  }
2966 
2972  {
2973  $combinedtext = $this->getRTETextWithMediaObjects();
2974  include_once("./Services/RTE/classes/class.ilRTE.php");
2975  ilRTE::_cleanupMediaObjectUsage($combinedtext, "qpl:html", $this->getId());
2976  }
2977 
2983  function &getInstances()
2984  {
2985  global $ilDB;
2986 
2987  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s",
2988  array("integer"),
2989  array($this->getId())
2990  );
2991  $instances = array();
2992  $ids = array();
2993  while ($row = $ilDB->fetchAssoc($result))
2994  {
2995  array_push($ids, $row["question_id"]);
2996  }
2997  foreach ($ids as $question_id)
2998  {
2999  // check non random tests
3000  $result = $ilDB->queryF("SELECT tst_tests.obj_fi FROM tst_tests, tst_test_question WHERE tst_test_question.question_fi = %s AND tst_test_question.test_fi = tst_tests.test_id",
3001  array("integer"),
3002  array($question_id)
3003  );
3004  while ($row = $ilDB->fetchAssoc($result))
3005  {
3006  $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3007  }
3008  // check random tests
3009  $result = $ilDB->queryF("SELECT tst_tests.obj_fi FROM tst_tests, tst_test_rnd_qst, tst_active WHERE tst_test_rnd_qst.active_fi = tst_active.active_id AND tst_test_rnd_qst.question_fi = %s AND tst_tests.test_id = tst_active.test_fi",
3010  array("integer"),
3011  array($question_id)
3012  );
3013  while ($row = $ilDB->fetchAssoc($result))
3014  {
3015  $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3016  }
3017  }
3018  include_once "./Modules/Test/classes/class.ilObjTest.php";
3019  foreach ($instances as $key => $value)
3020  {
3021  $instances[$key] = array("obj_id" => $key, "title" => $value, "author" => ilObjTest::_lookupAuthor($key), "refs" => ilObject::_getAllReferences($key));
3022  }
3023  return $instances;
3024  }
3025 
3026  function _needsManualScoring($question_id)
3027  {
3028  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
3030  $questiontype = assQuestion::_getQuestionType($question_id);
3031  if (in_array($questiontype, $scoring))
3032  {
3033  return TRUE;
3034  }
3035  else
3036  {
3037  return FALSE;
3038  }
3039  }
3040 
3048  function getActiveUserData($active_id)
3049  {
3050  global $ilDB;
3051  $result = $ilDB->queryF("SELECT * FROM tst_active WHERE active_id = %s",
3052  array('integer'),
3053  array($active_id)
3054  );
3055  if ($result->numRows())
3056  {
3057  $row = $ilDB->fetchAssoc($result);
3058  return array("user_id" => $row["user_fi"], "test_id" => $row["test_fi"]);
3059  }
3060  else
3061  {
3062  return array();
3063  }
3064  }
3065 
3073  static function _includeClass($question_type, $gui = 0)
3074  {
3075  $type = $question_type;
3076  if ($gui) $type .= "GUI";
3077  if (file_exists("./Modules/TestQuestionPool/classes/class.".$type.".php"))
3078  {
3079  include_once "./Modules/TestQuestionPool/classes/class.".$type.".php";
3080  }
3081  else
3082  {
3083  global $ilPluginAdmin;
3084  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3085  foreach ($pl_names as $pl_name)
3086  {
3087  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3088  if (strcmp($pl->getQuestionType(), $question_type) == 0)
3089  {
3090  $pl->includeClass("class.".$type.".php");
3091  }
3092  }
3093  }
3094  }
3095 
3102  static function _getQuestionTypeName($type_tag)
3103  {
3104  if (file_exists("./Modules/TestQuestionPool/classes/class.".$type_tag.".php"))
3105  {
3106  global $lng;
3107  return $lng->txt($type_tag);
3108  }
3109  else
3110  {
3111  global $ilPluginAdmin;
3112  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3113  foreach ($pl_names as $pl_name)
3114  {
3115  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3116  if (strcmp($pl->getQuestionType(), $type_tag) == 0)
3117  {
3118  return $pl->getQuestionTypeTranslation();
3119  }
3120  }
3121  }
3122  return "";
3123  }
3124 
3132  function &_instanciateQuestionGUI($question_id)
3133  {
3134  if (strcmp($question_id, "") != 0)
3135  {
3136  $question_type = assQuestion::_getQuestionType($question_id);
3137  $question_type_gui = $question_type . "GUI";
3138  assQuestion::_includeClass($question_type, 1);
3139  $question_gui = new $question_type_gui();
3140  $question_gui->object->loadFromDb($question_id);
3141  return $question_gui;
3142  }
3143  }
3144 
3157  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
3158  {
3159  return $startrow;
3160  }
3161 
3165  public function __get($value)
3166  {
3167  switch ($value)
3168  {
3169  case "id":
3170  return $this->getId();
3171  break;
3172  case "title":
3173  return $this->getTitle();
3174  break;
3175  case "comment":
3176  return $this->getComment();
3177  break;
3178  case "owner":
3179  return $this->getOwner();
3180  break;
3181  case "author":
3182  return $this->getAuthor();
3183  break;
3184  case "question":
3185  return $this->getQuestion();
3186  break;
3187  case "points":
3188  return $this->getPoints();
3189  break;
3190  case "est_working_time":
3191  return $this->getEstimatedWorkingTime();
3192  break;
3193  case "shuffle":
3194  return $this->getShuffle();
3195  break;
3196  case "test_id":
3197  return $this->getTestId();
3198  break;
3199  case "obj_id":
3200  return $this->getObjId();
3201  break;
3202  case "ilias":
3203  return $this->ilias;
3204  break;
3205  case "tpl":
3206  return $this->tpl;
3207  break;
3208  case "page":
3209  return $this->page;
3210  break;
3211  case "outputType":
3212  return $this->getOutputType();
3213  break;
3214  case "suggested_solutions":
3215  return $this->getSuggestedSolutions();
3216  break;
3217  case "original_id":
3218  return $this->getOriginalId();
3219  break;
3220  default:
3221  if (array_key_exists($value, $this->arrData))
3222  {
3223  return $this->arrData[$value];
3224  }
3225  else
3226  {
3227  return null;
3228  }
3229  break;
3230  }
3231  }
3232 
3236  public function __set($key, $value)
3237  {
3238  switch ($key)
3239  {
3240  case "id":
3241  $this->setId($value);
3242  break;
3243  case "title":
3244  $this->setTitle($value);
3245  break;
3246  case "comment":
3247  $this->setComment($value);
3248  break;
3249  case "owner":
3250  $this->setOwner($value);
3251  break;
3252  case "author":
3253  $this->setAuthor($value);
3254  break;
3255  case "question":
3256  $this->setQuestion($value);
3257  break;
3258  case "points":
3259  $this->setPoints($value);
3260  break;
3261  case "est_working_time":
3262  if (is_array($value))
3263  {
3264  $this->setEstimatedWorkingTime($value["h"], $value["m"], $value["s"]);
3265  }
3266  break;
3267  case "shuffle":
3268  $this->setShuffle($value);
3269  break;
3270  case "test_id":
3271  $this->setTestId($value);
3272  break;
3273  case "obj_id":
3274  $this->setObjId($value);
3275  break;
3276  case "outputType":
3277  $this->setOutputType($value);
3278  break;
3279  case "original_id":
3280  $this->setOriginalId($value);
3281  break;
3282  case "page":
3283  $this->page =& $value;
3284  break;
3285  default:
3286  $this->arrData[$key] = $value;
3287  break;
3288  }
3289  }
3290 
3291  public function getNrOfTries()
3292  {
3293  return $this->nr_of_tries;
3294  }
3295 
3296  public function setNrOfTries($a_nr_of_tries)
3297  {
3298  $this->nr_of_tries = $a_nr_of_tries;
3299  }
3300 }
3301 
3302 ?>