ILIAS  eassessment Revision 61809
 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 
174  private $external_id;
175 
186  function __construct(
187  $title = "",
188  $comment = "",
189  $author = "",
190  $owner = -1,
191  $question = ""
192  )
193  {
194  global $ilias;
195  global $lng;
196  global $tpl;
197 
198  $this->ilias =& $ilias;
199  $this->lng =& $lng;
200  $this->tpl =& $tpl;
201 
202  $this->original_id = null;
203  $this->title = $title;
204  $this->comment = $comment;
205  $this->page = null;
206  $this->author = $author;
207  $this->setQuestion($question);
208  if (!$this->author)
209  {
210  $this->author = $this->ilias->account->fullname;
211  }
212  $this->owner = $owner;
213  if ($this->owner <= 0)
214  {
215  $this->owner = $this->ilias->account->id;
216  }
217  $this->id = -1;
218  $this->test_id = -1;
219  $this->suggested_solutions = array();
220  $this->shuffle = 1;
221  $this->external_id = '';
222  $this->nr_of_tries = "";
223  $this->setEstimatedWorkingTime(0,1,0);
224  $this->outputType = OUTPUT_HTML;
225  $this->arrData = array();
226  }
227 
239  function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
240  {
241  include_once "./Modules/TestQuestionPool/classes/import/qti12/class." . $this->getQuestionType() . "Import.php";
242  $classname = $this->getQuestionType() . "Import";
243  $import = new $classname($this);
244  $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
245  }
246 
253  function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
254  {
255  include_once "./Modules/TestQuestionPool/classes/export/qti12/class." . $this->getQuestionType() . "Export.php";
256  $classname = $this->getQuestionType() . "Export";
257  $export = new $classname($this);
258  return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
259  }
260 
267  function isComplete()
268  {
269  return false;
270  }
271 
279  function questionTitleExists($questionpool_id, $title)
280  {
281  global $ilDB;
282 
283  $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE obj_fi = %s AND title = %s",
284  array('integer','text'),
285  array($questionpool_id, $title)
286  );
287  return ($result->numRows() == 1) ? TRUE : FALSE;
288  }
289 
297  function setTitle($title = "")
298  {
299  $this->title = $title;
300  }
301 
309  function setId($id = -1)
310  {
311  $this->id = $id;
312  }
313 
321  function setTestId($id = -1)
322  {
323  $this->test_id = $id;
324  }
325 
333  function setComment($comment = "")
334  {
335  $this->comment = $comment;
336  }
337 
346  {
347  $this->outputType = $outputType;
348  }
349 
350 
358  function setShuffle($shuffle = true)
359  {
360  if ($shuffle)
361  {
362  $this->shuffle = 1;
363  }
364  else
365  {
366  $this->shuffle = 0;
367  }
368  }
369 
379  function setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
380  {
381  $this->est_working_time = array("h" => (int)$hour, "m" => (int)$min, "s" => (int)$sec);
382  }
383 
391  function keyInArray($searchkey, $array)
392  {
393  if ($searchKey)
394  {
395  foreach ($array as $key => $value)
396  {
397  if (strcmp($key, $searchkey)==0)
398  {
399  return true;
400  }
401  }
402  }
403  return false;
404  }
405 
413  function setAuthor($author = "")
414  {
415  if (!$author)
416  {
417  $author = $this->ilias->account->fullname;
418  }
419  $this->author = $author;
420  }
421 
429  function setOwner($owner = "")
430  {
431  $this->owner = $owner;
432  }
433 
441  function getTitle()
442  {
443  return $this->title;
444  }
445 
453  function getId()
454  {
455  return $this->id;
456  }
457 
465  function getShuffle()
466  {
467  return $this->shuffle;
468  }
469 
477  function getTestId()
478  {
479  return $this->test_id;
480  }
481 
489  function getComment()
490  {
491  return $this->comment;
492  }
493 
501  function getOutputType()
502  {
503  return $this->outputType;
504  }
505 
513  {
514  return FALSE;
515  }
516 
525  {
526  if (!$this->est_working_time)
527  {
528  $this->est_working_time = array("h" => 0, "m" => 0, "s" => 0);
529  }
531  }
532 
540  function getAuthor()
541  {
542  return $this->author;
543  }
544 
552  function getOwner()
553  {
554  return $this->owner;
555  }
556 
564  function getObjId()
565  {
566  return $this->obj_id;
567  }
568 
576  function setObjId($obj_id = 0)
577  {
578  $this->obj_id = $obj_id;
579  }
580 
587  function _getMaximumPoints($question_id)
588  {
589  global $ilDB;
590 
591  $points = 0;
592  $result = $ilDB->queryF("SELECT points FROM qpl_questions WHERE question_id = %s",
593  array('integer'),
594  array($question_id)
595  );
596  if ($result->numRows() == 1)
597  {
598  $row = $ilDB->fetchAssoc($result);
599  $points = $row["points"];
600  }
601  return $points;
602  }
603 
610  function &_getQuestionInfo($question_id)
611  {
612  global $ilDB;
613 
614  $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",
615  array('integer'),
616  array($question_id)
617  );
618  if ($result->numRows())
619  {
620  return $ilDB->fetchAssoc($result);
621  }
622  else return array();
623  }
624 
631  public static function _getSuggestedSolutionCount($question_id)
632  {
633  global $ilDB;
634 
635  $result = $ilDB->queryF("SELECT suggested_solution_id FROM qpl_sol_sug WHERE question_fi = %s",
636  array('integer'),
637  array($question_id)
638  );
639  return $result->numRows();
640  }
641 
648  public static function _getSuggestedSolutionOutput($question_id)
649  {
651  if (!is_object($question)) return "";
652  return $question->getSuggestedSolutionOutput();
653  }
654 
655  public function getSuggestedSolutionOutput()
656  {
657  $output = array();
658  foreach ($this->suggested_solutions as $solution)
659  {
660  switch ($solution["type"])
661  {
662  case "lm":
663  case "st":
664  case "pg":
665  case "git":
666  array_push($output, '<a href="' . assQuestion::_getInternalLinkHref($solution["internal_link"]) . '">' . $this->lng->txt("solution_hint") . '</a>');
667  break;
668  case "file":
669  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>');
670  break;
671  case "text":
672  array_push($output, $this->prepareTextareaOutput($solution["value"]));
673  break;
674  }
675  }
676  return join($output, "<br />");
677  }
678 
687  function &_getSuggestedSolution($question_id, $subquestion_index = 0)
688  {
689  global $ilDB;
690 
691  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
692  array('integer','integer'),
693  array($question_id, $subquestion_index)
694  );
695  if ($result->numRows() == 1)
696  {
697  $row = $ilDB->fetchAssoc($result);
698  return array(
699  "internal_link" => $row["internal_link"],
700  "import_id" => $row["import_id"]
701  );
702  }
703  else
704  {
705  return array();
706  }
707  }
708 
714  public function getSuggestedSolutions()
715  {
717  }
718 
726  function _getReachedPoints($active_id, $question_id, $pass = NULL)
727  {
728  global $ilDB;
729 
730  $points = 0;
731  if (is_null($pass))
732  {
733  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
734  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
735  }
736  $result = $ilDB->queryF("SELECT * FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
737  array('integer','integer','integer'),
738  array($active_id, $question_id, $pass)
739  );
740  if ($result->numRows() == 1)
741  {
742  $row = $ilDB->fetchAssoc($result);
743  $points = $row["points"];
744  }
745  return $points;
746  }
747 
756  function getReachedPoints($active_id, $pass = NULL)
757  {
758  return round($this->_getReachedPoints($active_id, $this->getId(), $pass), 2);
759  }
760 
767  function getMaximumPoints()
768  {
769  return $this->points;
770  }
771 
778  public function calculateResultsFromSolution($active_id, $pass = NULL)
779  {
780  global $ilDB;
781  global $ilUser;
782  if (is_null($pass))
783  {
784  include_once "./Modules/Test/classes/class.ilObjTest.php";
785  $pass = ilObjTest::_getPass($active_id);
786  }
787  $reached_points = $this->calculateReachedPoints($active_id, $pass);
788  if (is_null($reached_points)) $reached_points = 0;
789 
790  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
791  array("integer", "integer", "integer"),
792  array(
793  $active_id,
794  $this->getId(),
795  $pass
796  )
797  );
798 
799  $next_id = $ilDB->nextId("tst_test_result");
800  $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)",
801  array("integer","integer", "integer", "integer", "float", "integer"),
802  array(
803  $next_id,
804  $active_id,
805  $this->getId(),
806  $pass,
807  $reached_points,
808  time()
809  )
810  );
811  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
813  {
814  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_user_answered_question", ilObjAssessmentFolder::_getLogLanguage()), $reached_points), $active_id, $this->getId());
815  }
816 
817  // update test pass results
818  $this->_updateTestPassResults($active_id, $pass);
819 
820  // Update objective status
821  include_once 'Modules/Course/classes/class.ilCourseObjectiveResult.php';
822  ilCourseObjectiveResult::_updateObjectiveResult($ilUser->getId(),$active_id,$this->getId());
823 
824  }
825 
832  function saveWorkingData($active_id, $pass = NULL)
833  {
834  $this->calculateResultsFromSolution($active_id, $pass);
835  }
836 
837  function _updateTestResultCache($active_id)
838  {
839  global $ilDB;
840 
841  include_once "./Modules/Test/classes/class.ilObjTest.php";
842  $pass = ilObjTest::_getResultPass($active_id);
843 
844  $result = $ilDB->queryF("SELECT tst_pass_result.* FROM tst_pass_result WHERE active_fi = %s AND pass = %s",
845  array('integer','integer'),
846  array($active_id, $pass)
847  );
848  $row = $ilDB->fetchAssoc($result);
849  $max = $row['maxpoints'];
850  $reached = $row['points'];
851  include_once "./Modules/Test/classes/class.assMarkSchema.php";
852  $percentage = (!$max) ? 0 : ($reached / $max) * 100.0;
853  $mark = ASS_MarkSchema::_getMatchingMarkFromActiveId($active_id, $percentage);
854  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_result_cache WHERE active_fi = %s",
855  array('integer'),
856  array($active_id)
857  );
858  $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)",
859  array(
860  'integer',
861  'integer',
862  'float',
863  'float',
864  'text',
865  'text',
866  'integer',
867  'integer',
868  'integer'
869  ),
870  array(
871  $active_id,
872  strlen($pass) ? $pass : 0,
873  strlen($max) ? $max : 0,
874  strlen($reached) ? $reached : 0,
875  strlen($mark["short_name"]) ? $mark["short_name"] : " ",
876  strlen($mark["official_name"]) ? $mark["official_name"] : " ",
877  ($mark["passed"]) ? 1 : 0,
878  (!$mark["passed"]) ? 1 : 0,
879  time()
880  )
881  );
882  }
883 
884  function _updateTestPassResults($active_id, $pass)
885  {
886  global $ilDB;
887  include_once "./Modules/Test/classes/class.ilObjTest.php";
890  // update test pass results
891  $result = $ilDB->queryF("SELECT SUM(points) reachedpoints, COUNT(question_fi) answeredquestions FROM tst_test_result WHERE active_fi = %s AND pass = %s",
892  array('integer','integer'),
893  array($active_id, $pass)
894  );
895  if ($result->numRows() > 0)
896  {
897  $row = $ilDB->fetchAssoc($result);
898  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_pass_result WHERE active_fi = %s AND pass = %s",
899  array('integer','integer'),
900  array($active_id, $pass)
901  );
902  $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)",
903  array(
904  'integer',
905  'integer',
906  'float',
907  'float',
908  'integer',
909  'integer',
910  'integer',
911  'integer'
912  ),
913  array(
914  $active_id,
915  $pass,
916  ($row["reachedpoints"]) ? $row["reachedpoints"] : 0,
917  $data["points"],
918  $data["count"],
919  $row["answeredquestions"],
920  $time,
921  time()
922  )
923  );
924  }
926  return array(
927  'active_fi' => $active_id,
928  'pass' => $pass,
929  'points' => ($row["reachedpoints"]) ? $row["reachedpoints"] : 0,
930  'maxpoints' => $data["points"],
931  'questioncount' => $data["count"],
932  'answeredquestions' => $row["answeredquestions"],
933  'workingtime' => $time,
934  'tstamp' => time()
935  );
936  }
937 
945  function logAction($logtext = "", $active_id = "", $question_id = "")
946  {
947  global $ilUser;
948 
949  $original_id = "";
950  if (strcmp($question_id, "") != 0)
951  {
952  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
954  }
955  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
956  include_once "./Modules/Test/classes/class.ilObjTest.php";
957  ilObjAssessmentFolder::_addLog($ilUser->id, ilObjTest::_getObjectIDFromActiveID($active_id), $logtext, $question_id, $original_id);
958  }
959 
967  function _logAction($logtext = "", $active_id = "", $question_id = "")
968  {
969  global $ilUser;
970 
971  $original_id = "";
972  if (strcmp($question_id, "") != 0)
973  {
974  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
976  }
977  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
978  include_once "./Modules/Test/classes/class.ilObjTest.php";
979  ilObjAssessmentFolder::_addLog($ilUser->id, ilObjTest::_getObjectIDFromActiveID($active_id), $logtext, $question_id, $original_id);
980  }
981 
990  {
991  $mediatempdir = CLIENT_WEB_DIR . "/assessment/temp";
992  if (!@is_dir($mediatempdir)) ilUtil::createDirectory($mediatempdir);
993  $temp_name = tempnam($mediatempdir, $name . "_____");
994  $temp_name = str_replace("\\", "/", $temp_name);
995  @unlink($temp_name);
996  if (!ilUtil::moveUploadedFile($file, $name, $temp_name))
997  {
998  return FALSE;
999  }
1000  else
1001  {
1002  return $temp_name;
1003  }
1004  }
1005 
1012  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/solution/";
1013  }
1014 
1021  function getJavaPath() {
1022  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/java/";
1023  }
1024 
1031  function getImagePath()
1032  {
1033  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/images/";
1034  }
1035 
1042  function getFlashPath()
1043  {
1044  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/flash/";
1045  }
1046 
1053  function getJavaPathWeb()
1054  {
1055  include_once "./Services/Utilities/classes/class.ilUtil.php";
1056  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/java/";
1058  }
1059 
1066  {
1067  include_once "./Services/Utilities/classes/class.ilUtil.php";
1068  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/solution/";
1070  }
1071 
1078  function getImagePathWeb()
1079  {
1080  include_once "./Services/Utilities/classes/class.ilUtil.php";
1081  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/images/";
1083  }
1084 
1091  function getFlashPathWeb()
1092  {
1093  include_once "./Services/Utilities/classes/class.ilUtil.php";
1094  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/flash/";
1096  }
1097 
1105  function &getSolutionValues($active_id, $pass = NULL)
1106  {
1107  global $ilDB;
1108 
1109  $values = array();
1110 
1111  if (is_null($pass))
1112  {
1113  $pass = $this->getSolutionMaxPass($active_id);
1114  }
1115 
1116  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s ORDER BY solution_id",
1117  array('integer','integer','integer'),
1118  array($active_id, $this->getId(), $pass)
1119  );
1120  while ($row = $ilDB->fetchAssoc($result))
1121  {
1122  array_push($values, $row);
1123  }
1124 
1125  return $values;
1126  }
1127 
1128  public static function _getSolutionValues($active_id, $question_id, $pass)
1129  {
1130  global $ilDB;
1131 
1132  $values = array();
1133  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s ORDER BY solution_id",
1134  array('integer','integer','integer'),
1135  array($active_id, $question_id, $pass)
1136  );
1137  while ($row = $ilDB->fetchAssoc($result))
1138  {
1139  array_push($values, $row);
1140  }
1141 
1142  return $values;
1143  }
1144 
1151  function isInUse($question_id = "")
1152  {
1153  global $ilDB;
1154 
1155  if ($question_id < 1) $question_id = $this->getId();
1156  $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",
1157  array('integer'),
1158  array($question_id)
1159  );
1160  $row = $ilDB->fetchAssoc($result);
1161  $count = $row["question_count"];
1162 
1163  $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",
1164  array('integer'),
1165  array($question_id)
1166  );
1167  $count += $result->numRows();
1168 
1169  return $count;
1170  }
1171 
1178  function isClone($question_id = "")
1179  {
1180  global $ilDB;
1181 
1182  if ($question_id < 1) $question_id = $this->id;
1183  $result = $ilDB->queryF("SELECT original_id FROM qpl_questions WHERE question_id = %s",
1184  array('integer'),
1185  array($question_id)
1186  );
1187  $row = $ilDB->fetchAssoc($result);
1188  return ($row["original_id"] > 0) ? TRUE : FALSE;
1189  }
1190 
1197  function pcArrayShuffle($array)
1198  {
1199  $keys = array_keys($array);
1200  shuffle($keys);
1201  $result = array();
1202  foreach ($keys as $key)
1203  {
1204  $result[$key] = $array[$key];
1205  }
1206  return $result;
1207  }
1208 
1214  function getQuestionTypeFromDb($question_id)
1215  {
1216  global $ilDB;
1217 
1218  $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",
1219  array('integer'),
1220  array($question_id)
1221  );
1222  $data = $ilDB->fetchAssoc($result);
1223  return $data["type_tag"];
1224  }
1225 
1233  {
1234  return "";
1235  }
1236 
1244  {
1245  return "";
1246  }
1247 
1254  function deleteAnswers($question_id)
1255  {
1256  global $ilDB;
1257  $answer_table_name = $this->getAnswerTableName();
1258  if (is_array($answer_table_name))
1259  {
1260  foreach ($answer_table_name as $table)
1261  {
1262  if (strlen($table))
1263  {
1264  $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1265  array('integer'),
1266  array($question_id)
1267  );
1268  }
1269  }
1270  }
1271  else
1272  {
1273  if (strlen($answer_table_name))
1274  {
1275  $affectedRows = $ilDB->manipulateF("DELETE FROM $answer_table_name WHERE question_fi = %s",
1276  array('integer'),
1277  array($question_id)
1278  );
1279  }
1280  }
1281  }
1282 
1289  function deleteAdditionalTableData($question_id)
1290  {
1291  global $ilDB;
1292  $additional_table_name = $this->getAdditionalTableName();
1293  if (is_array($additional_table_name))
1294  {
1295  foreach ($additional_table_name as $table)
1296  {
1297  if (strlen($table))
1298  {
1299  $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1300  array('integer'),
1301  array($question_id)
1302  );
1303  }
1304  }
1305  }
1306  else
1307  {
1308  if (strlen($additional_table_name))
1309  {
1310  $affectedRows = $ilDB->manipulateF("DELETE FROM $additional_table_name WHERE question_fi = %s",
1311  array('integer'),
1312  array($question_id)
1313  );
1314  }
1315  }
1316  }
1317 
1324  protected function deletePageOfQuestion($question_id)
1325  {
1326  include_once "./Services/COPage/classes/class.ilPageObject.php";
1327  $page = new ilPageObject("qpl", $question_id);
1328  $page->delete();
1329  return true;
1330  }
1331 
1338  public function delete($question_id)
1339  {
1340  global $ilDB, $ilLog;
1341 
1342  if ($question_id < 1) return true; // nothing to do
1343 
1344  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1345  array('integer'),
1346  array($question_id)
1347  );
1348  if ($result->numRows() == 1)
1349  {
1350  $row = $ilDB->fetchAssoc($result);
1351  $obj_id = $row["obj_fi"];
1352  }
1353  else
1354  {
1355  return true; // nothing to do
1356  }
1357  try
1358  {
1359  $this->deletePageOfQuestion($question_id);
1360  }
1361  catch (Exception $e)
1362  {
1363  $ilLog->write("EXCEPTION: Could not delete page of question $question_id: $e");
1364  return false;
1365  }
1366 
1367  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_questions WHERE question_id = %s",
1368  array('integer'),
1369  array($question_id)
1370  );
1371  if ($affectedRows == 0) return false;
1372 
1373  try
1374  {
1375  $this->deleteAdditionalTableData($question_id);
1376  $this->deleteAnswers($question_id);
1377  }
1378  catch (Exception $e)
1379  {
1380  $ilLog->write("EXCEPTION: Could not delete additional table data of question $question_id: $e");
1381  return false;
1382  }
1383 
1384  try
1385  {
1386  // delete the question in the tst_test_question table (list of test questions)
1387  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_question WHERE question_fi = %s",
1388  array('integer'),
1389  array($question_id)
1390  );
1391  }
1392  catch (Exception $e)
1393  {
1394  $ilLog->write("EXCEPTION: Could not delete delete question $question_id from a test: $e");
1395  return false;
1396  }
1397 
1398  try
1399  {
1400  // delete suggested solutions contained in the question
1401  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
1402  array('integer'),
1403  array($question_id)
1404  );
1405  }
1406  catch (Exception $e)
1407  {
1408  $ilLog->write("EXCEPTION: Could not delete suggested solutions of question $question_id: $e");
1409  return false;
1410  }
1411 
1412  try
1413  {
1414  $directory = CLIENT_WEB_DIR . "/assessment/" . $obj_id . "/$question_id";
1415  if (preg_match("/\d+/", $obj_id) and preg_match("/\d+/", $question_id) and is_dir($directory))
1416  {
1417  include_once "./Services/Utilities/classes/class.ilUtil.php";
1418  ilUtil::delDir($directory);
1419  }
1420  }
1421  catch (Exception $e)
1422  {
1423  $ilLog->write("EXCEPTION: Could not delete question file directory $directory of question $question_id: $e");
1424  return false;
1425  }
1426 
1427  try
1428  {
1429  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1430  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $question_id);
1431  // remaining usages are not in text anymore -> delete them
1432  // and media objects (note: delete method of ilObjMediaObject
1433  // checks whether object is used in another context; if yes,
1434  // the object is not deleted!)
1435  foreach($mobs as $mob)
1436  {
1437  ilObjMediaObject::_removeUsage($mob, "qpl:html", $question_id);
1438  if (ilObjMediaObject::_exists($mob))
1439  {
1440  $mob_obj =& new ilObjMediaObject($mob);
1441  $mob_obj->delete();
1442  }
1443  }
1444  }
1445  catch (Exception $e)
1446  {
1447  $ilLog->write("EXCEPTION: Error deleting the media objects of question $question_id: $e");
1448  return false;
1449  }
1450 
1451  try
1452  {
1453  // update question count of question pool
1454  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1456  }
1457  catch (Exception $e)
1458  {
1459  $ilLog->write("EXCEPTION: Error updating the question pool question count of question pool " . $this->getObjId() . " when deleting question $question_id: $e");
1460  return false;
1461  }
1462  return true;
1463  }
1464 
1468  function getTotalAnswers()
1469  {
1470  return $this->_getTotalAnswers($this->id);
1471  }
1472 
1479  function _getTotalAnswers($a_q_id)
1480  {
1481  global $ilDB;
1482 
1483  // get all question references to the question id
1484  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
1485  array('integer','integer'),
1486  array($a_q_id, $a_q_id)
1487  );
1488  if ($result->numRows() == 0)
1489  {
1490  return 0;
1491  }
1492  $found_id = array();
1493  while ($row = $ilDB->fetchAssoc($result))
1494  {
1495  array_push($found_id, $row["question_id"]);
1496  }
1497 
1498  $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
1499 
1500  return $result->numRows();
1501  }
1502 
1503 
1510  function _getTotalRightAnswers($a_q_id)
1511  {
1512  global $ilDB;
1513  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
1514  array('integer','integer'),
1515  array($a_q_id, $a_q_id)
1516  );
1517  if ($result->numRows() == 0)
1518  {
1519  return 0;
1520  }
1521  $found_id = array();
1522  while ($row = $ilDB->fetchAssoc($result))
1523  {
1524  array_push($found_id, $row["question_id"]);
1525  }
1526  $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
1527  $answers = array();
1528  while ($row = $ilDB->fetchAssoc($result))
1529  {
1530  $reached = $row["points"];
1531  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1532  $max = assQuestion::_getMaximumPoints($row["question_fi"]);
1533  array_push($answers, array("reached" => $reached, "max" => $max));
1534  }
1535  $max = 0.0;
1536  $reached = 0.0;
1537  foreach ($answers as $key => $value)
1538  {
1539  $max += $value["max"];
1540  $reached += $value["reached"];
1541  }
1542  if ($max > 0)
1543  {
1544  return $reached / $max;
1545  }
1546  else
1547  {
1548  return 0;
1549  }
1550  }
1551 
1557  function _getTitle($a_q_id)
1558  {
1559  global $ilDB;
1560  $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE question_id = %s",
1561  array('integer'),
1562  array($a_q_id)
1563  );
1564  if ($result->numRows() == 1)
1565  {
1566  $row = $ilDB->fetchAssoc($result);
1567  return $row["title"];
1568  }
1569  else
1570  {
1571  return "";
1572  }
1573  }
1574 
1580  function _getQuestionText($a_q_id)
1581  {
1582  global $ilDB;
1583  $result = $ilDB->queryF("SELECT question_text FROM qpl_questions WHERE question_id = %s",
1584  array('integer'),
1585  array($a_q_id)
1586  );
1587  if ($result->numRows() == 1)
1588  {
1589  $row = $ilDB->fetchAssoc($result);
1590  return $row["question_text"];
1591  }
1592  else
1593  {
1594  return "";
1595  }
1596  }
1597 
1598 
1600  {
1601  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1602  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $a_q_id);
1603  foreach ($mobs as $mob)
1604  {
1605  ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->getId());
1606  }
1607  }
1608 
1610  {
1611  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1612  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1613  foreach ($mobs as $mob)
1614  {
1615  ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->original_id);
1616  }
1617  }
1618 
1622  function createPageObject()
1623  {
1624  $qpl_id = $this->getObjId();
1625 
1626  include_once "./Services/COPage/classes/class.ilPageObject.php";
1627  $this->page = new ilPageObject("qpl", 0);
1628  $this->page->setId($this->getId());
1629  $this->page->setParentId($qpl_id);
1630  $this->page->setXMLContent("<PageObject><PageContent>".
1631  "<Question QRef=\"il__qst_".$this->getId()."\"/>".
1632  "</PageContent></PageObject>");
1633  $this->page->create();
1634  }
1635 
1636  function copyPageOfQuestion($a_q_id)
1637  {
1638  if ($a_q_id > 0)
1639  {
1640  include_once "./Services/COPage/classes/class.ilPageObject.php";
1641  $page = new ilPageObject("qpl", $a_q_id);
1642 
1643  $xml = str_replace("il__qst_".$a_q_id, "il__qst_".$this->id, $page->getXMLContent());
1644  $this->page->setXMLContent($xml);
1645  $this->page->saveMobUsage($xml);
1646  $this->page->updateFromXML();
1647  }
1648  }
1649 
1651  {
1652  include_once "./Services/COPage/classes/class.ilPageObject.php";
1653  $page = new ilPageObject("qpl", $this->id);
1654  return $page->getXMLContent();
1655  }
1656 
1664  function _getQuestionType($question_id)
1665  {
1666  global $ilDB;
1667 
1668  if ($question_id < 1) return "";
1669  $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",
1670  array('integer'),
1671  array($question_id)
1672  );
1673  if ($result->numRows() == 1)
1674  {
1675  $data = $ilDB->fetchAssoc($result);
1676  return $data["type_tag"];
1677  }
1678  else
1679  {
1680  return "";
1681  }
1682  }
1683 
1691  function _getQuestionTitle($question_id)
1692  {
1693  global $ilDB;
1694 
1695  if ($question_id < 1) return "";
1696 
1697  $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE qpl_questions.question_id = %s",
1698  array('integer'),
1699  array($question_id)
1700  );
1701  if ($result->numRows() == 1)
1702  {
1703  $data = $ilDB->fetchAssoc($result);
1704  return $data["title"];
1705  }
1706  else
1707  {
1708  return "";
1709  }
1710  }
1711 
1713  {
1714  $this->original_id = $original_id;
1715  }
1716 
1717  function getOriginalId()
1718  {
1719  return $this->original_id;
1720  }
1721 
1728  function loadFromDb($question_id)
1729  {
1730  global $ilDB;
1731 
1732  $result = $ilDB->queryF("SELECT external_id FROM qpl_questions WHERE question_id = %s",
1733  array("integer"),
1734  array($question_id)
1735  );
1736  if ($result->numRows() == 1)
1737  {
1738  $data = $ilDB->fetchAssoc($result);
1739  $this->external_id = $data['external_id'];
1740  }
1741 
1742  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
1743  array('integer'),
1744  array($this->getId())
1745  );
1746  $this->suggested_solutions = array();
1747  if ($result->numRows())
1748  {
1749  include_once("./Services/RTE/classes/class.ilRTE.php");
1750  while ($row = $ilDB->fetchAssoc($result))
1751  {
1752  $value = (is_array(unserialize($row["value"]))) ? unserialize($row["value"]) : ilRTE::_replaceMediaObjectImageSrc($row["value"], 1);
1753  $this->suggested_solutions[$row["subquestion_index"]] = array(
1754  "type" => $row["type"],
1755  "value" => $value,
1756  "internal_link" => $row["internal_link"],
1757  "import_id" => $row["import_id"]
1758  );
1759  }
1760  }
1761  }
1762 
1769  public function createNewQuestion()
1770  {
1771  global $ilDB, $ilUser;
1772 
1773  $complete = "0";
1774  $estw_time = $this->getEstimatedWorkingTime();
1775  $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
1776  $obj_id = ($this->getObjId() <= 0) ? (ilObject::_lookupObjId((strlen($_GET["ref_id"])) ? $_GET["ref_id"] : $_POST["sel_qpl"])) : $this->getObjId();
1777  if ($obj_id > 0)
1778  {
1779  $next_id = $ilDB->nextId('qpl_questions');
1780  $affectedRows = $ilDB->insert("qpl_questions", array(
1781  "question_id" => array("integer", $next_id),
1782  "question_type_fi" => array("integer", $this->getQuestionTypeID()),
1783  "obj_fi" => array("integer", $obj_id),
1784  "title" => array("text", NULL),
1785  "description" => array("text", NULL),
1786  "author" => array("text", $this->getAuthor()),
1787  "owner" => array("integer", $ilUser->getId()),
1788  "question_text" => array("clob", NULL),
1789  "points" => array("float", 0),
1790  "nr_of_tries" => array("integer", 1),
1791  "working_time" => array("text", $estw_time),
1792  "complete" => array("text", $complete),
1793  "created" => array("integer", time()),
1794  "external_id" => array("text", $this->getExternalID()),
1795  "original_id" => array("integer", NULL),
1796  "tstamp" => array("integer", 0)
1797  ));
1798  $this->setId($next_id);
1799  // create page object of question
1800  $this->createPageObject();
1801  }
1802  return $this->getId();
1803  }
1804 
1805  public function saveQuestionDataToDb($original_id = "")
1806  {
1807  global $ilDB;
1808 
1809  $estw_time = $this->getEstimatedWorkingTime();
1810  $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
1811 
1812  // cleanup RTE images which are not inserted into the question text
1813  include_once("./Services/RTE/classes/class.ilRTE.php");
1814  if ($this->getId() == -1)
1815  {
1816  // Neuen Datensatz schreiben
1817  $next_id = $ilDB->nextId('qpl_questions');
1818  $affectedRows = $ilDB->insert("qpl_questions", array(
1819  "question_id" => array("integer", $next_id),
1820  "question_type_fi" => array("integer", $this->getQuestionTypeID()),
1821  "obj_fi" => array("integer", $this->getObjId()),
1822  "title" => array("text", $this->getTitle()),
1823  "description" => array("text", $this->getComment()),
1824  "author" => array("text", $this->getAuthor()),
1825  "owner" => array("integer", $this->getOwner()),
1826  "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
1827  "points" => array("float", $this->getMaximumPoints()),
1828  "working_time" => array("text", $estw_time),
1829  "nr_of_tries" => array("integer", (strlen($this->getNrOfTries())) ? $this->getNrOfTries() : 1),
1830  "created" => array("integer", time()),
1831  "original_id" => array("integer", ($original_id) ? $original_id : NULL),
1832  "external_id" => array("text", $this->getExternalID()),
1833  "tstamp" => array("integer", time())
1834  ));
1835  $this->setId($next_id);
1836  // create page object of question
1837  $this->createPageObject();
1838  }
1839  else
1840  {
1841  // Vorhandenen Datensatz aktualisieren
1842  $affectedRows = $ilDB->update("qpl_questions", array(
1843  "obj_fi" => array("integer", $this->getObjId()),
1844  "title" => array("text", $this->getTitle()),
1845  "description" => array("text", $this->getComment()),
1846  "author" => array("text", $this->getAuthor()),
1847  "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
1848  "points" => array("float", $this->getMaximumPoints()),
1849  "nr_of_tries" => array("integer", (strlen($this->getNrOfTries())) ? $this->getNrOfTries() : 1),
1850  "working_time" => array("text", $estw_time),
1851  "external_id" => array("text", $this->getExternalID()),
1852  "tstamp" => array("integer", time())
1853  ), array(
1854  "question_id" => array("integer", $this->getId())
1855  ));
1856  }
1857  }
1858 
1865  function saveToDb($original_id = "")
1866  {
1867  global $ilDB;
1868 
1869  $this->updateSuggestedSolutions();
1870 
1871  // remove unused media objects from ILIAS
1872  $this->cleanupMediaObjectUsage();
1873 
1874  $complete = "0";
1875  if ($this->isComplete())
1876  {
1877  $complete = "1";
1878  }
1879 
1880  // update the question time stamp and completion status
1881  $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET tstamp = %s, owner = %s, complete = %s WHERE question_id = %s",
1882  array('integer','integer','text', 'integer'),
1883  array(time(), ($this->getOwner() <= 0) ? $this->ilias->account->id : $this->getOwner(), $complete, $this->getId())
1884  );
1885 
1886  // update question count of question pool
1887  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1889  }
1890 
1894  protected function onDuplicate($source_question_id)
1895  {
1896  $this->duplicateSuggestedSolutionFiles($source_question_id);
1897  }
1898 
1902  protected function onCopy($source_questionpool_id, $source_question_id)
1903  {
1904  $this->copySuggestedSolutionFiles($source_questionpool_id, $source_question_id);
1905  }
1906 
1910  public function deleteSuggestedSolutions()
1911  {
1912  global $ilDB;
1913  // delete the links in the qpl_sol_sug table
1914  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
1915  array('integer'),
1916  array($this->getId())
1917  );
1918  // delete the links in the int_link table
1919  include_once "./Services/COPage/classes/class.ilInternalLink.php";
1921  $this->suggested_solutions = array();
1923  }
1924 
1932  function getSuggestedSolution($subquestion_index = 0)
1933  {
1934  if (array_key_exists($subquestion_index, $this->suggested_solutions))
1935  {
1936  return $this->suggested_solutions[$subquestion_index];
1937  }
1938  else
1939  {
1940  return array();
1941  }
1942  }
1943 
1952  function getSuggestedSolutionTitle($subquestion_index = 0)
1953  {
1954  if (array_key_exists($subquestion_index, $this->suggested_solutions))
1955  {
1956  $title = $this->suggested_solutions[$subquestion_index]["internal_link"];
1957  // TO DO: resolve internal link an get link type and title
1958  }
1959  else
1960  {
1961  $title = "";
1962  }
1963  return $title;
1964  }
1965 
1975  function setSuggestedSolution($solution_id = "", $subquestion_index = 0, $is_import = false)
1976  {
1977  if (strcmp($solution_id, "") != 0)
1978  {
1979  $import_id = "";
1980  if ($is_import)
1981  {
1982  $import_id = $solution_id;
1983  $solution_id = $this->_resolveInternalLink($import_id);
1984  }
1985  $this->suggested_solutions[$subquestion_index] = array(
1986  "internal_link" => $solution_id,
1987  "import_id" => $import_id
1988  );
1989  }
1990  }
1991 
1995  protected function duplicateSuggestedSolutionFiles($question_id)
1996  {
1997  global $ilLog;
1998 
1999  foreach ($this->suggested_solutions as $index => $solution)
2000  {
2001  if (strcmp($solution["type"], "file") == 0)
2002  {
2003  $filepath = $this->getSuggestedSolutionPath();
2004  $filepath_original = str_replace("/$this->id/solution", "/$question_id/solution", $filepath);
2005  if (!file_exists($filepath))
2006  {
2007  ilUtil::makeDirParents($filepath);
2008  }
2009  $filename = $solution["value"]["name"];
2010  if (strlen($filename))
2011  {
2012  if (!copy($filepath_original . $filename, $filepath . $filename))
2013  {
2014  $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
2015  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2016  }
2017  }
2018  }
2019  }
2020  }
2021 
2026  {
2027  global $ilLog;
2028 
2029  $filepath = $this->getSuggestedSolutionPath();
2030  $filepath_original = str_replace("/$this->id/solution", "/$original_id/solution", $filepath);
2031  ilUtil::delDir($filepath_original);
2032  foreach ($this->suggested_solutions as $index => $solution)
2033  {
2034  if (strcmp($solution["type"], "file") == 0)
2035  {
2036  if (!file_exists($filepath_original))
2037  {
2038  ilUtil::makeDirParents($filepath_original);
2039  }
2040  $filename = $solution["value"]["name"];
2041  if (strlen($filename))
2042  {
2043  if (!@copy($filepath . $filename, $filepath_original . $filename))
2044  {
2045  $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
2046  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2047  }
2048  }
2049  }
2050  }
2051  }
2052 
2053  protected function copySuggestedSolutionFiles($source_questionpool_id, $source_question_id)
2054  {
2055  global $ilLog;
2056 
2057  foreach ($this->suggested_solutions as $index => $solution)
2058  {
2059  if (strcmp($solution["type"], "file") == 0)
2060  {
2061  $filepath = $this->getSuggestedSolutionPath();
2062  $filepath_original = str_replace("/$this->obj_id/$this->id/solution", "/$source_questionpool_id/$source_question_id/solution", $filepath);
2063  if (!file_exists($filepath))
2064  {
2065  ilUtil::makeDirParents($filepath);
2066  }
2067  $filename = $solution["value"]["name"];
2068  if (strlen($filename))
2069  {
2070  if (!copy($filepath_original . $filename, $filepath . $filename))
2071  {
2072  $ilLog->write("File could not be copied!!!!", $ilLog->ERROR);
2073  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2074  }
2075  }
2076  }
2077  }
2078  }
2079 
2084  {
2085  global $ilDB;
2086 
2087  $id = (strlen($original_id) && is_numeric($original_id)) ? $original_id : $this->getId();
2088  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2089  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
2090  array('integer'),
2091  array($id)
2092  );
2094  include_once("./Services/RTE/classes/class.ilRTE.php");
2095  foreach ($this->suggested_solutions as $index => $solution)
2096  {
2097  $next_id = $ilDB->nextId('qpl_sol_sug');
2098  $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)",
2099  array("integer","integer", "text", "text", "text", "text", "integer","integer"),
2100  array(
2101  $next_id,
2102  $id,
2103  $solution["type"],
2104  ilRTE::_replaceMediaObjectImageSrc((is_array($solution["value"])) ? serialize($solution["value"]) : $solution["value"], 0),
2105  $solution["internal_link"],
2106  NULL,
2107  $index,
2108  time()
2109  )
2110  );
2111  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
2112  {
2113  ilInternalLink::_saveLink("qst", $id, $matches[2], $matches[3], $matches[1]);
2114  }
2115  }
2116  if (strlen($original_id) && is_numeric($original_id)) $this->syncSuggestedSolutionFiles($id);
2117  $this->cleanupMediaObjectUsage();
2118  }
2119 
2129  function saveSuggestedSolution($type, $solution_id = "", $subquestion_index = 0, $value = "")
2130  {
2131  global $ilDB;
2132 
2133  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
2134  array("integer", "integer"),
2135  array(
2136  $this->getId(),
2137  $subquestion_index
2138  )
2139  );
2140 
2141  $next_id = $ilDB->nextId('qpl_sol_sug');
2142  include_once("./Services/RTE/classes/class.ilRTE.php");
2143  $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)",
2144  array("integer","integer", "text", "text", "text", "text", "integer","integer"),
2145  array(
2146  $next_id,
2147  $this->getId(),
2148  $type,
2149  ilRTE::_replaceMediaObjectImageSrc((is_array($value)) ? serialize($value) : $value, 0),
2150  $solution_id,
2151  NULL,
2152  $subquestion_index,
2153  time()
2154  )
2155  );
2156  if ($affectedRows == 1)
2157  {
2158  $this->suggested_solutions["subquestion_index"] = array(
2159  "type" => $type,
2160  "value" => $value,
2161  "internal_link" => $solution_id,
2162  "import_id" => ""
2163  );
2164  }
2165  $this->cleanupMediaObjectUsage();
2166  }
2167 
2168  function _resolveInternalLink($internal_link)
2169  {
2170  if (preg_match("/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches))
2171  {
2172  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2173  include_once "./Modules/LearningModule/classes/class.ilLMObject.php";
2174  include_once "./Modules/Glossary/classes/class.ilGlossaryTerm.php";
2175  switch ($matches[2])
2176  {
2177  case "lm":
2178  $resolved_link = ilLMObject::_getIdForImportId($internal_link);
2179  break;
2180  case "pg":
2181  $resolved_link = ilInternalLink::_getIdForImportId("PageObject", $internal_link);
2182  break;
2183  case "st":
2184  $resolved_link = ilInternalLink::_getIdForImportId("StructureObject", $internal_link);
2185  break;
2186  case "git":
2187  $resolved_link = ilInternalLink::_getIdForImportId("GlossaryItem", $internal_link);
2188  break;
2189  case "mob":
2190  $resolved_link = ilInternalLink::_getIdForImportId("MediaObject", $internal_link);
2191  break;
2192  }
2193  if (strcmp($resolved_link, "") == 0)
2194  {
2195  $resolved_link = $internal_link;
2196  }
2197  }
2198  else
2199  {
2200  $resolved_link = $internal_link;
2201  }
2202  return $resolved_link;
2203  }
2204 
2205  function _resolveIntLinks($question_id)
2206  {
2207  global $ilDB;
2208  $resolvedlinks = 0;
2209  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2210  array('integer'),
2211  array($question_id)
2212  );
2213  if ($result->numRows())
2214  {
2215  while ($row = $ilDB->fetchAssoc($result))
2216  {
2217  $internal_link = $row["internal_link"];
2218  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2219  $resolved_link = assQuestion::_resolveInternalLink($internal_link);
2220  if (strcmp($internal_link, $resolved_link) != 0)
2221  {
2222  // internal link was resolved successfully
2223  $affectedRows = $ilDB->manipulateF("UPDATE qpl_sol_sug SET internal_link = %s WHERE suggested_solution_id = %s",
2224  array('text','integer'),
2225  array($resolved_link, $row["suggested_solution_id"])
2226  );
2227  $resolvedlinks++;
2228  }
2229  }
2230  }
2231  if ($resolvedlinks)
2232  {
2233  // there are resolved links -> reenter theses links to the database
2234 
2235  // delete all internal links from the database
2236  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2237  ilInternalLink::_deleteAllLinksOfSource("qst", $question_id);
2238 
2239  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2240  array('integer'),
2241  array($question_id)
2242  );
2243  if ($result->numRows())
2244  {
2245  while ($row = $ilDB->fetchAssoc($result))
2246  {
2247  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $row["internal_link"], $matches))
2248  {
2249  ilInternalLink::_saveLink("qst", $question_id, $matches[2], $matches[3], $matches[1]);
2250  }
2251  }
2252  }
2253  }
2254  }
2255 
2256  function _getInternalLinkHref($target = "")
2257  {
2258  global $ilDB;
2259  $linktypes = array(
2260  "lm" => "LearningModule",
2261  "pg" => "PageObject",
2262  "st" => "StructureObject",
2263  "git" => "GlossaryItem",
2264  "mob" => "MediaObject"
2265  );
2266  $href = "";
2267  if (preg_match("/il__(\w+)_(\d+)/", $target, $matches))
2268  {
2269  $type = $matches[1];
2270  $target_id = $matches[2];
2271  include_once "./Services/Utilities/classes/class.ilUtil.php";
2272  switch($linktypes[$matches[1]])
2273  {
2274  case "LearningModule":
2275  $href = "./goto.php?target=" . $type . "_" . $target_id;
2276  break;
2277  case "PageObject":
2278  case "StructureObject":
2279  $href = "./goto.php?target=" . $type . "_" . $target_id;
2280  break;
2281  case "GlossaryItem":
2282  $href = "./goto.php?target=" . $type . "_" . $target_id;
2283  break;
2284  case "MediaObject":
2285  $href = "./ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[$type] . "&cmd=media&ref_id=".$_GET["ref_id"]."&mob_id=".$target_id;
2286  break;
2287  }
2288  }
2289  return $href;
2290  }
2291 
2299  function _getOriginalId($question_id)
2300  {
2301  global $ilDB;
2302  $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE question_id = %s",
2303  array('integer'),
2304  array($question_id)
2305  );
2306  if ($result->numRows() > 0)
2307  {
2308  $row = $ilDB->fetchAssoc($result);
2309  if ($row["original_id"] > 0)
2310  {
2311  return $row["original_id"];
2312  }
2313  else
2314  {
2315  return $row["question_id"];
2316  }
2317  }
2318  else
2319  {
2320  return "";
2321  }
2322  }
2323 
2324  function syncWithOriginal()
2325  {
2326  global $ilDB;
2327 
2328  if ($this->getOriginalId())
2329  {
2330  $id = $this->getId();
2331  $original = $this->getOriginalId();
2332 
2333  $this->setId($this->getOriginalId());
2334  $this->setOriginalId(NULL);
2335  $this->saveToDb();
2336  $this->deletePageOfQuestion($original);
2337  $this->createPageObject();
2338  $this->copyPageOfQuestion($id);
2339 
2340  $this->setId($id);
2341  $this->setOriginalId($original);
2342  $this->updateSuggestedSolutions($original);
2343  $this->syncFeedbackGeneric();
2345  }
2346  }
2347 
2348  function createRandomSolution($test_id, $user_id)
2349  {
2350  }
2351 
2359  function _questionExists($question_id)
2360  {
2361  global $ilDB;
2362 
2363  if ($question_id < 1)
2364  {
2365  return false;
2366  }
2367 
2368  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE question_id = %s",
2369  array('integer'),
2370  array($question_id)
2371  );
2372  if ($result->numRows() == 1)
2373  {
2374  return true;
2375  }
2376  else
2377  {
2378  return false;
2379  }
2380  }
2381 
2389  function &_instanciateQuestion($question_id)
2390  {
2391  if (strcmp($question_id, "") != 0)
2392  {
2393  $question_type = assQuestion::_getQuestionType($question_id);
2394  if (!strlen($question_type)) return null;
2395  assQuestion::_includeClass($question_type);
2396  $question = new $question_type();
2397  $question->loadFromDb($question_id);
2398  return $question;
2399  }
2400  }
2401 
2408  function getPoints()
2409  {
2410  if (strcmp($this->points, "") == 0)
2411  {
2412  return 0;
2413  }
2414  else
2415  {
2416  return $this->points;
2417  }
2418  }
2419 
2420 
2427  function setPoints($a_points)
2428  {
2429  $this->points = $a_points;
2430  }
2431 
2438  function getSolutionMaxPass($active_id)
2439  {
2440  return $this->_getSolutionMaxPass($this->getId(), $active_id);
2441  }
2442 
2449  function _getSolutionMaxPass($question_id, $active_id)
2450  {
2451 /* include_once "./Modules/Test/classes/class.ilObjTest.php";
2452  $pass = ilObjTest::_getPass($active_id);
2453  return $pass;*/
2454 
2455  // the following code was the old solution which added the non answered
2456  // questions of a pass from the answered questions of the previous pass
2457  // with the above solution, only the answered questions of the last pass are counted
2458  global $ilDB;
2459 
2460  $result = $ilDB->queryF("SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
2461  array('integer','integer'),
2462  array($active_id, $question_id)
2463  );
2464  if ($result->numRows() == 1)
2465  {
2466  $row = $ilDB->fetchAssoc($result);
2467  return ($row["maxpass"]) ? $row["maxpass"] : 0;
2468  }
2469  else
2470  {
2471  return 0;
2472  }
2473  }
2474 
2483  function _isWriteable($question_id, $user_id)
2484  {
2485  global $ilDB;
2486 
2487  if (($question_id < 1) || ($user_id < 1))
2488  {
2489  return false;
2490  }
2491 
2492  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
2493  array('integer'),
2494  array($question_id)
2495  );
2496  if ($result->numRows() == 1)
2497  {
2498  $row = $ilDB->fetchAssoc($result);
2499  $qpl_object_id = $row["obj_fi"];
2500  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
2501  return ilObjQuestionPool::_isWriteable($qpl_object_id, $user_id);
2502  }
2503  else
2504  {
2505  return false;
2506  }
2507  }
2508 
2515  function _isUsedInRandomTest($question_id = "")
2516  {
2517  global $ilDB;
2518 
2519  if ($question_id < 1) return 0;
2520  $result = $ilDB->queryF("SELECT test_random_question_id FROM tst_test_rnd_qst WHERE question_fi = %s",
2521  array('integer'),
2522  array($question_id)
2523  );
2524  return $result->numRows();
2525  }
2526 
2536  function calculateReachedPoints($active_id, $pass = NULL, $points = 0)
2537  {
2538  include_once "./Modules/Test/classes/class.ilObjTest.php";
2539  $count_system = ilObjTest::_getCountSystem($active_id);
2540  if ($count_system == 1)
2541  {
2542  if ($points != $this->getMaximumPoints())
2543  {
2544  $points = 0;
2545  }
2546  }
2547  $score_cutting = ilObjTest::_getScoreCutting($active_id);
2548  if ($score_cutting == 0)
2549  {
2550  if ($points < 0)
2551  {
2552  $points = 0;
2553  }
2554  }
2555  return $points;
2556  }
2557 
2566  public static function _isWorkedThrough($active_id, $question_id, $pass = NULL)
2567  {
2568  global $ilDB;
2569 
2570  $points = 0;
2571  if (is_null($pass))
2572  {
2573  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2574  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
2575  }
2576  $result = $ilDB->queryF("SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
2577  array('integer','integer','integer'),
2578  array($active_id, $question_id, $pass)
2579  );
2580  if ($result->numRows())
2581  {
2582  return TRUE;
2583  }
2584  else
2585  {
2586  return FALSE;
2587  }
2588  }
2589 
2597  public static function _areAnswered($a_user_id,$a_question_ids)
2598  {
2599  global $ilDB;
2600 
2601  $res = $ilDB->queryF("SELECT DISTINCT(question_fi) FROM tst_test_result JOIN tst_active ".
2602  "ON (active_id = active_fi) ".
2603  "WHERE " . $ilDB->in('question_fi', $a_question_ids, false, 'integer') .
2604  " AND user_fi = %s",
2605  array('integer'),
2606  array($a_user_id)
2607  );
2608  return ($res->numRows() == count($a_question_ids)) ? true : false;
2609  }
2610 
2618  function isHTML($a_text)
2619  {
2620  if (preg_match("/<[^>]*?>/", $a_text))
2621  {
2622  return TRUE;
2623  }
2624  else
2625  {
2626  return FALSE;
2627  }
2628  }
2629 
2636  function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE)
2637  {
2638  include_once "./Services/Utilities/classes/class.ilUtil.php";
2639  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output);
2640  }
2641 
2649  function QTIMaterialToString($a_material)
2650  {
2651  $result = "";
2652  for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
2653  {
2654  $material = $a_material->getMaterial($i);
2655  if (strcmp($material["type"], "mattext") == 0)
2656  {
2657  $result .= $material["material"]->getContent();
2658  }
2659  if (strcmp($material["type"], "matimage") == 0)
2660  {
2661  $matimage = $material["material"];
2662  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
2663  {
2664  // import an mediaobject which was inserted using tiny mce
2665  if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
2666  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
2667  }
2668  }
2669  }
2670  return $result;
2671  }
2672 
2681  function addQTIMaterial(&$a_xml_writer, $a_material, $close_material_tag = TRUE, $add_mobs = TRUE)
2682  {
2683  include_once "./Services/RTE/classes/class.ilRTE.php";
2684  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
2685 
2686  $a_xml_writer->xmlStartTag("material");
2687  $attrs = array(
2688  "texttype" => "text/plain"
2689  );
2690  if ($this->isHTML($a_material))
2691  {
2692  $attrs["texttype"] = "text/xhtml";
2693  }
2694  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
2695  if ($add_mobs)
2696  {
2697  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
2698  foreach ($mobs as $mob)
2699  {
2700  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
2701  if (strpos($a_material, "mm_$mob") !== FALSE)
2702  {
2703  if (ilObjMediaObject::_exists($mob))
2704  {
2705  $mob_obj =& new ilObjMediaObject($mob);
2706  $imgattrs = array(
2707  "label" => $moblabel,
2708  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
2709  );
2710  }
2711  $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
2712  }
2713  }
2714  }
2715  if ($close_material_tag) $a_xml_writer->xmlEndTag("material");
2716  }
2717 
2718  function createNewImageFileName($image_filename)
2719  {
2720  $extension = "";
2721  if (preg_match("/.*\.(png|jpg|gif|jpeg)$/i", $image_filename, $matches))
2722  {
2723  $extension = "." . $matches[1];
2724  }
2725  $image_filename = md5($image_filename) . $extension;
2726  return $image_filename;
2727  }
2728 
2739  function _setReachedPoints($active_id, $question_id, $points, $maxpoints, $pass = NULL, $manualscoring = FALSE, $rescoring = FALSE)
2740  {
2741  global $ilDB;
2742 
2743  if ($points <= $maxpoints)
2744  {
2745  if (is_null($pass))
2746  {
2747  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
2748  }
2749 
2750  // retrieve the already given points
2751  $old_points = 0;
2752  $result = $ilDB->queryF("SELECT points FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
2753  array('integer','integer','integer'),
2754  array($active_id, $question_id, $pass)
2755  );
2756  $manual = ($manualscoring) ? 1 : 0;
2757  if ($result->numRows())
2758  {
2759  $row = $ilDB->fetchAssoc($result);
2760  $old_points = $row["points"];
2761  $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",
2762  array('float', 'integer', 'integer', 'integer', 'integer', 'integer'),
2763  array($points, $manual, time(), $active_id, $question_id, $pass)
2764  );
2765  }
2766  else
2767  {
2768  $next_id = $ilDB->nextId('tst_test_result');
2769  $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)",
2770  array('integer', 'integer','integer', 'float', 'integer', 'integer','integer'),
2771  array($next_id, $active_id, $question_id, $points, $pass, $manual, time())
2772  );
2773  }
2775  // finally update objective result
2776  include_once "./Modules/Test/classes/class.ilObjTest.php";
2777  include_once './Modules/Course/classes/class.ilCourseObjectiveResult.php';
2779 
2780  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
2782  {
2783  global $lng, $ilUser;
2784  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
2785  $username = ilObjTestAccess::_getParticipantData($active_id);
2786  if ($rescoring)
2787  {
2788  assQuestion::_logAction(sprintf($lng->txtlng("assessment", "log_answer_changed_points_rescore", ilObjAssessmentFolder::_getLogLanguage()), $username, $old_points, $points, $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")"), $active_id, $question_id);
2789  }
2790  else
2791  {
2792  assQuestion::_logAction(sprintf($lng->txtlng("assessment", "log_answer_changed_points", ilObjAssessmentFolder::_getLogLanguage()), $username, $old_points, $points, $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")"), $active_id, $question_id);
2793  }
2794  }
2795 
2796  return TRUE;
2797  }
2798  else
2799  {
2800  return FALSE;
2801  }
2802  }
2803 
2811  function getQuestion()
2812  {
2813  return $this->question;
2814  }
2815 
2823  function setQuestion($question = "")
2824  {
2825  $this->question = $question;
2826  }
2827 
2834  function getQuestionType()
2835  {
2836  // must be overwritten in every parent class
2837  return "";
2838  }
2839 
2849  {
2850  global $ilDB;
2851 
2852  $result = $ilDB->queryF("SELECT question_type_id FROM qpl_qst_type WHERE type_tag = %s",
2853  array('text'),
2854  array($this->getQuestionType())
2855  );
2856  if ($result->numRows() == 1)
2857  {
2858  $row = $ilDB->fetchAssoc($result);
2859  return $row["question_type_id"];
2860  }
2861  return 0;
2862  }
2863 
2873  function saveFeedbackGeneric($correctness, $feedback)
2874  {
2875  global $ilDB;
2876 
2877  switch ($correctness)
2878  {
2879  case 0:
2880  $correctness = 0;
2881  break;
2882  case 1:
2883  default:
2884  $correctness = 1;
2885  break;
2886  }
2887  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_generic WHERE question_fi = %s AND correctness = %s",
2888  array('integer', 'text'),
2889  array($this->getId(), $correctness)
2890  );
2891  if (strlen($feedback))
2892  {
2893  include_once("./Services/RTE/classes/class.ilRTE.php");
2894  $next_id = $ilDB->nextId('qpl_fb_generic');
2895  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_generic (feedback_id, question_fi, correctness, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
2896  array('integer','integer','text','text','integer'),
2897  array($next_id, $this->getId(), $correctness, ilRTE::_replaceMediaObjectImageSrc($feedback, 0), time())
2898  );
2899  }
2900  }
2901 
2911  function getFeedbackGeneric($correctness)
2912  {
2913  global $ilDB;
2914 
2915  $feedback = "";
2916  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s AND correctness = %s",
2917  array('integer', 'text'),
2918  array($this->getId(), $correctness)
2919  );
2920  if ($result->numRows())
2921  {
2922  $row = $ilDB->fetchAssoc($result);
2923  include_once("./Services/RTE/classes/class.ilRTE.php");
2924  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
2925  }
2926  return $feedback;
2927  }
2928 
2936  {
2937  global $ilDB;
2938 
2939  $feedback = "";
2940  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s",
2941  array('integer'),
2942  array($original_id)
2943  );
2944  if ($result->numRows())
2945  {
2946  while ($row = $ilDB->fetchAssoc($result))
2947  {
2948  $next_id = $ilDB->nextId('qpl_fb_generic');
2949  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_generic (feedback_id, question_fi, correctness, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
2950  array('integer','integer','text','text','integer'),
2951  array($next_id, $this->getId(), $row["correctness"], $row["feedback"], time())
2952  );
2953  }
2954  }
2955  }
2956 
2958  {
2959  global $ilDB;
2960 
2961  $feedback = "";
2962 
2963  // delete generic feedback of the original
2964  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_generic WHERE question_fi = %s",
2965  array('integer'),
2966  array($this->original_id)
2967  );
2968 
2969  // get generic feedback of the actual question
2970  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s",
2971  array('integer'),
2972  array($this->getId())
2973  );
2974 
2975  // save generic feedback to the original
2976  if ($result->numRows())
2977  {
2978  while ($row = $ilDB->fetchAssoc($result))
2979  {
2980  $next_id = $ilDB->nextId('qpl_fb_generic');
2981  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_generic (feedback_id, question_fi, correctness, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
2982  array('integer','integer','text','text','integer'),
2983  array($next_id, $this->original_id, $row["correctness"], $row["feedback"], time())
2984  );
2985  }
2986  }
2987  }
2988 
2994  {
2995  // must be called in parent classes. add additional RTE text in the parent
2996  // classes and call this method to add the standard RTE text
2997  $collected = $this->getQuestion();
2998  $collected .= $this->getFeedbackGeneric(0);
2999  $collected .= $this->getFeedbackGeneric(1);
3000  foreach ($this->suggested_solutions as $solution_array)
3001  {
3002  $collected .= $solution_array["value"];
3003  }
3004  return $collected;
3005  }
3006 
3012  {
3013  $combinedtext = $this->getRTETextWithMediaObjects();
3014  include_once("./Services/RTE/classes/class.ilRTE.php");
3015  ilRTE::_cleanupMediaObjectUsage($combinedtext, "qpl:html", $this->getId());
3016  }
3017 
3023  function &getInstances()
3024  {
3025  global $ilDB;
3026 
3027  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s",
3028  array("integer"),
3029  array($this->getId())
3030  );
3031  $instances = array();
3032  $ids = array();
3033  while ($row = $ilDB->fetchAssoc($result))
3034  {
3035  array_push($ids, $row["question_id"]);
3036  }
3037  foreach ($ids as $question_id)
3038  {
3039  // check non random tests
3040  $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",
3041  array("integer"),
3042  array($question_id)
3043  );
3044  while ($row = $ilDB->fetchAssoc($result))
3045  {
3046  $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3047  }
3048  // check random tests
3049  $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",
3050  array("integer"),
3051  array($question_id)
3052  );
3053  while ($row = $ilDB->fetchAssoc($result))
3054  {
3055  $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3056  }
3057  }
3058  include_once "./Modules/Test/classes/class.ilObjTest.php";
3059  foreach ($instances as $key => $value)
3060  {
3061  $instances[$key] = array("obj_id" => $key, "title" => $value, "author" => ilObjTest::_lookupAuthor($key), "refs" => ilObject::_getAllReferences($key));
3062  }
3063  return $instances;
3064  }
3065 
3066  function _needsManualScoring($question_id)
3067  {
3068  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
3070  $questiontype = assQuestion::_getQuestionType($question_id);
3071  if (in_array($questiontype, $scoring))
3072  {
3073  return TRUE;
3074  }
3075  else
3076  {
3077  return FALSE;
3078  }
3079  }
3080 
3088  function getActiveUserData($active_id)
3089  {
3090  global $ilDB;
3091  $result = $ilDB->queryF("SELECT * FROM tst_active WHERE active_id = %s",
3092  array('integer'),
3093  array($active_id)
3094  );
3095  if ($result->numRows())
3096  {
3097  $row = $ilDB->fetchAssoc($result);
3098  return array("user_id" => $row["user_fi"], "test_id" => $row["test_fi"]);
3099  }
3100  else
3101  {
3102  return array();
3103  }
3104  }
3105 
3113  static function _includeClass($question_type, $gui = 0)
3114  {
3115  $type = $question_type;
3116  if ($gui) $type .= "GUI";
3117  if (file_exists("./Modules/TestQuestionPool/classes/class.".$type.".php"))
3118  {
3119  include_once "./Modules/TestQuestionPool/classes/class.".$type.".php";
3120  }
3121  else
3122  {
3123  global $ilPluginAdmin;
3124  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3125  foreach ($pl_names as $pl_name)
3126  {
3127  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3128  if (strcmp($pl->getQuestionType(), $question_type) == 0)
3129  {
3130  $pl->includeClass("class.".$type.".php");
3131  }
3132  }
3133  }
3134  }
3135 
3142  static function _getQuestionTypeName($type_tag)
3143  {
3144  if (file_exists("./Modules/TestQuestionPool/classes/class.".$type_tag.".php"))
3145  {
3146  global $lng;
3147  return $lng->txt($type_tag);
3148  }
3149  else
3150  {
3151  global $ilPluginAdmin;
3152  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3153  foreach ($pl_names as $pl_name)
3154  {
3155  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3156  if (strcmp($pl->getQuestionType(), $type_tag) == 0)
3157  {
3158  return $pl->getQuestionTypeTranslation();
3159  }
3160  }
3161  }
3162  return "";
3163  }
3164 
3172  function &_instanciateQuestionGUI($question_id)
3173  {
3174  if (strcmp($question_id, "") != 0)
3175  {
3176  $question_type = assQuestion::_getQuestionType($question_id);
3177  $question_type_gui = $question_type . "GUI";
3178  assQuestion::_includeClass($question_type, 1);
3179  $question_gui = new $question_type_gui();
3180  $question_gui->object->loadFromDb($question_id);
3181  return $question_gui;
3182  }
3183  }
3184 
3194  public function setExportDetailsXLS(&$adapter, $startrow, $active_id, $pass)
3195  {
3196  return $startrow;
3197  }
3198 
3202  public function __get($value)
3203  {
3204  switch ($value)
3205  {
3206  case "id":
3207  return $this->getId();
3208  break;
3209  case "title":
3210  return $this->getTitle();
3211  break;
3212  case "comment":
3213  return $this->getComment();
3214  break;
3215  case "owner":
3216  return $this->getOwner();
3217  break;
3218  case "author":
3219  return $this->getAuthor();
3220  break;
3221  case "question":
3222  return $this->getQuestion();
3223  break;
3224  case "points":
3225  return $this->getPoints();
3226  break;
3227  case "est_working_time":
3228  return $this->getEstimatedWorkingTime();
3229  break;
3230  case "shuffle":
3231  return $this->getShuffle();
3232  break;
3233  case "test_id":
3234  return $this->getTestId();
3235  break;
3236  case "obj_id":
3237  return $this->getObjId();
3238  break;
3239  case "ilias":
3240  return $this->ilias;
3241  break;
3242  case "tpl":
3243  return $this->tpl;
3244  break;
3245  case "page":
3246  return $this->page;
3247  break;
3248  case "outputType":
3249  return $this->getOutputType();
3250  break;
3251  case "suggested_solutions":
3252  return $this->getSuggestedSolutions();
3253  break;
3254  case "original_id":
3255  return $this->getOriginalId();
3256  break;
3257  default:
3258  if (array_key_exists($value, $this->arrData))
3259  {
3260  return $this->arrData[$value];
3261  }
3262  else
3263  {
3264  return null;
3265  }
3266  break;
3267  }
3268  }
3269 
3273  public function __set($key, $value)
3274  {
3275  switch ($key)
3276  {
3277  case "id":
3278  $this->setId($value);
3279  break;
3280  case "title":
3281  $this->setTitle($value);
3282  break;
3283  case "comment":
3284  $this->setComment($value);
3285  break;
3286  case "owner":
3287  $this->setOwner($value);
3288  break;
3289  case "author":
3290  $this->setAuthor($value);
3291  break;
3292  case "question":
3293  $this->setQuestion($value);
3294  break;
3295  case "points":
3296  $this->setPoints($value);
3297  break;
3298  case "est_working_time":
3299  if (is_array($value))
3300  {
3301  $this->setEstimatedWorkingTime($value["h"], $value["m"], $value["s"]);
3302  }
3303  break;
3304  case "shuffle":
3305  $this->setShuffle($value);
3306  break;
3307  case "test_id":
3308  $this->setTestId($value);
3309  break;
3310  case "obj_id":
3311  $this->setObjId($value);
3312  break;
3313  case "outputType":
3314  $this->setOutputType($value);
3315  break;
3316  case "original_id":
3317  $this->setOriginalId($value);
3318  break;
3319  case "page":
3320  $this->page =& $value;
3321  break;
3322  default:
3323  $this->arrData[$key] = $value;
3324  break;
3325  }
3326  }
3327 
3328  public function getNrOfTries()
3329  {
3330  return $this->nr_of_tries;
3331  }
3332 
3333  public function setNrOfTries($a_nr_of_tries)
3334  {
3335  $this->nr_of_tries = $a_nr_of_tries;
3336  }
3337 
3338  public function getExternalID()
3339  {
3340  if (!strlen($this->external_id))
3341  {
3342  if ($this->getId() > 0)
3343  {
3344  return "il_".IL_INST_ID."_qst_".$this->getId();
3345  }
3346  else
3347  {
3348  return uniqid('', true);
3349  }
3350  }
3351  else
3352  {
3353  return $this->external_id;
3354  }
3355  }
3356 
3357  public function setExternalID($id)
3358  {
3359  $this->external_id = $id;
3360  }
3361 }
3362 
3363 ?>