ILIAS  Release_4_2_x_branch Revision 61807
 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 
178 
189  function __construct(
190  $title = "",
191  $comment = "",
192  $author = "",
193  $owner = -1,
194  $question = ""
195  )
196  {
197  global $ilias;
198  global $lng;
199  global $tpl;
200 
201  $this->ilias =& $ilias;
202  $this->lng =& $lng;
203  $this->tpl =& $tpl;
204 
205  $this->original_id = null;
206  $this->title = $title;
207  $this->comment = $comment;
208  $this->page = null;
209  $this->author = $author;
210  $this->setQuestion($question);
211  if (!$this->author)
212  {
213  $this->author = $this->ilias->account->fullname;
214  }
215  $this->owner = $owner;
216  if ($this->owner <= 0)
217  {
218  $this->owner = $this->ilias->account->id;
219  }
220  $this->id = -1;
221  $this->test_id = -1;
222  $this->suggested_solutions = array();
223  $this->shuffle = 1;
224  $this->nr_of_tries = "";
225  $this->setEstimatedWorkingTime(0,1,0);
226  $this->outputType = OUTPUT_HTML;
227  $this->arrData = array();
228  }
229 
241  function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
242  {
243  include_once "./Modules/TestQuestionPool/classes/import/qti12/class." . $this->getQuestionType() . "Import.php";
244  $classname = $this->getQuestionType() . "Import";
245  $import = new $classname($this);
246  $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
247  }
248 
255  function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
256  {
257  include_once "./Modules/TestQuestionPool/classes/export/qti12/class." . $this->getQuestionType() . "Export.php";
258  $classname = $this->getQuestionType() . "Export";
259  $export = new $classname($this);
260  return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
261  }
262 
269  function isComplete()
270  {
271  return false;
272  }
273 
281  function questionTitleExists($questionpool_id, $title)
282  {
283  global $ilDB;
284 
285  $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE obj_fi = %s AND title = %s",
286  array('integer','text'),
287  array($questionpool_id, $title)
288  );
289  return ($result->numRows() == 1) ? TRUE : FALSE;
290  }
291 
299  function setTitle($title = "")
300  {
301  $this->title = $title;
302  }
303 
311  function setId($id = -1)
312  {
313  $this->id = $id;
314  }
315 
323  function setTestId($id = -1)
324  {
325  $this->test_id = $id;
326  }
327 
335  function setComment($comment = "")
336  {
337  $this->comment = $comment;
338  }
339 
348  {
349  $this->outputType = $outputType;
350  }
351 
352 
360  function setShuffle($shuffle = true)
361  {
362  if ($shuffle)
363  {
364  $this->shuffle = 1;
365  }
366  else
367  {
368  $this->shuffle = 0;
369  }
370  }
371 
381  function setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
382  {
383  $this->est_working_time = array("h" => (int)$hour, "m" => (int)$min, "s" => (int)$sec);
384  }
385 
393  function keyInArray($searchkey, $array)
394  {
395  if ($searchKey)
396  {
397  foreach ($array as $key => $value)
398  {
399  if (strcmp($key, $searchkey)==0)
400  {
401  return true;
402  }
403  }
404  }
405  return false;
406  }
407 
415  function setAuthor($author = "")
416  {
417  if (!$author)
418  {
419  $author = $this->ilias->account->fullname;
420  }
421  $this->author = $author;
422  }
423 
431  function setOwner($owner = "")
432  {
433  $this->owner = $owner;
434  }
435 
443  function getTitle()
444  {
445  return $this->title;
446  }
447 
455  function getId()
456  {
457  return $this->id;
458  }
459 
467  function getShuffle()
468  {
469  return $this->shuffle;
470  }
471 
479  function getTestId()
480  {
481  return $this->test_id;
482  }
483 
491  function getComment()
492  {
493  return $this->comment;
494  }
495 
503  function getOutputType()
504  {
505  return $this->outputType;
506  }
507 
515  {
516  return FALSE;
517  }
518 
527  {
528  if (!$this->est_working_time)
529  {
530  $this->est_working_time = array("h" => 0, "m" => 0, "s" => 0);
531  }
533  }
534 
542  function getAuthor()
543  {
544  return $this->author;
545  }
546 
554  function getOwner()
555  {
556  return $this->owner;
557  }
558 
566  function getObjId()
567  {
568  return $this->obj_id;
569  }
570 
578  function setObjId($obj_id = 0)
579  {
580  $this->obj_id = $obj_id;
581  }
582 
589  function _getMaximumPoints($question_id)
590  {
591  global $ilDB;
592 
593  $points = 0;
594  $result = $ilDB->queryF("SELECT points FROM qpl_questions WHERE question_id = %s",
595  array('integer'),
596  array($question_id)
597  );
598  if ($result->numRows() == 1)
599  {
600  $row = $ilDB->fetchAssoc($result);
601  $points = $row["points"];
602  }
603  return $points;
604  }
605 
612  function &_getQuestionInfo($question_id)
613  {
614  global $ilDB;
615 
616  $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",
617  array('integer'),
618  array($question_id)
619  );
620  if ($result->numRows())
621  {
622  return $ilDB->fetchAssoc($result);
623  }
624  else return array();
625  }
626 
633  public static function _getSuggestedSolutionCount($question_id)
634  {
635  global $ilDB;
636 
637  $result = $ilDB->queryF("SELECT suggested_solution_id FROM qpl_sol_sug WHERE question_fi = %s",
638  array('integer'),
639  array($question_id)
640  );
641  return $result->numRows();
642  }
643 
650  public static function _getSuggestedSolutionOutput($question_id)
651  {
653  if (!is_object($question)) return "";
654  return $question->getSuggestedSolutionOutput();
655  }
656 
657  public function getSuggestedSolutionOutput()
658  {
659  $output = array();
660  foreach ($this->suggested_solutions as $solution)
661  {
662  switch ($solution["type"])
663  {
664  case "lm":
665  case "st":
666  case "pg":
667  case "git":
668  array_push($output, '<a href="' . assQuestion::_getInternalLinkHref($solution["internal_link"]) . '">' . $this->lng->txt("solution_hint") . '</a>');
669  break;
670  case "file":
671  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>');
672  break;
673  case "text":
674  array_push($output, $this->prepareTextareaOutput($solution["value"]));
675  break;
676  }
677  }
678  return join($output, "<br />");
679  }
680 
689  function &_getSuggestedSolution($question_id, $subquestion_index = 0)
690  {
691  global $ilDB;
692 
693  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
694  array('integer','integer'),
695  array($question_id, $subquestion_index)
696  );
697  if ($result->numRows() == 1)
698  {
699  $row = $ilDB->fetchAssoc($result);
700  return array(
701  "internal_link" => $row["internal_link"],
702  "import_id" => $row["import_id"]
703  );
704  }
705  else
706  {
707  return array();
708  }
709  }
710 
716  public function getSuggestedSolutions()
717  {
719  }
720 
728  function _getReachedPoints($active_id, $question_id, $pass = NULL)
729  {
730  global $ilDB;
731 
732  $points = 0;
733  if (is_null($pass))
734  {
735  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
736  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
737  }
738  $result = $ilDB->queryF("SELECT * FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
739  array('integer','integer','integer'),
740  array($active_id, $question_id, $pass)
741  );
742  if ($result->numRows() == 1)
743  {
744  $row = $ilDB->fetchAssoc($result);
745  $points = $row["points"];
746  }
747  return $points;
748  }
749 
758  function getReachedPoints($active_id, $pass = NULL)
759  {
760  return round($this->_getReachedPoints($active_id, $this->getId(), $pass), 2);
761  }
762 
769  function getMaximumPoints()
770  {
771  return $this->points;
772  }
773 
780  public function calculateResultsFromSolution($active_id, $pass = NULL)
781  {
782  global $ilDB;
783  global $ilUser;
784  if (is_null($pass))
785  {
786  include_once "./Modules/Test/classes/class.ilObjTest.php";
787  $pass = ilObjTest::_getPass($active_id);
788  }
789  $reached_points = $this->calculateReachedPoints($active_id, $pass);
790  if (is_null($reached_points)) $reached_points = 0;
791 
792  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
793  array("integer", "integer", "integer"),
794  array(
795  $active_id,
796  $this->getId(),
797  $pass
798  )
799  );
800 
801  $next_id = $ilDB->nextId("tst_test_result");
802  $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)",
803  array("integer","integer", "integer", "integer", "float", "integer"),
804  array(
805  $next_id,
806  $active_id,
807  $this->getId(),
808  $pass,
809  $reached_points,
810  time()
811  )
812  );
813  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
815  {
816  $this->logAction(sprintf($this->lng->txtlng("assessment", "log_user_answered_question", ilObjAssessmentFolder::_getLogLanguage()), $reached_points), $active_id, $this->getId());
817  }
818 
819  // update test pass results
820  $this->_updateTestPassResults($active_id, $pass);
821 
822  // Update objective status
823  include_once 'Modules/Course/classes/class.ilCourseObjectiveResult.php';
824  ilCourseObjectiveResult::_updateObjectiveResult($ilUser->getId(),$active_id,$this->getId());
825 
826  }
827 
834  function saveWorkingData($active_id, $pass = NULL)
835  {
836  $this->calculateResultsFromSolution($active_id, $pass);
837  }
838 
839  function _updateTestResultCache($active_id)
840  {
841  global $ilDB;
842 
843  include_once "./Modules/Test/classes/class.ilObjTest.php";
844  $pass = ilObjTest::_getResultPass($active_id);
845 
846  $result = $ilDB->queryF("SELECT tst_pass_result.* FROM tst_pass_result WHERE active_fi = %s AND pass = %s",
847  array('integer','integer'),
848  array($active_id, $pass)
849  );
850  $row = $ilDB->fetchAssoc($result);
851  $max = $row['maxpoints'];
852  $reached = $row['points'];
853  include_once "./Modules/Test/classes/class.assMarkSchema.php";
854  $percentage = (!$max) ? 0 : ($reached / $max) * 100.0;
855  $mark = ASS_MarkSchema::_getMatchingMarkFromActiveId($active_id, $percentage);
856  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_result_cache WHERE active_fi = %s",
857  array('integer'),
858  array($active_id)
859  );
860  $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)",
861  array(
862  'integer',
863  'integer',
864  'float',
865  'float',
866  'text',
867  'text',
868  'integer',
869  'integer',
870  'integer'
871  ),
872  array(
873  $active_id,
874  strlen($pass) ? $pass : 0,
875  strlen($max) ? $max : 0,
876  strlen($reached) ? $reached : 0,
877  strlen($mark["short_name"]) ? $mark["short_name"] : " ",
878  strlen($mark["official_name"]) ? $mark["official_name"] : " ",
879  ($mark["passed"]) ? 1 : 0,
880  (!$mark["passed"]) ? 1 : 0,
881  time()
882  )
883  );
884  }
885 
886  function _updateTestPassResults($active_id, $pass)
887  {
888  global $ilDB;
889  include_once "./Modules/Test/classes/class.ilObjTest.php";
892  // update test pass results
893  $result = $ilDB->queryF("SELECT SUM(points) reachedpoints, COUNT(question_fi) answeredquestions FROM tst_test_result WHERE active_fi = %s AND pass = %s",
894  array('integer','integer'),
895  array($active_id, $pass)
896  );
897  if ($result->numRows() > 0)
898  {
899  $row = $ilDB->fetchAssoc($result);
900  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_pass_result WHERE active_fi = %s AND pass = %s",
901  array('integer','integer'),
902  array($active_id, $pass)
903  );
904  $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)",
905  array(
906  'integer',
907  'integer',
908  'float',
909  'float',
910  'integer',
911  'integer',
912  'integer',
913  'integer'
914  ),
915  array(
916  $active_id,
917  strlen($pass) ? $pass : 0,
918  ($row["reachedpoints"]) ? $row["reachedpoints"] : 0,
919  $data["points"],
920  $data["count"],
921  $row["answeredquestions"],
922  $time,
923  time()
924  )
925  );
926  }
928  return array(
929  'active_fi' => $active_id,
930  'pass' => $pass,
931  'points' => ($row["reachedpoints"]) ? $row["reachedpoints"] : 0,
932  'maxpoints' => $data["points"],
933  'questioncount' => $data["count"],
934  'answeredquestions' => $row["answeredquestions"],
935  'workingtime' => $time,
936  'tstamp' => time()
937  );
938  }
939 
947  function logAction($logtext = "", $active_id = "", $question_id = "")
948  {
949  global $ilUser;
950 
951  $original_id = "";
952  if (strcmp($question_id, "") != 0)
953  {
954  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
956  }
957  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
958  include_once "./Modules/Test/classes/class.ilObjTest.php";
959  ilObjAssessmentFolder::_addLog($ilUser->id, ilObjTest::_getObjectIDFromActiveID($active_id), $logtext, $question_id, $original_id);
960  }
961 
969  function _logAction($logtext = "", $active_id = "", $question_id = "")
970  {
971  global $ilUser;
972 
973  $original_id = "";
974  if (strcmp($question_id, "") != 0)
975  {
976  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
978  }
979  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
980  include_once "./Modules/Test/classes/class.ilObjTest.php";
981  ilObjAssessmentFolder::_addLog($ilUser->id, ilObjTest::_getObjectIDFromActiveID($active_id), $logtext, $question_id, $original_id);
982  }
983 
991  function moveUploadedMediaFile($file, $name)
992  {
993  $mediatempdir = CLIENT_WEB_DIR . "/assessment/temp";
994  if (!@is_dir($mediatempdir)) ilUtil::createDirectory($mediatempdir);
995  $temp_name = tempnam($mediatempdir, $name . "_____");
996  $temp_name = str_replace("\\", "/", $temp_name);
997  @unlink($temp_name);
998  if (!ilUtil::moveUploadedFile($file, $name, $temp_name))
999  {
1000  return FALSE;
1001  }
1002  else
1003  {
1004  return $temp_name;
1005  }
1006  }
1007 
1014  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/solution/";
1015  }
1016 
1023  function getJavaPath() {
1024  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/java/";
1025  }
1026 
1033  function getImagePath($question_id = null, $object_id = null)
1034  {
1035  if( $question_id === null)
1036  {
1037  $question_id = $this->id;
1038  }
1039 
1040  if( $object_id === null)
1041  {
1042  $object_id = $this->obj_id;
1043  }
1044 
1045  return CLIENT_WEB_DIR . "/assessment/$object_id/$question_id/images/";
1046  }
1047 
1054  function getFlashPath()
1055  {
1056  return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/flash/";
1057  }
1058 
1065  function getJavaPathWeb()
1066  {
1067  include_once "./Services/Utilities/classes/class.ilUtil.php";
1068  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/java/";
1070  }
1071 
1078  {
1079  include_once "./Services/Utilities/classes/class.ilUtil.php";
1080  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/solution/";
1082  }
1083 
1090  function getImagePathWeb()
1091  {
1092  if(!$this->export_image_path)
1093  {
1094  include_once "./Services/Utilities/classes/class.ilUtil.php";
1095  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/images/";
1097  }
1098  else
1099  {
1100  return $this->export_image_path;
1101  }
1102  }
1103 
1110  function getFlashPathWeb()
1111  {
1112  include_once "./Services/Utilities/classes/class.ilUtil.php";
1113  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/flash/";
1115  }
1116 
1124  function &getSolutionValues($active_id, $pass = NULL)
1125  {
1126  global $ilDB;
1127 
1128  $values = array();
1129 
1130  if (is_null($pass))
1131  {
1132  $pass = $this->getSolutionMaxPass($active_id);
1133  }
1134 
1135  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s ORDER BY solution_id",
1136  array('integer','integer','integer'),
1137  array($active_id, $this->getId(), $pass)
1138  );
1139  while ($row = $ilDB->fetchAssoc($result))
1140  {
1141  array_push($values, $row);
1142  }
1143 
1144  return $values;
1145  }
1146 
1153  function isInUse($question_id = "")
1154  {
1155  global $ilDB;
1156 
1157  if ($question_id < 1) $question_id = $this->getId();
1158  $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",
1159  array('integer'),
1160  array($question_id)
1161  );
1162  $row = $ilDB->fetchAssoc($result);
1163  $count = $row["question_count"];
1164 
1165  $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",
1166  array('integer'),
1167  array($question_id)
1168  );
1169  $count += $result->numRows();
1170 
1171  return $count;
1172  }
1173 
1180  function isClone($question_id = "")
1181  {
1182  global $ilDB;
1183 
1184  if ($question_id < 1) $question_id = $this->id;
1185  $result = $ilDB->queryF("SELECT original_id FROM qpl_questions WHERE question_id = %s",
1186  array('integer'),
1187  array($question_id)
1188  );
1189  $row = $ilDB->fetchAssoc($result);
1190  return ($row["original_id"] > 0) ? TRUE : FALSE;
1191  }
1192 
1199  function pcArrayShuffle($array)
1200  {
1201  $keys = array_keys($array);
1202  shuffle($keys);
1203  $result = array();
1204  foreach ($keys as $key)
1205  {
1206  $result[$key] = $array[$key];
1207  }
1208  return $result;
1209  }
1210 
1216  function getQuestionTypeFromDb($question_id)
1217  {
1218  global $ilDB;
1219 
1220  $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",
1221  array('integer'),
1222  array($question_id)
1223  );
1224  $data = $ilDB->fetchAssoc($result);
1225  return $data["type_tag"];
1226  }
1227 
1235  {
1236  return "";
1237  }
1238 
1246  {
1247  return "";
1248  }
1249 
1256  function deleteAnswers($question_id)
1257  {
1258  global $ilDB;
1259  $answer_table_name = $this->getAnswerTableName();
1260  if (is_array($answer_table_name))
1261  {
1262  foreach ($answer_table_name as $table)
1263  {
1264  if (strlen($table))
1265  {
1266  $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1267  array('integer'),
1268  array($question_id)
1269  );
1270  }
1271  }
1272  }
1273  else
1274  {
1275  if (strlen($answer_table_name))
1276  {
1277  $affectedRows = $ilDB->manipulateF("DELETE FROM $answer_table_name WHERE question_fi = %s",
1278  array('integer'),
1279  array($question_id)
1280  );
1281  }
1282  }
1283  }
1284 
1291  function deleteAdditionalTableData($question_id)
1292  {
1293  global $ilDB;
1294  $additional_table_name = $this->getAdditionalTableName();
1295  if (is_array($additional_table_name))
1296  {
1297  foreach ($additional_table_name as $table)
1298  {
1299  if (strlen($table))
1300  {
1301  $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1302  array('integer'),
1303  array($question_id)
1304  );
1305  }
1306  }
1307  }
1308  else
1309  {
1310  if (strlen($additional_table_name))
1311  {
1312  $affectedRows = $ilDB->manipulateF("DELETE FROM $additional_table_name WHERE question_fi = %s",
1313  array('integer'),
1314  array($question_id)
1315  );
1316  }
1317  }
1318  }
1319 
1326  protected function deletePageOfQuestion($question_id)
1327  {
1328  include_once "./Services/COPage/classes/class.ilPageObject.php";
1329  $page = new ilPageObject("qpl", $question_id);
1330  $page->delete();
1331  return true;
1332  }
1333 
1340  public function delete($question_id)
1341  {
1342  global $ilDB, $ilLog;
1343 
1344  if ($question_id < 1) return true; // nothing to do
1345 
1346  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1347  array('integer'),
1348  array($question_id)
1349  );
1350  if ($result->numRows() == 1)
1351  {
1352  $row = $ilDB->fetchAssoc($result);
1353  $obj_id = $row["obj_fi"];
1354  }
1355  else
1356  {
1357  return true; // nothing to do
1358  }
1359  try
1360  {
1361  $this->deletePageOfQuestion($question_id);
1362  }
1363  catch (Exception $e)
1364  {
1365  $ilLog->write("EXCEPTION: Could not delete page of question $question_id: $e");
1366  return false;
1367  }
1368 
1369  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_questions WHERE question_id = %s",
1370  array('integer'),
1371  array($question_id)
1372  );
1373  if ($affectedRows == 0) return false;
1374 
1375  try
1376  {
1377  $this->deleteAdditionalTableData($question_id);
1378  $this->deleteAnswers($question_id);
1379  }
1380  catch (Exception $e)
1381  {
1382  $ilLog->write("EXCEPTION: Could not delete additional table data of question $question_id: $e");
1383  return false;
1384  }
1385 
1386  try
1387  {
1388  // delete the question in the tst_test_question table (list of test questions)
1389  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_question WHERE question_fi = %s",
1390  array('integer'),
1391  array($question_id)
1392  );
1393  }
1394  catch (Exception $e)
1395  {
1396  $ilLog->write("EXCEPTION: Could not delete delete question $question_id from a test: $e");
1397  return false;
1398  }
1399 
1400  try
1401  {
1402  // delete suggested solutions contained in the question
1403  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
1404  array('integer'),
1405  array($question_id)
1406  );
1407  }
1408  catch (Exception $e)
1409  {
1410  $ilLog->write("EXCEPTION: Could not delete suggested solutions of question $question_id: $e");
1411  return false;
1412  }
1413 
1414  try
1415  {
1416  $directory = CLIENT_WEB_DIR . "/assessment/" . $obj_id . "/$question_id";
1417  if (preg_match("/\d+/", $obj_id) and preg_match("/\d+/", $question_id) and is_dir($directory))
1418  {
1419  include_once "./Services/Utilities/classes/class.ilUtil.php";
1420  ilUtil::delDir($directory);
1421  }
1422  }
1423  catch (Exception $e)
1424  {
1425  $ilLog->write("EXCEPTION: Could not delete question file directory $directory of question $question_id: $e");
1426  return false;
1427  }
1428 
1429  try
1430  {
1431  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1432  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $question_id);
1433  // remaining usages are not in text anymore -> delete them
1434  // and media objects (note: delete method of ilObjMediaObject
1435  // checks whether object is used in another context; if yes,
1436  // the object is not deleted!)
1437  foreach($mobs as $mob)
1438  {
1439  ilObjMediaObject::_removeUsage($mob, "qpl:html", $question_id);
1440  if (ilObjMediaObject::_exists($mob))
1441  {
1442  $mob_obj =& new ilObjMediaObject($mob);
1443  $mob_obj->delete();
1444  }
1445  }
1446  }
1447  catch (Exception $e)
1448  {
1449  $ilLog->write("EXCEPTION: Error deleting the media objects of question $question_id: $e");
1450  return false;
1451  }
1452 
1453  try
1454  {
1455  // update question count of question pool
1456  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1458  }
1459  catch (Exception $e)
1460  {
1461  $ilLog->write("EXCEPTION: Error updating the question pool question count of question pool " . $this->getObjId() . " when deleting question $question_id: $e");
1462  return false;
1463  }
1464  return true;
1465  }
1466 
1470  function getTotalAnswers()
1471  {
1472  return $this->_getTotalAnswers($this->id);
1473  }
1474 
1481  function _getTotalAnswers($a_q_id)
1482  {
1483  global $ilDB;
1484 
1485  // get all question references to the question id
1486  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
1487  array('integer','integer'),
1488  array($a_q_id, $a_q_id)
1489  );
1490  if ($result->numRows() == 0)
1491  {
1492  return 0;
1493  }
1494  $found_id = array();
1495  while ($row = $ilDB->fetchAssoc($result))
1496  {
1497  array_push($found_id, $row["question_id"]);
1498  }
1499 
1500  $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
1501 
1502  return $result->numRows();
1503  }
1504 
1505 
1512  function _getTotalRightAnswers($a_q_id)
1513  {
1514  global $ilDB;
1515  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
1516  array('integer','integer'),
1517  array($a_q_id, $a_q_id)
1518  );
1519  if ($result->numRows() == 0)
1520  {
1521  return 0;
1522  }
1523  $found_id = array();
1524  while ($row = $ilDB->fetchAssoc($result))
1525  {
1526  array_push($found_id, $row["question_id"]);
1527  }
1528  $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
1529  $answers = array();
1530  while ($row = $ilDB->fetchAssoc($result))
1531  {
1532  $reached = $row["points"];
1533  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1534  $max = assQuestion::_getMaximumPoints($row["question_fi"]);
1535  array_push($answers, array("reached" => $reached, "max" => $max));
1536  }
1537  $max = 0.0;
1538  $reached = 0.0;
1539  foreach ($answers as $key => $value)
1540  {
1541  $max += $value["max"];
1542  $reached += $value["reached"];
1543  }
1544  if ($max > 0)
1545  {
1546  return $reached / $max;
1547  }
1548  else
1549  {
1550  return 0;
1551  }
1552  }
1553 
1559  function _getTitle($a_q_id)
1560  {
1561  global $ilDB;
1562  $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE question_id = %s",
1563  array('integer'),
1564  array($a_q_id)
1565  );
1566  if ($result->numRows() == 1)
1567  {
1568  $row = $ilDB->fetchAssoc($result);
1569  return $row["title"];
1570  }
1571  else
1572  {
1573  return "";
1574  }
1575  }
1576 
1582  function _getQuestionText($a_q_id)
1583  {
1584  global $ilDB;
1585  $result = $ilDB->queryF("SELECT question_text FROM qpl_questions WHERE question_id = %s",
1586  array('integer'),
1587  array($a_q_id)
1588  );
1589  if ($result->numRows() == 1)
1590  {
1591  $row = $ilDB->fetchAssoc($result);
1592  return $row["question_text"];
1593  }
1594  else
1595  {
1596  return "";
1597  }
1598  }
1599 
1600 
1602  {
1603  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1604  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $a_q_id);
1605  foreach ($mobs as $mob)
1606  {
1607  ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->getId());
1608  }
1609  }
1610 
1612  {
1613  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1614  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1615  foreach ($mobs as $mob)
1616  {
1617  ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->original_id);
1618  }
1619  }
1620 
1624  function createPageObject()
1625  {
1626  $qpl_id = $this->getObjId();
1627 
1628  include_once "./Services/COPage/classes/class.ilPageObject.php";
1629  $this->page = new ilPageObject("qpl", 0);
1630  $this->page->setId($this->getId());
1631  $this->page->setParentId($qpl_id);
1632  $this->page->setXMLContent("<PageObject><PageContent>".
1633  "<Question QRef=\"il__qst_".$this->getId()."\"/>".
1634  "</PageContent></PageObject>");
1635  $this->page->create();
1636  }
1637 
1638  function copyPageOfQuestion($a_q_id)
1639  {
1640  if ($a_q_id > 0)
1641  {
1642  include_once "./Services/COPage/classes/class.ilPageObject.php";
1643  $page = new ilPageObject("qpl", $a_q_id);
1644 
1645  $xml = str_replace("il__qst_".$a_q_id, "il__qst_".$this->id, $page->getXMLContent());
1646  $this->page->setXMLContent($xml);
1647  $this->page->saveMobUsage($xml);
1648  $this->page->updateFromXML();
1649  }
1650  }
1651 
1653  {
1654  include_once "./Services/COPage/classes/class.ilPageObject.php";
1655  $page = new ilPageObject("qpl", $this->id);
1656  return $page->getXMLContent();
1657  }
1658 
1666  function _getQuestionType($question_id)
1667  {
1668  global $ilDB;
1669 
1670  if ($question_id < 1) return "";
1671  $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",
1672  array('integer'),
1673  array($question_id)
1674  );
1675  if ($result->numRows() == 1)
1676  {
1677  $data = $ilDB->fetchAssoc($result);
1678  return $data["type_tag"];
1679  }
1680  else
1681  {
1682  return "";
1683  }
1684  }
1685 
1693  function _getQuestionTitle($question_id)
1694  {
1695  global $ilDB;
1696 
1697  if ($question_id < 1) return "";
1698 
1699  $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE qpl_questions.question_id = %s",
1700  array('integer'),
1701  array($question_id)
1702  );
1703  if ($result->numRows() == 1)
1704  {
1705  $data = $ilDB->fetchAssoc($result);
1706  return $data["title"];
1707  }
1708  else
1709  {
1710  return "";
1711  }
1712  }
1713 
1715  {
1716  $this->original_id = $original_id;
1717  }
1718 
1719  function getOriginalId()
1720  {
1721  return $this->original_id;
1722  }
1723 
1730  function loadFromDb($question_id)
1731  {
1732  global $ilDB;
1733 
1734  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
1735  array('integer'),
1736  array($this->getId())
1737  );
1738  $this->suggested_solutions = array();
1739  if ($result->numRows())
1740  {
1741  include_once("./Services/RTE/classes/class.ilRTE.php");
1742  while ($row = $ilDB->fetchAssoc($result))
1743  {
1744  $value = (is_array(unserialize($row["value"]))) ? unserialize($row["value"]) : ilRTE::_replaceMediaObjectImageSrc($row["value"], 1);
1745  $this->suggested_solutions[$row["subquestion_index"]] = array(
1746  "type" => $row["type"],
1747  "value" => $value,
1748  "internal_link" => $row["internal_link"],
1749  "import_id" => $row["import_id"]
1750  );
1751  }
1752  }
1753  }
1754 
1761  public function createNewQuestion($a_create_page = true)
1762  {
1763  global $ilDB, $ilUser;
1764 
1765  $complete = "0";
1766  $estw_time = $this->getEstimatedWorkingTime();
1767  $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
1768  $obj_id = ($this->getObjId() <= 0) ? (ilObject::_lookupObjId((strlen($_GET["ref_id"])) ? $_GET["ref_id"] : $_POST["sel_qpl"])) : $this->getObjId();
1769  if ($obj_id > 0)
1770  {
1771  if($a_create_page)
1772  {
1773  $tstamp = 0;
1774  }
1775  else
1776  {
1777  // question pool must not try to purge
1778  $tstamp = time();
1779  }
1780 
1781  $next_id = $ilDB->nextId('qpl_questions');
1782  $affectedRows = $ilDB->insert("qpl_questions", array(
1783  "question_id" => array("integer", $next_id),
1784  "question_type_fi" => array("integer", $this->getQuestionTypeID()),
1785  "obj_fi" => array("integer", $obj_id),
1786  "title" => array("text", NULL),
1787  "description" => array("text", NULL),
1788  "author" => array("text", $this->getAuthor()),
1789  "owner" => array("integer", $ilUser->getId()),
1790  "question_text" => array("clob", NULL),
1791  "points" => array("float", 0),
1792  "nr_of_tries" => array("integer", 1),
1793  "working_time" => array("text", $estw_time),
1794  "complete" => array("text", $complete),
1795  "created" => array("integer", time()),
1796  "original_id" => array("integer", NULL),
1797  "tstamp" => array("integer", $tstamp)
1798  ));
1799  $this->setId($next_id);
1800 
1801  if($a_create_page)
1802  {
1803  // create page object of question
1804  $this->createPageObject();
1805  }
1806  }
1807  return $this->getId();
1808  }
1809 
1810  public function saveQuestionDataToDb($original_id = "")
1811  {
1812  global $ilDB;
1813 
1814  $estw_time = $this->getEstimatedWorkingTime();
1815  $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
1816 
1817  // cleanup RTE images which are not inserted into the question text
1818  include_once("./Services/RTE/classes/class.ilRTE.php");
1819  if ($this->getId() == -1)
1820  {
1821  // Neuen Datensatz schreiben
1822  $next_id = $ilDB->nextId('qpl_questions');
1823  $affectedRows = $ilDB->insert("qpl_questions", array(
1824  "question_id" => array("integer", $next_id),
1825  "question_type_fi" => array("integer", $this->getQuestionTypeID()),
1826  "obj_fi" => array("integer", $this->getObjId()),
1827  "title" => array("text", $this->getTitle()),
1828  "description" => array("text", $this->getComment()),
1829  "author" => array("text", $this->getAuthor()),
1830  "owner" => array("integer", $this->getOwner()),
1831  "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
1832  "points" => array("float", $this->getMaximumPoints()),
1833  "working_time" => array("text", $estw_time),
1834  "nr_of_tries" => array("integer", (strlen($this->getNrOfTries())) ? $this->getNrOfTries() : 1),
1835  "created" => array("integer", time()),
1836  "original_id" => array("integer", ($original_id) ? $original_id : NULL),
1837  "tstamp" => array("integer", time())
1838  ));
1839  $this->setId($next_id);
1840  // create page object of question
1841  $this->createPageObject();
1842  }
1843  else
1844  {
1845  // Vorhandenen Datensatz aktualisieren
1846  $affectedRows = $ilDB->update("qpl_questions", array(
1847  "obj_fi" => array("integer", $this->getObjId()),
1848  "title" => array("text", $this->getTitle()),
1849  "description" => array("text", $this->getComment()),
1850  "author" => array("text", $this->getAuthor()),
1851  "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
1852  "points" => array("float", $this->getMaximumPoints()),
1853  "nr_of_tries" => array("integer", (strlen($this->getNrOfTries())) ? $this->getNrOfTries() : 1),
1854  "working_time" => array("text", $estw_time),
1855  "tstamp" => array("integer", time())
1856  ), array(
1857  "question_id" => array("integer", $this->getId())
1858  ));
1859  }
1860  }
1861 
1868  function saveToDb($original_id = "")
1869  {
1870  global $ilDB;
1871 
1872  $this->updateSuggestedSolutions();
1873 
1874  // remove unused media objects from ILIAS
1875  $this->cleanupMediaObjectUsage();
1876 
1877  $complete = "0";
1878  if ($this->isComplete())
1879  {
1880  $complete = "1";
1881  }
1882 
1883  // update the question time stamp and completion status
1884  $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET tstamp = %s, owner = %s, complete = %s WHERE question_id = %s",
1885  array('integer','integer', 'integer','text'),
1886  array(time(), ($this->getOwner() <= 0) ? $this->ilias->account->id : $this->getOwner(), $complete, $this->getId())
1887  );
1888 
1889  // update question count of question pool
1890  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1892  }
1893 
1894  public function setNewOriginalId($newId) {
1895  global $ilDB;
1896  $ilDB->manipulateF("UPDATE qpl_questions SET tstamp = %s, original_id = %s WHERE question_id = %s",
1897  array('integer','integer', 'text'),
1898  array(time(), $newId, $this->getId())
1899  );
1900  }
1901 
1905  protected function onDuplicate($originalParentId, $originalQuestionId, $duplicateParentId, $duplicateQuestionId)
1906  {
1907  $this->duplicateSuggestedSolutionFiles($originalParentId, $originalQuestionId);
1908  }
1909 
1913  protected function onCopy($source_questionpool_id, $source_question_id)
1914  {
1915  $this->copySuggestedSolutionFiles($source_questionpool_id, $source_question_id);
1916  }
1917 
1921  public function deleteSuggestedSolutions()
1922  {
1923  global $ilDB;
1924  // delete the links in the qpl_sol_sug table
1925  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
1926  array('integer'),
1927  array($this->getId())
1928  );
1929  // delete the links in the int_link table
1930  include_once "./Services/COPage/classes/class.ilInternalLink.php";
1932  $this->suggested_solutions = array();
1934  }
1935 
1943  function getSuggestedSolution($subquestion_index = 0)
1944  {
1945  if (array_key_exists($subquestion_index, $this->suggested_solutions))
1946  {
1947  return $this->suggested_solutions[$subquestion_index];
1948  }
1949  else
1950  {
1951  return array();
1952  }
1953  }
1954 
1963  function getSuggestedSolutionTitle($subquestion_index = 0)
1964  {
1965  if (array_key_exists($subquestion_index, $this->suggested_solutions))
1966  {
1967  $title = $this->suggested_solutions[$subquestion_index]["internal_link"];
1968  // TO DO: resolve internal link an get link type and title
1969  }
1970  else
1971  {
1972  $title = "";
1973  }
1974  return $title;
1975  }
1976 
1986  function setSuggestedSolution($solution_id = "", $subquestion_index = 0, $is_import = false)
1987  {
1988  if (strcmp($solution_id, "") != 0)
1989  {
1990  $import_id = "";
1991  if ($is_import)
1992  {
1993  $import_id = $solution_id;
1994  $solution_id = $this->_resolveInternalLink($import_id);
1995  }
1996  $this->suggested_solutions[$subquestion_index] = array(
1997  "internal_link" => $solution_id,
1998  "import_id" => $import_id
1999  );
2000  }
2001  }
2002 
2006  protected function duplicateSuggestedSolutionFiles($parent_id, $question_id)
2007  {
2008  global $ilLog;
2009 
2010  foreach ($this->suggested_solutions as $index => $solution)
2011  {
2012  if (strcmp($solution["type"], "file") == 0)
2013  {
2014  $filepath = $this->getSuggestedSolutionPath();
2015  $filepath_original = str_replace(
2016  "/{$this->obj_id}/{$this->id}/solution",
2017  "/$parent_id/$question_id/solution",
2018  $filepath
2019  );
2020  if (!file_exists($filepath))
2021  {
2022  ilUtil::makeDirParents($filepath);
2023  }
2024  $filename = $solution["value"]["name"];
2025  if (strlen($filename))
2026  {
2027  if (!copy($filepath_original . $filename, $filepath . $filename))
2028  {
2029  $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
2030  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2031  }
2032  }
2033  }
2034  }
2035  }
2036 
2041  {
2042  global $ilLog;
2043 
2044  $filepath = $this->getSuggestedSolutionPath();
2045  $filepath_original = str_replace("/$this->id/solution", "/$original_id/solution", $filepath);
2046  ilUtil::delDir($filepath_original);
2047  foreach ($this->suggested_solutions as $index => $solution)
2048  {
2049  if (strcmp($solution["type"], "file") == 0)
2050  {
2051  if (!file_exists($filepath_original))
2052  {
2053  ilUtil::makeDirParents($filepath_original);
2054  }
2055  $filename = $solution["value"]["name"];
2056  if (strlen($filename))
2057  {
2058  if (!@copy($filepath . $filename, $filepath_original . $filename))
2059  {
2060  $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
2061  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2062  }
2063  }
2064  }
2065  }
2066  }
2067 
2068  protected function copySuggestedSolutionFiles($source_questionpool_id, $source_question_id)
2069  {
2070  global $ilLog;
2071 
2072  foreach ($this->suggested_solutions as $index => $solution)
2073  {
2074  if (strcmp($solution["type"], "file") == 0)
2075  {
2076  $filepath = $this->getSuggestedSolutionPath();
2077  $filepath_original = str_replace("/$this->obj_id/$this->id/solution", "/$source_questionpool_id/$source_question_id/solution", $filepath);
2078  if (!file_exists($filepath))
2079  {
2080  ilUtil::makeDirParents($filepath);
2081  }
2082  $filename = $solution["value"]["name"];
2083  if (strlen($filename))
2084  {
2085  if (!copy($filepath_original . $filename, $filepath . $filename))
2086  {
2087  $ilLog->write("File could not be copied!!!!", $ilLog->ERROR);
2088  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2089  }
2090  }
2091  }
2092  }
2093  }
2094 
2098  public function updateSuggestedSolutions($original_id = "")
2099  {
2100  global $ilDB;
2101 
2102  $id = (strlen($original_id) && is_numeric($original_id)) ? $original_id : $this->getId();
2103  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2104  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
2105  array('integer'),
2106  array($id)
2107  );
2109  include_once("./Services/RTE/classes/class.ilRTE.php");
2110  foreach ($this->suggested_solutions as $index => $solution)
2111  {
2112  $next_id = $ilDB->nextId('qpl_sol_sug');
2113 
2115  $ilDB->insert('qpl_sol_sug', array(
2116  'suggested_solution_id' => array( 'integer', $next_id ),
2117  'question_fi' => array( 'integer', $id ),
2118  'type' => array( 'text', $solution['type'] ),
2119  'value' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( (is_array( $solution['value'] ) ) ? serialize( $solution[ 'value' ] ) : $solution['value'], 0 ) ),
2120  'internal_link' => array( 'text', $solution['internal_link'] ),
2121  'import_id' => array( 'text', null ),
2122  'subquestion_index' => array( 'integer', $index ),
2123  'tstamp' => array( 'integer', time() ),
2124  )
2125  );
2126 
2127  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
2128  {
2129  ilInternalLink::_saveLink("qst", $id, $matches[2], $matches[3], $matches[1]);
2130  }
2131  }
2132  if (strlen($original_id) && is_numeric($original_id)) $this->syncSuggestedSolutionFiles($id);
2133  $this->cleanupMediaObjectUsage();
2134  }
2135 
2145  function saveSuggestedSolution($type, $solution_id = "", $subquestion_index = 0, $value = "")
2146  {
2147  global $ilDB;
2148 
2149  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
2150  array("integer", "integer"),
2151  array(
2152  $this->getId(),
2153  $subquestion_index
2154  )
2155  );
2156 
2157  $next_id = $ilDB->nextId('qpl_sol_sug');
2158  include_once("./Services/RTE/classes/class.ilRTE.php");
2160  $affectedRows = $ilDB->insert('qpl_sol_sug', array(
2161  'suggested_solution_id' => array( 'integer', $next_id ),
2162  'question_fi' => array( 'integer', $this->getId() ),
2163  'type' => array( 'text', $type ),
2164  'value' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( (is_array( $value ) ) ? serialize( $value ) : $value, 0 ) ),
2165  'internal_link' => array( 'text', $solution_id ),
2166  'import_id' => array( 'text', null ),
2167  'subquestion_index' => array( 'integer', $subquestion_index ),
2168  'tstamp' => array( 'integer', time() ),
2169  )
2170  );
2171 
2172  if ($affectedRows == 1)
2173  {
2174  $this->suggested_solutions["subquestion_index"] = array(
2175  "type" => $type,
2176  "value" => $value,
2177  "internal_link" => $solution_id,
2178  "import_id" => ""
2179  );
2180  }
2181  $this->cleanupMediaObjectUsage();
2182  }
2183 
2184  function _resolveInternalLink($internal_link)
2185  {
2186  if (preg_match("/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches))
2187  {
2188  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2189  include_once "./Modules/LearningModule/classes/class.ilLMObject.php";
2190  include_once "./Modules/Glossary/classes/class.ilGlossaryTerm.php";
2191  switch ($matches[2])
2192  {
2193  case "lm":
2194  $resolved_link = ilLMObject::_getIdForImportId($internal_link);
2195  break;
2196  case "pg":
2197  $resolved_link = ilInternalLink::_getIdForImportId("PageObject", $internal_link);
2198  break;
2199  case "st":
2200  $resolved_link = ilInternalLink::_getIdForImportId("StructureObject", $internal_link);
2201  break;
2202  case "git":
2203  $resolved_link = ilInternalLink::_getIdForImportId("GlossaryItem", $internal_link);
2204  break;
2205  case "mob":
2206  $resolved_link = ilInternalLink::_getIdForImportId("MediaObject", $internal_link);
2207  break;
2208  }
2209  if (strcmp($resolved_link, "") == 0)
2210  {
2211  $resolved_link = $internal_link;
2212  }
2213  }
2214  else
2215  {
2216  $resolved_link = $internal_link;
2217  }
2218  return $resolved_link;
2219  }
2220 
2221  function _resolveIntLinks($question_id)
2222  {
2223  global $ilDB;
2224  $resolvedlinks = 0;
2225  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2226  array('integer'),
2227  array($question_id)
2228  );
2229  if ($result->numRows())
2230  {
2231  while ($row = $ilDB->fetchAssoc($result))
2232  {
2233  $internal_link = $row["internal_link"];
2234  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2235  $resolved_link = assQuestion::_resolveInternalLink($internal_link);
2236  if (strcmp($internal_link, $resolved_link) != 0)
2237  {
2238  // internal link was resolved successfully
2239  $affectedRows = $ilDB->manipulateF("UPDATE qpl_sol_sug SET internal_link = %s WHERE suggested_solution_id = %s",
2240  array('text','integer'),
2241  array($resolved_link, $row["suggested_solution_id"])
2242  );
2243  $resolvedlinks++;
2244  }
2245  }
2246  }
2247  if ($resolvedlinks)
2248  {
2249  // there are resolved links -> reenter theses links to the database
2250 
2251  // delete all internal links from the database
2252  include_once "./Services/COPage/classes/class.ilInternalLink.php";
2253  ilInternalLink::_deleteAllLinksOfSource("qst", $question_id);
2254 
2255  $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2256  array('integer'),
2257  array($question_id)
2258  );
2259  if ($result->numRows())
2260  {
2261  while ($row = $ilDB->fetchAssoc($result))
2262  {
2263  if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $row["internal_link"], $matches))
2264  {
2265  ilInternalLink::_saveLink("qst", $question_id, $matches[2], $matches[3], $matches[1]);
2266  }
2267  }
2268  }
2269  }
2270  }
2271 
2272  function _getInternalLinkHref($target = "")
2273  {
2274  global $ilDB;
2275  $linktypes = array(
2276  "lm" => "LearningModule",
2277  "pg" => "PageObject",
2278  "st" => "StructureObject",
2279  "git" => "GlossaryItem",
2280  "mob" => "MediaObject"
2281  );
2282  $href = "";
2283  if (preg_match("/il__(\w+)_(\d+)/", $target, $matches))
2284  {
2285  $type = $matches[1];
2286  $target_id = $matches[2];
2287  include_once "./Services/Utilities/classes/class.ilUtil.php";
2288  switch($linktypes[$matches[1]])
2289  {
2290  case "LearningModule":
2291  $href = "./goto.php?target=" . $type . "_" . $target_id;
2292  break;
2293  case "PageObject":
2294  case "StructureObject":
2295  $href = "./goto.php?target=" . $type . "_" . $target_id;
2296  break;
2297  case "GlossaryItem":
2298  $href = "./goto.php?target=" . $type . "_" . $target_id;
2299  break;
2300  case "MediaObject":
2301  $href = "./ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[$type] . "&cmd=media&ref_id=".$_GET["ref_id"]."&mob_id=".$target_id;
2302  break;
2303  }
2304  }
2305  return $href;
2306  }
2307 
2315  function _getOriginalId($question_id)
2316  {
2317  global $ilDB;
2318  $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE question_id = %s",
2319  array('integer'),
2320  array($question_id)
2321  );
2322  if ($result->numRows() > 0)
2323  {
2324  $row = $ilDB->fetchAssoc($result);
2325  if ($row["original_id"] > 0)
2326  {
2327  return $row["original_id"];
2328  }
2329  else
2330  {
2331  return $row["question_id"];
2332  }
2333  }
2334  else
2335  {
2336  return "";
2337  }
2338  }
2339 
2340  function syncWithOriginal()
2341  {
2342  global $ilDB;
2343 
2344  if( !$this->getOriginalId() )
2345  {
2346  return;
2347  }
2348 
2349  $originalObjId = self::lookupOriginalParentObjId($this->getOriginalId());
2350 
2351  if ( !$originalObjId )
2352  {
2353  return;
2354  }
2355 
2356  $id = $this->getId();
2357  $original = $this->getOriginalId();
2358 
2359  $this->setId($this->getOriginalId());
2360  $this->setOriginalId(NULL);
2361  $this->setObjId($originalObjId);
2362  $this->saveToDb();
2363  $this->deletePageOfQuestion($original);
2364  $this->createPageObject();
2365  $this->copyPageOfQuestion($id);
2366 
2367  $this->setId($id);
2368  $this->setOriginalId($original);
2369  $this->updateSuggestedSolutions($original);
2370  $this->syncFeedbackGeneric();
2372  }
2373 
2382  public static function lookupOriginalParentObjId($originalQuestionId)
2383  {
2384  global $ilDB;
2385 
2386  $query = "SELECT obj_fi FROM qpl_questions WHERE question_id = %s";
2387 
2388  $res = $ilDB->queryF($query, array('integer'), array((int)$originalQuestionId));
2389  $row = $ilDB->fetchAssoc($res);
2390 
2391  return $row['obj_fi'];
2392  }
2393 
2394  function createRandomSolution($test_id, $user_id)
2395  {
2396  }
2397 
2405  function _questionExists($question_id)
2406  {
2407  global $ilDB;
2408 
2409  if ($question_id < 1)
2410  {
2411  return false;
2412  }
2413 
2414  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE question_id = %s",
2415  array('integer'),
2416  array($question_id)
2417  );
2418  if ($result->numRows() == 1)
2419  {
2420  return true;
2421  }
2422  else
2423  {
2424  return false;
2425  }
2426  }
2427 
2435  function _questionExistsInPool($question_id)
2436  {
2437  global $ilDB;
2438 
2439  if ($question_id < 1)
2440  {
2441  return false;
2442  }
2443 
2444  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions INNER JOIN object_data ON obj_fi = obj_id WHERE question_id = %s AND type = 'qpl'",
2445  array('integer'),
2446  array($question_id)
2447  );
2448  if ($result->numRows() == 1)
2449  {
2450  return true;
2451  }
2452  else
2453  {
2454  return false;
2455  }
2456  }
2457 
2465  function &_instanciateQuestion($question_id)
2466  {
2467  if (strcmp($question_id, "") != 0)
2468  {
2469  $question_type = assQuestion::_getQuestionType($question_id);
2470  if (!strlen($question_type)) return null;
2471  assQuestion::_includeClass($question_type);
2472  $question = new $question_type();
2473  $question->loadFromDb($question_id);
2474  return $question;
2475  }
2476  }
2477 
2484  function getPoints()
2485  {
2486  if (strcmp($this->points, "") == 0)
2487  {
2488  return 0;
2489  }
2490  else
2491  {
2492  return $this->points;
2493  }
2494  }
2495 
2496 
2503  function setPoints($a_points)
2504  {
2505  $this->points = $a_points;
2506  }
2507 
2514  function getSolutionMaxPass($active_id)
2515  {
2516  return $this->_getSolutionMaxPass($this->getId(), $active_id);
2517  }
2518 
2525  function _getSolutionMaxPass($question_id, $active_id)
2526  {
2527 /* include_once "./Modules/Test/classes/class.ilObjTest.php";
2528  $pass = ilObjTest::_getPass($active_id);
2529  return $pass;*/
2530 
2531  // the following code was the old solution which added the non answered
2532  // questions of a pass from the answered questions of the previous pass
2533  // with the above solution, only the answered questions of the last pass are counted
2534  global $ilDB;
2535 
2536  $result = $ilDB->queryF("SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
2537  array('integer','integer'),
2538  array($active_id, $question_id)
2539  );
2540  if ($result->numRows() == 1)
2541  {
2542  $row = $ilDB->fetchAssoc($result);
2543  return $row["maxpass"];
2544  }
2545  else
2546  {
2547  return 0;
2548  }
2549  }
2550 
2559  function _isWriteable($question_id, $user_id)
2560  {
2561  global $ilDB;
2562 
2563  if (($question_id < 1) || ($user_id < 1))
2564  {
2565  return false;
2566  }
2567 
2568  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
2569  array('integer'),
2570  array($question_id)
2571  );
2572  if ($result->numRows() == 1)
2573  {
2574  $row = $ilDB->fetchAssoc($result);
2575  $qpl_object_id = $row["obj_fi"];
2576  include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
2577  return ilObjQuestionPool::_isWriteable($qpl_object_id, $user_id);
2578  }
2579  else
2580  {
2581  return false;
2582  }
2583  }
2584 
2591  function _isUsedInRandomTest($question_id = "")
2592  {
2593  global $ilDB;
2594 
2595  if ($question_id < 1) return 0;
2596  $result = $ilDB->queryF("SELECT test_random_question_id FROM tst_test_rnd_qst WHERE question_fi = %s",
2597  array('integer'),
2598  array($question_id)
2599  );
2600  return $result->numRows();
2601  }
2602 
2612  function calculateReachedPoints($active_id, $pass = NULL, $points = 0)
2613  {
2614  include_once "./Modules/Test/classes/class.ilObjTest.php";
2615  $count_system = ilObjTest::_getCountSystem($active_id);
2616  if ($count_system == 1)
2617  {
2618  if ($points != $this->getMaximumPoints())
2619  {
2620  $points = 0;
2621  }
2622  }
2623  $score_cutting = ilObjTest::_getScoreCutting($active_id);
2624  if ($score_cutting == 0)
2625  {
2626  if ($points < 0)
2627  {
2628  $points = 0;
2629  }
2630  }
2631  return $points;
2632  }
2633 
2642  public static function _isWorkedThrough($active_id, $question_id, $pass = NULL)
2643  {
2644  global $ilDB;
2645 
2646  $points = 0;
2647  if (is_null($pass))
2648  {
2649  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2650  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
2651  }
2652  $result = $ilDB->queryF("SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
2653  array('integer','integer','integer'),
2654  array($active_id, $question_id, $pass)
2655  );
2656  if ($result->numRows())
2657  {
2658  return TRUE;
2659  }
2660  else
2661  {
2662  return FALSE;
2663  }
2664  }
2665 
2673  public static function _areAnswered($a_user_id,$a_question_ids)
2674  {
2675  global $ilDB;
2676 
2677  $res = $ilDB->queryF("SELECT DISTINCT(question_fi) FROM tst_test_result JOIN tst_active ".
2678  "ON (active_id = active_fi) ".
2679  "WHERE " . $ilDB->in('question_fi', $a_question_ids, false, 'integer') .
2680  " AND user_fi = %s",
2681  array('integer'),
2682  array($a_user_id)
2683  );
2684  return ($res->numRows() == count($a_question_ids)) ? true : false;
2685  }
2686 
2694  function isHTML($a_text)
2695  {
2696  if (preg_match("/<[^>]*?>/", $a_text))
2697  {
2698  return TRUE;
2699  }
2700  else
2701  {
2702  return FALSE;
2703  }
2704  }
2705 
2712  function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE)
2713  {
2714  include_once "./Services/Utilities/classes/class.ilUtil.php";
2715  return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output);
2716  }
2717 
2725  function QTIMaterialToString($a_material)
2726  {
2727  $result = "";
2728  for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
2729  {
2730  $material = $a_material->getMaterial($i);
2731  if (strcmp($material["type"], "mattext") == 0)
2732  {
2733  $result .= $material["material"]->getContent();
2734  }
2735  if (strcmp($material["type"], "matimage") == 0)
2736  {
2737  $matimage = $material["material"];
2738  if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
2739  {
2740  // import an mediaobject which was inserted using tiny mce
2741  if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
2742  array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
2743  }
2744  }
2745  }
2746  return $result;
2747  }
2748 
2757  function addQTIMaterial(&$a_xml_writer, $a_material, $close_material_tag = TRUE, $add_mobs = TRUE)
2758  {
2759  include_once "./Services/RTE/classes/class.ilRTE.php";
2760  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
2761 
2762  $a_xml_writer->xmlStartTag("material");
2763  $attrs = array(
2764  "texttype" => "text/plain"
2765  );
2766  if ($this->isHTML($a_material))
2767  {
2768  $attrs["texttype"] = "text/xhtml";
2769  }
2770  $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
2771  if ($add_mobs)
2772  {
2773  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
2774  foreach ($mobs as $mob)
2775  {
2776  $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
2777  if (strpos($a_material, "mm_$mob") !== FALSE)
2778  {
2779  if (ilObjMediaObject::_exists($mob))
2780  {
2781  $mob_obj =& new ilObjMediaObject($mob);
2782  $imgattrs = array(
2783  "label" => $moblabel,
2784  "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
2785  );
2786  }
2787  $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
2788  }
2789  }
2790  }
2791  if ($close_material_tag) $a_xml_writer->xmlEndTag("material");
2792  }
2793 
2794  function createNewImageFileName($image_filename)
2795  {
2796  $extension = "";
2797  if (preg_match("/.*\.(png|jpg|gif|jpeg)$/i", $image_filename, $matches))
2798  {
2799  $extension = "." . $matches[1];
2800  }
2801  $image_filename = md5($image_filename) . $extension;
2802  return $image_filename;
2803  }
2804 
2815  function _setReachedPoints($active_id, $question_id, $points, $maxpoints, $pass = NULL, $manualscoring = FALSE)
2816  {
2817  global $ilDB;
2818 
2819  if ($points <= $maxpoints)
2820  {
2821  if (is_null($pass))
2822  {
2823  $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
2824  }
2825 
2826  // retrieve the already given points
2827  $old_points = 0;
2828  $result = $ilDB->queryF("SELECT points FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
2829  array('integer','integer','integer'),
2830  array($active_id, $question_id, $pass)
2831  );
2832  $manual = ($manualscoring) ? 1 : 0;
2833  if ($result->numRows())
2834  {
2835  $row = $ilDB->fetchAssoc($result);
2836  $old_points = $row["points"];
2837  $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",
2838  array('float', 'integer', 'integer', 'integer', 'integer', 'integer'),
2839  array($points, $manual, time(), $active_id, $question_id, $pass)
2840  );
2841  }
2842  else
2843  {
2844  $next_id = $ilDB->nextId('tst_test_result');
2845  $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)",
2846  array('integer', 'integer','integer', 'float', 'integer', 'integer','integer'),
2847  array($next_id, $active_id, $question_id, $points, $pass, $manual, time())
2848  );
2849  }
2851  // finally update objective result
2852  include_once "./Modules/Test/classes/class.ilObjTest.php";
2853  include_once './Modules/Course/classes/class.ilCourseObjectiveResult.php';
2855 
2856  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
2858  {
2859  global $lng, $ilUser;
2860  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
2861  $username = ilObjTestAccess::_getParticipantData($active_id);
2862  assQuestion::_logAction(sprintf($lng->txtlng("assessment", "log_answer_changed_points", ilObjAssessmentFolder::_getLogLanguage()), $username, $old_points, $points, $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")"), $active_id, $question_id);
2863  }
2864 
2865  return TRUE;
2866  }
2867  else
2868  {
2869  return FALSE;
2870  }
2871  }
2872 
2880  function getQuestion()
2881  {
2882  return $this->question;
2883  }
2884 
2892  function setQuestion($question = "")
2893  {
2894  $this->question = $question;
2895  }
2896 
2903  function getQuestionType()
2904  {
2905  // must be overwritten in every parent class
2906  return "";
2907  }
2908 
2918  {
2919  global $ilDB;
2920 
2921  $result = $ilDB->queryF("SELECT question_type_id FROM qpl_qst_type WHERE type_tag = %s",
2922  array('text'),
2923  array($this->getQuestionType())
2924  );
2925  if ($result->numRows() == 1)
2926  {
2927  $row = $ilDB->fetchAssoc($result);
2928  return $row["question_type_id"];
2929  }
2930  return 0;
2931  }
2932 
2942  function saveFeedbackGeneric($correctness, $feedback)
2943  {
2944  global $ilDB;
2945 
2946  switch ($correctness)
2947  {
2948  case 0:
2949  $correctness = 0;
2950  break;
2951  case 1:
2952  default:
2953  $correctness = 1;
2954  break;
2955  }
2956  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_generic WHERE question_fi = %s AND correctness = %s",
2957  array('integer', 'text'),
2958  array($this->getId(), $correctness)
2959  );
2960  if (strlen($feedback))
2961  {
2962  include_once("./Services/RTE/classes/class.ilRTE.php");
2963  $next_id = $ilDB->nextId('qpl_fb_generic');
2964 
2966  $ilDB->insert('qpl_fb_generic', array(
2967  'feedback_id' => array( 'integer', $next_id ),
2968  'question_fi' => array( 'integer', $this->getId() ),
2969  'correctness' => array( 'text', $correctness ),
2970  'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( $feedback, 0 ) ),
2971  'tstamp' => array( 'integer', time() ),
2972  )
2973  );
2974  }
2975  }
2976 
2986  function getFeedbackGeneric($correctness)
2987  {
2988  global $ilDB;
2989 
2990  $feedback = "";
2991  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s AND correctness = %s",
2992  array('integer', 'text'),
2993  array($this->getId(), $correctness)
2994  );
2995  if ($result->numRows())
2996  {
2997  $row = $ilDB->fetchAssoc($result);
2998  include_once("./Services/RTE/classes/class.ilRTE.php");
2999  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
3000  }
3001  return $feedback;
3002  }
3003 
3010  function duplicateFeedbackGeneric($original_id)
3011  {
3012  global $ilDB;
3013 
3014  $feedback = "";
3015  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s",
3016  array('integer'),
3017  array($original_id)
3018  );
3019  if ($result->numRows())
3020  {
3021  while ($row = $ilDB->fetchAssoc($result))
3022  {
3023  $next_id = $ilDB->nextId('qpl_fb_generic');
3024 
3026  $ilDB->insert('qpl_fb_generic', array(
3027  'feedback_id' => array( 'integer', $next_id ),
3028  'question_fi' => array( 'integer', $this->getId() ),
3029  'correctness' => array( 'text', $row["correctness"] ),
3030  'feedback' => array( 'clob', $row["feedback"] ),
3031  'tstamp' => array( 'integer', time() ),
3032  )
3033  );
3034  }
3035  }
3036  }
3037 
3038  function syncFeedbackGeneric()
3039  {
3040  global $ilDB;
3041 
3042  $feedback = "";
3043 
3044  // delete generic feedback of the original
3045  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_generic WHERE question_fi = %s",
3046  array('integer'),
3047  array($this->original_id)
3048  );
3049 
3050  // get generic feedback of the actual question
3051  $result = $ilDB->queryF("SELECT * FROM qpl_fb_generic WHERE question_fi = %s",
3052  array('integer'),
3053  array($this->getId())
3054  );
3055 
3056  // save generic feedback to the original
3057  if ($result->numRows())
3058  {
3059  while ($row = $ilDB->fetchAssoc($result))
3060  {
3061  $next_id = $ilDB->nextId('qpl_fb_generic');
3062 
3064  $ilDB->insert('qpl_fb_generic', array(
3065  'feedback_id' => array( 'integer', $next_id ),
3066  'question_fi' => array( 'integer', $this->original_id ),
3067  'correctness' => array( 'text', $row["correctness"] ),
3068  'feedback' => array( 'clob', $row["feedback"] ),
3069  'tstamp' => array( 'integer', time() ),
3070  )
3071  );
3072 
3073  }
3074  }
3075  }
3076 
3082  {
3083  // must be called in parent classes. add additional RTE text in the parent
3084  // classes and call this method to add the standard RTE text
3085  $collected = $this->getQuestion();
3086  $collected .= $this->getFeedbackGeneric(0);
3087  $collected .= $this->getFeedbackGeneric(1);
3088  foreach ($this->suggested_solutions as $solution_array)
3089  {
3090  $collected .= $solution_array["value"];
3091  }
3092  return $collected;
3093  }
3094 
3100  {
3101  $combinedtext = $this->getRTETextWithMediaObjects();
3102  include_once("./Services/RTE/classes/class.ilRTE.php");
3103  ilRTE::_cleanupMediaObjectUsage($combinedtext, "qpl:html", $this->getId());
3104  }
3105 
3111  function &getInstances()
3112  {
3113  global $ilDB;
3114 
3115  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s",
3116  array("integer"),
3117  array($this->getId())
3118  );
3119  $instances = array();
3120  $ids = array();
3121  while ($row = $ilDB->fetchAssoc($result))
3122  {
3123  array_push($ids, $row["question_id"]);
3124  }
3125  foreach ($ids as $question_id)
3126  {
3127  // check non random tests
3128  $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",
3129  array("integer"),
3130  array($question_id)
3131  );
3132  while ($row = $ilDB->fetchAssoc($result))
3133  {
3134  $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3135  }
3136  // check random tests
3137  $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",
3138  array("integer"),
3139  array($question_id)
3140  );
3141  while ($row = $ilDB->fetchAssoc($result))
3142  {
3143  $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3144  }
3145  }
3146  include_once "./Modules/Test/classes/class.ilObjTest.php";
3147  foreach ($instances as $key => $value)
3148  {
3149  $instances[$key] = array("obj_id" => $key, "title" => $value, "author" => ilObjTest::_lookupAuthor($key), "refs" => ilObject::_getAllReferences($key));
3150  }
3151  return $instances;
3152  }
3153 
3154  function _needsManualScoring($question_id)
3155  {
3156  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
3158  $questiontype = assQuestion::_getQuestionType($question_id);
3159  if (in_array($questiontype, $scoring))
3160  {
3161  return TRUE;
3162  }
3163  else
3164  {
3165  return FALSE;
3166  }
3167  }
3168 
3176  function getActiveUserData($active_id)
3177  {
3178  global $ilDB;
3179  $result = $ilDB->queryF("SELECT * FROM tst_active WHERE active_id = %s",
3180  array('integer'),
3181  array($active_id)
3182  );
3183  if ($result->numRows())
3184  {
3185  $row = $ilDB->fetchAssoc($result);
3186  return array("user_id" => $row["user_fi"], "test_id" => $row["test_fi"]);
3187  }
3188  else
3189  {
3190  return array();
3191  }
3192  }
3193 
3201  static function _includeClass($question_type, $gui = 0)
3202  {
3203  $type = $question_type;
3204  if ($gui) $type .= "GUI";
3205  if (file_exists("./Modules/TestQuestionPool/classes/class.".$type.".php"))
3206  {
3207  include_once "./Modules/TestQuestionPool/classes/class.".$type.".php";
3208  }
3209  else
3210  {
3211  global $ilPluginAdmin;
3212  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3213  foreach ($pl_names as $pl_name)
3214  {
3215  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3216  if (strcmp($pl->getQuestionType(), $question_type) == 0)
3217  {
3218  $pl->includeClass("class.".$type.".php");
3219  }
3220  }
3221  }
3222  }
3223 
3230  static function _getQuestionTypeName($type_tag)
3231  {
3232  if (file_exists("./Modules/TestQuestionPool/classes/class.".$type_tag.".php"))
3233  {
3234  global $lng;
3235  return $lng->txt($type_tag);
3236  }
3237  else
3238  {
3239  global $ilPluginAdmin;
3240  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3241  foreach ($pl_names as $pl_name)
3242  {
3243  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3244  if (strcmp($pl->getQuestionType(), $type_tag) == 0)
3245  {
3246  return $pl->getQuestionTypeTranslation();
3247  }
3248  }
3249  }
3250  return "";
3251  }
3252 
3260  function &_instanciateQuestionGUI($question_id)
3261  {
3262  if (strcmp($question_id, "") != 0)
3263  {
3264  $question_type = assQuestion::_getQuestionType($question_id);
3265  $question_type_gui = $question_type . "GUI";
3266  assQuestion::_includeClass($question_type, 1);
3267  $question_gui = new $question_type_gui();
3268  $question_gui->object->loadFromDb($question_id);
3269  return $question_gui;
3270  }
3271  }
3272 
3285  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
3286  {
3287  return $startrow;
3288  }
3289 
3293  public function __get($value)
3294  {
3295  switch ($value)
3296  {
3297  case "id":
3298  return $this->getId();
3299  break;
3300  case "title":
3301  return $this->getTitle();
3302  break;
3303  case "comment":
3304  return $this->getComment();
3305  break;
3306  case "owner":
3307  return $this->getOwner();
3308  break;
3309  case "author":
3310  return $this->getAuthor();
3311  break;
3312  case "question":
3313  return $this->getQuestion();
3314  break;
3315  case "points":
3316  return $this->getPoints();
3317  break;
3318  case "est_working_time":
3319  return $this->getEstimatedWorkingTime();
3320  break;
3321  case "shuffle":
3322  return $this->getShuffle();
3323  break;
3324  case "test_id":
3325  return $this->getTestId();
3326  break;
3327  case "obj_id":
3328  return $this->getObjId();
3329  break;
3330  case "ilias":
3331  return $this->ilias;
3332  break;
3333  case "tpl":
3334  return $this->tpl;
3335  break;
3336  case "page":
3337  return $this->page;
3338  break;
3339  case "outputType":
3340  return $this->getOutputType();
3341  break;
3342  case "suggested_solutions":
3343  return $this->getSuggestedSolutions();
3344  break;
3345  case "original_id":
3346  return $this->getOriginalId();
3347  break;
3348  default:
3349  if (array_key_exists($value, $this->arrData))
3350  {
3351  return $this->arrData[$value];
3352  }
3353  else
3354  {
3355  return null;
3356  }
3357  break;
3358  }
3359  }
3360 
3364  public function __set($key, $value)
3365  {
3366  switch ($key)
3367  {
3368  case "id":
3369  $this->setId($value);
3370  break;
3371  case "title":
3372  $this->setTitle($value);
3373  break;
3374  case "comment":
3375  $this->setComment($value);
3376  break;
3377  case "owner":
3378  $this->setOwner($value);
3379  break;
3380  case "author":
3381  $this->setAuthor($value);
3382  break;
3383  case "question":
3384  $this->setQuestion($value);
3385  break;
3386  case "points":
3387  $this->setPoints($value);
3388  break;
3389  case "est_working_time":
3390  if (is_array($value))
3391  {
3392  $this->setEstimatedWorkingTime($value["h"], $value["m"], $value["s"]);
3393  }
3394  break;
3395  case "shuffle":
3396  $this->setShuffle($value);
3397  break;
3398  case "test_id":
3399  $this->setTestId($value);
3400  break;
3401  case "obj_id":
3402  $this->setObjId($value);
3403  break;
3404  case "outputType":
3405  $this->setOutputType($value);
3406  break;
3407  case "original_id":
3408  $this->setOriginalId($value);
3409  break;
3410  case "page":
3411  $this->page =& $value;
3412  break;
3413  default:
3414  $this->arrData[$key] = $value;
3415  break;
3416  }
3417  }
3418 
3419  public function getNrOfTries()
3420  {
3421  return $this->nr_of_tries;
3422  }
3423 
3424  public function setNrOfTries($a_nr_of_tries)
3425  {
3426  $this->nr_of_tries = $a_nr_of_tries;
3427  }
3428 
3429  public function setExportImagePath($a_path)
3430  {
3431  $this->export_image_path = (string)$a_path;
3432  }
3433 
3434  function _questionExistsInTest($question_id, $test_id)
3435  {
3436  global $ilDB;
3437 
3438  if ($question_id < 1)
3439  {
3440  return false;
3441  }
3442 
3443  $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE question_fi = %s AND test_fi = %s",
3444  array('integer', 'integer'),
3445  array($question_id, $test_id)
3446  );
3447  if ($result->numRows() == 1)
3448  {
3449  return true;
3450  }
3451  else
3452  {
3453  return false;
3454  }
3455  }
3456 
3463  function formatSAQuestion($a_q)
3464  {
3465  include_once("./Services/RTE/classes/class.ilRTE.php");
3466  $a_q = nl2br((string) ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0));
3467  $a_q = str_replace("</li><br />", "</li>", $a_q);
3468  $a_q = str_replace("</li><br>", "</li>", $a_q);
3469  return $a_q;
3470  }
3471 
3472 }
3473 
3474 ?>