ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
class.assQuestion.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
5
20abstract class assQuestion
21{
22 const IMG_MIME_TYPE_JPG = 'image/jpeg';
23 const IMG_MIME_TYPE_PNG = 'image/png';
24 const IMG_MIME_TYPE_GIF = 'image/gif';
25
26 protected static $allowedFileExtensionsByMimeType = array(
27 self::IMG_MIME_TYPE_JPG => array('jpg', 'jpeg'),
28 self::IMG_MIME_TYPE_PNG => array('png'),
29 self::IMG_MIME_TYPE_GIF => array('gif')
30 );
31
32 protected static $allowedCharsetsByMimeType = array(
33 self::IMG_MIME_TYPE_JPG => array('binary'),
34 self::IMG_MIME_TYPE_PNG => array('binary'),
35 self::IMG_MIME_TYPE_GIF => array('binary')
36 );
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
93
99 protected $shuffle;
100
106 protected $test_id;
107
113 protected $obj_id;
114
120 protected $ilias;
121
125 protected $tpl;
126
130 protected $lng;
131
135 protected $db;
136
142 protected $outputType;
143
150
156 protected $original_id;
157
163 protected $page;
164
169
173 private $arrData;
174
179
187
192 protected $external_id = '';
193
198
203
210
216 public $feedbackOBJ = null;
217
224
231
238
242 protected $questionChangeListeners = array();
243
247 protected $processLocker;
248
249 public $questionActionCmd = 'handleQuestionAction';
250
254 private static $resultGateway = null;
255
259 protected $step = null;
260
261 protected $lastChange;
262
273 function __construct(
274 $title = "",
275 $comment = "",
276 $author = "",
277 $owner = -1,
278 $question = ""
279 )
280 {
281 global $ilias, $lng, $tpl, $ilDB;
282
283 $this->ilias = $ilias;
284 $this->lng = $lng;
285 $this->tpl = $tpl;
286 $this->db = $ilDB;
287
288 $this->original_id = null;
289 $this->title = $title;
290 $this->comment = $comment;
291 $this->page = null;
292 $this->author = $author;
293 $this->setQuestion($question);
294 if (!$this->author)
295 {
296 $this->author = $this->ilias->account->fullname;
297 }
298 $this->owner = $owner;
299 if ($this->owner <= 0)
300 {
301 $this->owner = $this->ilias->account->id;
302 }
303 $this->id = -1;
304 $this->test_id = -1;
305 $this->suggested_solutions = array();
306 $this->shuffle = 1;
307 $this->nr_of_tries = 0;
308 $this->setEstimatedWorkingTime(0,1,0);
309 $this->outputType = OUTPUT_JAVASCRIPT;
310 $this->arrData = array();
311 $this->setExternalId('');
312
313 $this->questionActionCmd = 'handleQuestionAction';
314
315 $this->lastChange = null;
316 }
317
318 public static function isAllowedImageMimeType($mimeType)
319 {
320 return (bool)count(self::getAllowedFileExtensionsForMimeType($mimeType));
321 }
322
323 public static function fetchMimeTypeIdentifier($contentTypeString)
324 {
325 return current(explode(';', $contentTypeString));
326 }
327
328 public static function getAllowedFileExtensionsForMimeType($mimeType)
329 {
330 foreach(self::$allowedFileExtensionsByMimeType as $allowedMimeType => $extensions)
331 {
332 $rexCharsets = implode('|', self::$allowedCharsetsByMimeType[$allowedMimeType]);
333 $rexMimeType = preg_quote($allowedMimeType, '/');
334
335 $rex = '/^'.$rexMimeType.'(;(\s)*charset=('.$rexCharsets.'))*$/';
336
337 if( !preg_match($rex, $mimeType) )
338 {
339 continue;
340 }
341
342 return $extensions;
343 }
344
345 return array();
346 }
347
348 public static function isAllowedImageFileExtension($mimeType, $fileExtension)
349 {
350 return in_array(
351 strtolower($fileExtension), self::getAllowedFileExtensionsForMimeType($mimeType)
352 );
353 }
354
355 public static function getAllowedImageFileExtensions()
356 {
357 $allowedExtensions = array();
358
359 foreach(self::$allowedFileExtensionsByMimeType as $mimeType => $fileExtensions)
360 {
361 $allowedExtensions = array_merge($allowedExtensions, $fileExtensions);
362 }
363
364 return $allowedExtensions;
365 }
366
367
372 {
373 $this->processLocker = $processLocker;
374 }
375
379 public function getProcessLocker()
380 {
382 }
383
395 function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
396 {
397 include_once "./Modules/TestQuestionPool/classes/import/qti12/class." . $this->getQuestionType() . "Import.php";
398 $classname = $this->getQuestionType() . "Import";
399 $import = new $classname($this);
400 $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
401 }
402
409 function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
410 {
411 include_once "./Modules/TestQuestionPool/classes/export/qti12/class." . $this->getQuestionType() . "Export.php";
412 $classname = $this->getQuestionType() . "Export";
413 $export = new $classname($this);
414 return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
415 }
416
423 function isComplete()
424 {
425 return false;
426 }
427
435 function questionTitleExists($questionpool_id, $title)
436 {
437 global $ilDB;
438
439 $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE obj_fi = %s AND title = %s",
440 array('integer','text'),
441 array($questionpool_id, $title)
442 );
443 return ($result->numRows() > 0) ? TRUE : FALSE;
444 }
445
453 function setTitle($title = "")
454 {
455 $this->title = $title;
456 }
457
465 function setId($id = -1)
466 {
467 $this->id = $id;
468 }
469
477 function setTestId($id = -1)
478 {
479 $this->test_id = $id;
480 }
481
489 function setComment($comment = "")
490 {
491 $this->comment = $comment;
492 }
493
502 {
503 $this->outputType = $outputType;
504 }
505
506
514 function setShuffle($shuffle = true)
515 {
516 if ($shuffle)
517 {
518 $this->shuffle = 1;
519 }
520 else
521 {
522 $this->shuffle = 0;
523 }
524 }
525
536 function setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
537 {
538 $this->est_working_time = array("h" => (int)$hour, "m" => (int)$min, "s" => (int)$sec);
539 }
540
548 {
549 $this->est_working_time = array(
550 'h' => (int)substr($durationString, 0, 2),
551 'm' => (int)substr($durationString, 3, 2),
552 's' => (int)substr($durationString, 6, 2)
553 );
554 }
555
563 function keyInArray($searchkey, $array)
564 {
565 if ($searchkey)
566 {
567 foreach ($array as $key => $value)
568 {
569 if (strcmp($key, $searchkey)==0)
570 {
571 return true;
572 }
573 }
574 }
575 return false;
576 }
577
585 function setAuthor($author = "")
586 {
587 if (!$author)
588 {
589 $author = $this->ilias->account->fullname;
590 }
591 $this->author = $author;
592 }
593
601 function setOwner($owner = "")
602 {
603 $this->owner = $owner;
604 }
605
613 function getTitle()
614 {
615 return $this->title;
616 }
617
625 function getId()
626 {
627 return $this->id;
628 }
629
637 function getShuffle()
638 {
639 return $this->shuffle;
640 }
641
649 function getTestId()
650 {
651 return $this->test_id;
652 }
653
661 function getComment()
662 {
663 return $this->comment;
664 }
665
673 function getOutputType()
674 {
675 return $this->outputType;
676 }
677
684 public function supportsJavascriptOutput()
685 {
686 return FALSE;
687 }
688
689 public function supportsNonJsOutput()
690 {
691 return true;
692 }
693
694 public function requiresJsSwitch()
695 {
696 return $this->supportsJavascriptOutput() && $this->supportsNonJsOutput();
697 }
698
707 {
708 if (!$this->est_working_time)
709 {
710 $this->est_working_time = array("h" => 0, "m" => 0, "s" => 0);
711 }
713 }
714
722 function getAuthor()
723 {
724 return $this->author;
725 }
726
734 function getOwner()
735 {
736 return $this->owner;
737 }
738
746 function getObjId()
747 {
748 return $this->obj_id;
749 }
750
758 function setObjId($obj_id = 0)
759 {
760 $this->obj_id = $obj_id;
761 }
762
767 {
768 $this->external_id = $external_id;
769 }
770
774 public function getExternalId()
775 {
776 if(!strlen($this->external_id))
777 {
778 if($this->getId() > 0)
779 {
780 return 'il_' . IL_INST_ID . '_qst_' . $this->getId();
781 }
782 else
783 {
784 return uniqid('', true);
785 }
786 }
787 else
788 {
789 return $this->external_id;
790 }
791 }
792
799 function _getMaximumPoints($question_id)
800 {
801 global $ilDB;
802
803 $points = 0;
804 $result = $ilDB->queryF("SELECT points FROM qpl_questions WHERE question_id = %s",
805 array('integer'),
806 array($question_id)
807 );
808 if ($result->numRows() == 1)
809 {
810 $row = $ilDB->fetchAssoc($result);
811 $points = $row["points"];
812 }
813 return $points;
814 }
815
822 function &_getQuestionInfo($question_id)
823 {
824 global $ilDB;
825
826 $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",
827 array('integer'),
828 array($question_id)
829 );
830 if ($result->numRows())
831 {
832 return $ilDB->fetchAssoc($result);
833 }
834 else return array();
835 }
836
843 public static function _getSuggestedSolutionCount($question_id)
844 {
845 global $ilDB;
846
847 $result = $ilDB->queryF("SELECT suggested_solution_id FROM qpl_sol_sug WHERE question_fi = %s",
848 array('integer'),
849 array($question_id)
850 );
851 return $result->numRows();
852 }
853
860 public static function _getSuggestedSolutionOutput($question_id)
861 {
863 if (!is_object($question)) return "";
864 return $question->getSuggestedSolutionOutput();
865 }
866
868 {
869 $output = array();
870 foreach ($this->suggested_solutions as $solution)
871 {
872 switch ($solution["type"])
873 {
874 case "lm":
875 case "st":
876 case "pg":
877 case "git":
878 array_push($output, '<a href="' . assQuestion::_getInternalLinkHref($solution["internal_link"]) . '">' . $this->lng->txt("solution_hint") . '</a>');
879 break;
880 case "file":
881 $possible_texts = array_values(array_filter(array(
882 ilUtil::prepareFormOutput($solution['value']['filename']),
883 ilUtil::prepareFormOutput($solution['value']['name']),
884 $this->lng->txt('tst_show_solution_suggested')
885 )));
886 array_push($output, '<a href="' . $this->getSuggestedSolutionPathWeb() . $solution["value"]["name"] . '">' . $possible_texts[0] . '</a>');
887 break;
888 case "text":
889 $solutionValue = $solution["value"];
890 $solutionValue = $this->fixSvgToPng($solutionValue);
891 $solutionValue = $this->fixUnavailableSkinImageSources($solutionValue);
892 $output[] = $this->prepareTextareaOutput($solutionValue, true);
893 break;
894 }
895 }
896 return join($output, "<br />");
897 }
898
907 function &_getSuggestedSolution($question_id, $subquestion_index = 0)
908 {
909 global $ilDB;
910
911 $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
912 array('integer','integer'),
913 array($question_id, $subquestion_index)
914 );
915 if ($result->numRows() == 1)
916 {
917 $row = $ilDB->fetchAssoc($result);
918 return array(
919 "internal_link" => $row["internal_link"],
920 "import_id" => $row["import_id"]
921 );
922 }
923 else
924 {
925 return array();
926 }
927 }
928
934 public function getSuggestedSolutions()
935 {
937 }
938
946 function _getReachedPoints($active_id, $question_id, $pass = NULL)
947 {
948 global $ilDB;
949
950 $points = 0;
951 if (is_null($pass))
952 {
953 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
954 $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
955 }
956 $result = $ilDB->queryF("SELECT * FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
957 array('integer','integer','integer'),
958 array($active_id, $question_id, $pass)
959 );
960 if ($result->numRows() == 1)
961 {
962 $row = $ilDB->fetchAssoc($result);
963 $points = $row["points"];
964 }
965 return $points;
966 }
967
976 function getReachedPoints($active_id, $pass = NULL)
977 {
978 return round($this->_getReachedPoints($active_id, $this->getId(), $pass), 2);
979 }
980
988 {
989 return $this->points;
990 }
991
1003 final public function getAdjustedReachedPoints($active_id, $pass = NULL)
1004 {
1005 if (is_null($pass))
1006 {
1007 include_once "./Modules/Test/classes/class.ilObjTest.php";
1008 $pass = ilObjTest::_getPass($active_id);
1009 }
1010
1011 // determine reached points for submitted solution
1012 $reached_points = $this->calculateReachedPoints($active_id, $pass);
1013
1014
1015
1016 // deduct points for requested hints from reached points
1017 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
1018 $hintTracking = new ilAssQuestionHintTracking($this->getId(), $active_id, $pass);
1019 $requestsStatisticData = $hintTracking->getRequestStatisticDataByQuestionAndTestpass();
1020 $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
1021
1022 // adjust reached points regarding to tests scoring options
1023 $reached_points = $this->adjustReachedPointsByScoringOptions($reached_points, $active_id, $pass);
1024
1025 return $reached_points;
1026 }
1027
1037 final public function calculateResultsFromSolution($active_id, $pass = NULL, $obligationsEnabled = false)
1038 {
1039 global $ilDB, $ilUser;
1040
1041 if( is_null($pass) )
1042 {
1043 include_once "./Modules/Test/classes/class.ilObjTest.php";
1044 $pass = ilObjTest::_getPass($active_id);
1045 }
1046
1047 // determine reached points for submitted solution
1048 $reached_points = $this->calculateReachedPoints($active_id, $pass);
1049
1050 // deduct points for requested hints from reached points
1051 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
1052 $questionHintTracking = new ilAssQuestionHintTracking($this->getId(), $active_id, $pass);
1053 $requestsStatisticData = $questionHintTracking->getRequestStatisticDataByQuestionAndTestpass();
1054 $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
1055
1056 // adjust reached points regarding to tests scoring options
1057 $reached_points = $this->adjustReachedPointsByScoringOptions($reached_points, $active_id, $pass);
1058
1059 if( $obligationsEnabled && ilObjTest::isQuestionObligatory($this->getId()) )
1060 {
1061 $isAnswered = $this->isAnswered($active_id, $pass);
1062 }
1063 else
1064 {
1065 $isAnswered = true;
1066 }
1067
1068 if( is_null($reached_points) ) $reached_points = 0;
1069
1070 $this->getProcessLocker()->requestUserQuestionResultUpdateLock();
1071
1072 $query = "
1073 DELETE FROM tst_test_result
1074
1075 WHERE active_fi = %s
1076 AND question_fi = %s
1077 AND pass = %s
1078 ";
1079
1080 $types = array('integer', 'integer', 'integer');
1081 $values = array($active_id, $this->getId(), $pass);
1082
1083 if( $this->getStep() !== NULL )
1084 {
1085 $query .= "
1086 AND step = %s
1087 ";
1088
1089 $types[] = 'integer';
1090 $values[] = $this->getStep();
1091 }
1092
1093 $affectedRows = $ilDB->manipulateF($query, $types, $values);
1094
1095 $next_id = $ilDB->nextId("tst_test_result");
1096
1097 $fieldData = array(
1098 'test_result_id' => array('integer', $next_id),
1099 'active_fi' => array('integer', $active_id),
1100 'question_fi' => array('integer', $this->getId()),
1101 'pass' => array('integer', $pass),
1102 'points' => array('float', $reached_points),
1103 'tstamp' => array('integer', time()),
1104 'hint_count' => array('integer', $requestsStatisticData->getRequestsCount()),
1105 'hint_points' => array('float', $requestsStatisticData->getRequestsPoints()),
1106 'answered' => array('integer', $isAnswered)
1107 );
1108
1109 if( $this->getStep() !== NULL )
1110 {
1111 $fieldData['step'] = array('integer', $this->getStep());
1112 }
1113
1114 $ilDB->insert('tst_test_result', $fieldData);
1115
1116 $this->getProcessLocker()->releaseUserQuestionResultUpdateLock();
1117
1118 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1119
1121 {
1122 $this->logAction(
1123 sprintf(
1124 $this->lng->txtlng(
1125 "assessment", "log_user_answered_question", ilObjAssessmentFolder::_getLogLanguage()
1126 ),
1127 $reached_points
1128 ),
1129 $active_id,
1130 $this->getId()
1131 );
1132 }
1133
1134 // update test pass results
1135 $this->_updateTestPassResults($active_id, $pass, $obligationsEnabled, $this->getProcessLocker());
1136
1137 // Update objective status
1138 include_once 'Modules/Course/classes/class.ilCourseObjectiveResult.php';
1139 ilCourseObjectiveResult::_updateObjectiveResult($ilUser->getId(),$active_id,$this->getId());
1140 }
1141
1150 final public function persistWorkingState($active_id, $pass = NULL, $obligationsEnabled = false)
1151 {
1152 if( $pass === null )
1153 {
1154 require_once 'Modules/Test/classes/class.ilObjTest.php';
1155 $pass = ilObjTest::_getPass($active_id);
1156 }
1157
1158 $this->getProcessLocker()->requestPersistWorkingStateLock();
1159
1160 $saveStatus = $this->saveWorkingData($active_id, $pass);
1161
1162 $this->calculateResultsFromSolution($active_id, $pass, $obligationsEnabled);
1163
1164 $this->reworkWorkingData($active_id, $pass, $obligationsEnabled);
1165
1166 $this->getProcessLocker()->releasePersistWorkingStateLock();
1167
1168 return $saveStatus;
1169 }
1170
1174 final public function persistPreviewState(ilAssQuestionPreviewSession $previewSession)
1175 {
1176 $this->savePreviewData($previewSession);
1177 }
1178
1188 abstract public function saveWorkingData($active_id, $pass = NULL);
1189
1199 abstract protected function reworkWorkingData($active_id, $pass, $obligationsAnswered);
1200
1201 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
1202 {
1203 $previewSession->setParticipantsSolution($this->getSolutionSubmit());
1204 }
1205
1208 {
1209 global $ilDB;
1210
1211 include_once "./Modules/Test/classes/class.ilObjTest.php";
1212 include_once "./Modules/Test/classes/class.assMarkSchema.php";
1213
1214 $pass = ilObjTest::_getResultPass($active_id);
1215
1216 $query = "
1217 SELECT tst_pass_result.*
1218 FROM tst_pass_result
1219 WHERE active_fi = %s
1220 AND pass = %s
1221 ";
1222
1223 $result = $ilDB->queryF(
1224 $query, array('integer','integer'), array($active_id, $pass)
1225 );
1226
1227 $row = $ilDB->fetchAssoc($result);
1228
1229 $max = $row['maxpoints'];
1230 $reached = $row['points'];
1231
1232 $obligationsAnswered = (int)$row['obligations_answered'];
1233
1234 include_once "./Modules/Test/classes/class.assMarkSchema.php";
1235
1236 $percentage = (!$max) ? 0 : ($reached / $max) * 100.0;
1237
1238 $mark = ASS_MarkSchema::_getMatchingMarkFromActiveId($active_id, $percentage);
1239
1240 $isPassed = ( $mark["passed"] ? 1 : 0 );
1241 $isFailed = ( !$mark["passed"] ? 1 : 0 );
1242
1243 if( is_object($processLocker) )
1244 {
1245 $processLocker->requestUserTestResultUpdateLock();
1246 }
1247
1248 $query = "
1249 DELETE FROM tst_result_cache
1250 WHERE active_fi = %s
1251 ";
1252
1253 $affectedRows = $ilDB->manipulateF(
1254 $query, array('integer'), array($active_id)
1255 );
1256
1257 $ilDB->insert('tst_result_cache', array(
1258 'active_fi'=> array('integer', $active_id),
1259 'pass'=> array('integer', strlen($pass) ? $pass : 0),
1260 'max_points'=> array('float', strlen($max) ? $max : 0),
1261 'reached_points'=> array('float', strlen($reached) ? $reached : 0),
1262 'mark_short'=> array('text', strlen($mark["short_name"]) ? $mark["short_name"] : " "),
1263 'mark_official'=> array('text', strlen($mark["official_name"]) ? $mark["official_name"] : " "),
1264 'passed'=> array('integer', $isPassed),
1265 'failed'=> array('integer', $isFailed),
1266 'tstamp'=> array('integer', time()),
1267 'hint_count'=> array('integer', $row['hint_count']),
1268 'hint_points'=> array('float', $row['hint_points']),
1269 'obligations_answered' => array('integer', $obligationsAnswered)
1270 ));
1271
1272 if( is_object($processLocker) )
1273 {
1274 $processLocker->releaseUserTestResultUpdateLock();
1275 }
1276 }
1277
1279 function _updateTestPassResults($active_id, $pass, $obligationsEnabled = false, ilAssQuestionProcessLocker $processLocker = null, $test_obj_id = null)
1280 {
1281 global $ilDB;
1282
1283 include_once "./Modules/Test/classes/class.ilObjTest.php";
1284
1285 if( self::getResultGateway() !== null )
1286 {
1287 $data = self::getResultGateway()->getQuestionCountAndPointsForPassOfParticipant($active_id, $pass);
1288 $time = self::getResultGateway()->getWorkingTimeOfParticipantForPass($active_id, $pass);
1289 }
1290 else
1291 {
1294 }
1295
1296
1297 // update test pass results
1298
1299 $result = $ilDB->queryF("
1300 SELECT SUM(points) reachedpoints,
1301 SUM(hint_count) hint_count,
1302 SUM(hint_points) hint_points,
1303 COUNT(DISTINCT(question_fi)) answeredquestions
1304 FROM tst_test_result
1305 WHERE active_fi = %s
1306 AND pass = %s
1307 ",
1308 array('integer','integer'),
1309 array($active_id, $pass)
1310 );
1311
1312 if ($result->numRows() > 0)
1313 {
1314 if( $obligationsEnabled )
1315 {
1316 $query = '
1317 SELECT count(*) cnt,
1318 min( answered ) answ
1319 FROM tst_test_question
1320 INNER JOIN tst_active
1321 ON active_id = %s
1322 AND tst_test_question.test_fi = tst_active.test_fi
1323 LEFT JOIN tst_test_result
1324 ON tst_test_result.active_fi = %s
1325 AND tst_test_result.pass = %s
1326 AND tst_test_question.question_fi = tst_test_result.question_fi
1327 WHERE obligatory = 1';
1328
1329 $result_obligatory = $ilDB->queryF(
1330 $query, array('integer','integer','integer'), array($active_id, $active_id, $pass)
1331 );
1332
1333 $row_obligatory = $ilDB->fetchAssoc($result_obligatory);
1334
1335 if ($row_obligatory['cnt'] == 0)
1336 {
1337 $obligations_answered = 1;
1338 }
1339 else
1340 {
1341 $obligations_answered = (int) $row_obligatory['answ'];
1342 }
1343 }
1344 else
1345 {
1346 $obligations_answered = 1;
1347 }
1348
1349 $row = $ilDB->fetchAssoc($result);
1350
1351 if( $row['hint_count'] === null ) $row['hint_count'] = 0;
1352 if( $row['hint_points'] === null ) $row['hint_points'] = 0;
1353
1354 $exam_identifier = ilObjTest::buildExamId( $active_id, $pass, $test_obj_id);
1355
1356 if( is_object($processLocker) )
1357 {
1358 $processLocker->requestUserPassResultUpdateLock();
1359 }
1360
1361 /*
1362 $query = "
1363 DELETE FROM tst_pass_result
1364
1365 WHERE active_fi = %s
1366 AND pass = %s
1367 ";
1368
1369 $affectedRows = $ilDB->manipulateF(
1370 $query, array('integer','integer'), array($active_id, $pass)
1371 );
1372 */
1374 $ilDB->replace('tst_pass_result',
1375 array(
1376 'active_fi' => array('integer', $active_id),
1377 'pass' => array('integer', strlen($pass) ? $pass : 0)),
1378 array(
1379 'points' => array('float', $row['reachedpoints'] ? $row['reachedpoints'] : 0),
1380 'maxpoints' => array('float', $data['points']),
1381 'questioncount' => array('integer', $data['count']),
1382 'answeredquestions' => array('integer', $row['answeredquestions']),
1383 'workingtime' => array('integer', $time),
1384 'tstamp' => array('integer', time()),
1385 'hint_count' => array('integer', $row['hint_count']),
1386 'hint_points' => array('float', $row['hint_points']),
1387 'obligations_answered' => array('integer', $obligations_answered),
1388 'exam_id' => array('text', $exam_identifier)
1389 )
1390 );
1391
1392 /*
1393 $ilDB->insert('tst_pass_result', array(
1394 'active_fi' => array('integer', $active_id),
1395 'pass' => array('integer', strlen($pass) ? $pass : 0),
1396 'points' => array('float', $row['reachedpoints'] ? $row['reachedpoints'] : 0),
1397 'maxpoints' => array('float', $data['points']),
1398 'questioncount' => array('integer', $data['count']),
1399 'answeredquestions' => array('integer', $row['answeredquestions']),
1400 'workingtime' => array('integer', $time),
1401 'tstamp' => array('integer', time()),
1402 'hint_count' => array('integer', $row['hint_count']),
1403 'hint_points' => array('float', $row['hint_points']),
1404 'obligations_answered' => array('integer', $obligations_answered),
1405 'exam_id' => array('text', $exam_identifier)
1406 ));
1407 */
1408
1409 if( is_object($processLocker) )
1410 {
1411 $this->getProcessLocker()->releaseUserPassResultUpdateLock();
1412 }
1413 }
1414
1416
1417 return array(
1418 'active_fi' => $active_id,
1419 'pass' => $pass,
1420 'points' => ($row["reachedpoints"]) ? $row["reachedpoints"] : 0,
1421 'maxpoints' => $data["points"],
1422 'questioncount' => $data["count"],
1423 'answeredquestions' => $row["answeredquestions"],
1424 'workingtime' => $time,
1425 'tstamp' => time(),
1426 'hint_count' => $row['hint_count'],
1427 'hint_points' => $row['hint_points'],
1428 'obligations_answered' => $obligations_answered,
1429 'exam_id' => $exam_identifier
1430 );
1431 }
1432
1440 function logAction($logtext = "", $active_id = "", $question_id = "")
1441 {
1442 global $ilUser;
1443
1444 $original_id = "";
1445 if (strcmp($question_id, "") != 0)
1446 {
1447 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1449 }
1450 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1451 include_once "./Modules/Test/classes/class.ilObjTest.php";
1453 }
1454
1462 function _logAction($logtext = "", $active_id = "", $question_id = "")
1463 {
1464 global $ilUser;
1465
1466 $original_id = "";
1467 if (strcmp($question_id, "") != 0)
1468 {
1469 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1471 }
1472 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1473 include_once "./Modules/Test/classes/class.ilObjTest.php";
1475 }
1476
1485 {
1486 $mediatempdir = CLIENT_WEB_DIR . "/assessment/temp";
1487 if (!@is_dir($mediatempdir)) ilUtil::createDirectory($mediatempdir);
1488 $temp_name = tempnam($mediatempdir, $name . "_____");
1489 $temp_name = str_replace("\\", "/", $temp_name);
1490 @unlink($temp_name);
1491 if (!ilUtil::moveUploadedFile($file, $name, $temp_name))
1492 {
1493 return FALSE;
1494 }
1495 else
1496 {
1497 return $temp_name;
1498 }
1499 }
1500
1507 return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/solution/";
1508 }
1509
1516 function getJavaPath() {
1517 return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/java/";
1518 }
1519
1526 function getImagePath($question_id = null, $object_id = null)
1527 {
1528 if( $question_id === null)
1529 {
1530 $question_id = $this->id;
1531 }
1532
1533 if( $object_id === null)
1534 {
1535 $object_id = $this->obj_id;
1536 }
1537
1538 return $this->buildImagePath($question_id, $object_id);
1539 }
1540
1541 public function buildImagePath($questionId, $parentObjectId)
1542 {
1543 return CLIENT_WEB_DIR . "/assessment/{$parentObjectId}/{$questionId}/images/";
1544 }
1545
1552 function getFlashPath()
1553 {
1554 return CLIENT_WEB_DIR . "/assessment/$this->obj_id/$this->id/flash/";
1555 }
1556
1564 {
1565 include_once "./Services/Utilities/classes/class.ilUtil.php";
1566 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/java/";
1568 }
1569
1576 {
1577 include_once "./Services/Utilities/classes/class.ilUtil.php";
1578 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/solution/";
1580 }
1581
1589 {
1590 if(!$this->export_image_path)
1591 {
1592 include_once "./Services/Utilities/classes/class.ilUtil.php";
1593 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/images/";
1595 }
1596 else
1597 {
1599 }
1600 }
1601
1609 {
1610 include_once "./Services/Utilities/classes/class.ilUtil.php";
1611 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/$this->obj_id/$this->id/flash/";
1613 }
1614
1622 function &getSolutionValues($active_id, $pass = NULL)
1623 {
1624 global $ilDB;
1625
1626 $values = array();
1627
1628 if (is_null($pass))
1629 {
1630 $pass = $this->getSolutionMaxPass($active_id);
1631 }
1632
1633 $result = null;
1634 if( $this->getStep() !== NULL )
1635 {
1636 $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s AND step = %s ORDER BY solution_id",
1637 array('integer','integer','integer', 'integer'),
1638 array($active_id, $this->getId(), $pass, $this->getStep())
1639 );
1640 }
1641 else
1642 {
1643 $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s ORDER BY solution_id",
1644 array('integer','integer','integer'),
1645 array($active_id, $this->getId(), $pass)
1646 );
1647 }
1648
1649 while ($row = $ilDB->fetchAssoc($result))
1650 {
1651 array_push($values, $row);
1652 }
1653
1654 return $values;
1655 }
1656
1663 function isInUse($question_id = "")
1664 {
1665 global $ilDB;
1666
1667 if ($question_id < 1) $question_id = $this->getId();
1668 $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",
1669 array('integer'),
1670 array($question_id)
1671 );
1672 $row = $ilDB->fetchAssoc($result);
1673 $count = $row["question_count"];
1674
1675 $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",
1676 array('integer'),
1677 array($question_id)
1678 );
1679 $count += $result->numRows();
1680
1681 return $count;
1682 }
1683
1690 function isClone($question_id = "")
1691 {
1692 global $ilDB;
1693
1694 if ($question_id < 1) $question_id = $this->id;
1695 $result = $ilDB->queryF("SELECT original_id FROM qpl_questions WHERE question_id = %s",
1696 array('integer'),
1697 array($question_id)
1698 );
1699 $row = $ilDB->fetchAssoc($result);
1700 return ($row["original_id"] > 0) ? TRUE : FALSE;
1701 }
1702
1709 function pcArrayShuffle($array)
1710 {
1711 $keys = array_keys($array);
1712 shuffle($keys);
1713 $result = array();
1714 foreach ($keys as $key)
1715 {
1716 $result[$key] = $array[$key];
1717 }
1718 return $result;
1719 }
1720
1726 function getQuestionTypeFromDb($question_id)
1727 {
1728 global $ilDB;
1729
1730 $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",
1731 array('integer'),
1732 array($question_id)
1733 );
1734 $data = $ilDB->fetchAssoc($result);
1735 return $data["type_tag"];
1736 }
1737
1745 {
1746 return "";
1747 }
1748
1756 {
1757 return "";
1758 }
1759
1766 function deleteAnswers($question_id)
1767 {
1768 global $ilDB;
1769 $answer_table_name = $this->getAnswerTableName();
1770
1771 if( !is_array($answer_table_name) )
1772 {
1773 $answer_table_name = array($answer_table_name);
1774 }
1775
1776 foreach ($answer_table_name as $table)
1777 {
1778 if (strlen($table))
1779 {
1780 $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1781 array('integer'),
1782 array($question_id)
1783 );
1784 }
1785 }
1786 }
1787
1794 function deleteAdditionalTableData($question_id)
1795 {
1796 global $ilDB;
1797
1798 $additional_table_name = $this->getAdditionalTableName();
1799
1800 if( !is_array($additional_table_name) )
1801 {
1802 $additional_table_name = array($additional_table_name);
1803 }
1804
1805 foreach ($additional_table_name as $table)
1806 {
1807 if (strlen($table))
1808 {
1809 $affectedRows = $ilDB->manipulateF("DELETE FROM $table WHERE question_fi = %s",
1810 array('integer'),
1811 array($question_id)
1812 );
1813 }
1814 }
1815 }
1816
1823 protected function deletePageOfQuestion($question_id)
1824 {
1825 include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
1826 $page = new ilAssQuestionPage($question_id);
1827 $page->delete();
1828 return true;
1829 }
1830
1837 public function delete($question_id)
1838 {
1839 global $ilDB, $ilLog;
1840
1841 if ($question_id < 1) return true; // nothing to do
1842
1843 $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1844 array('integer'),
1845 array($question_id)
1846 );
1847 if ($result->numRows() == 1)
1848 {
1849 $row = $ilDB->fetchAssoc($result);
1850 $obj_id = $row["obj_fi"];
1851 }
1852 else
1853 {
1854 return true; // nothing to do
1855 }
1856 try
1857 {
1858 $this->deletePageOfQuestion($question_id);
1859 }
1860 catch (Exception $e)
1861 {
1862 $ilLog->write("EXCEPTION: Could not delete page of question $question_id: $e");
1863 return false;
1864 }
1865
1866 $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_questions WHERE question_id = %s",
1867 array('integer'),
1868 array($question_id)
1869 );
1870 if ($affectedRows == 0) return false;
1871
1872 try
1873 {
1874 $this->deleteAdditionalTableData($question_id);
1875 $this->deleteAnswers($question_id);
1876 $this->feedbackOBJ->deleteGenericFeedbacks($question_id, $this->isAdditionalContentEditingModePageObject());
1877 $this->feedbackOBJ->deleteSpecificAnswerFeedbacks($question_id, $this->isAdditionalContentEditingModePageObject());
1878 }
1879 catch (Exception $e)
1880 {
1881 $ilLog->write("EXCEPTION: Could not delete additional table data of question $question_id: $e");
1882 return false;
1883 }
1884
1885 try
1886 {
1887 // delete the question in the tst_test_question table (list of test questions)
1888 $affectedRows = $ilDB->manipulateF("DELETE FROM tst_test_question WHERE question_fi = %s",
1889 array('integer'),
1890 array($question_id)
1891 );
1892 }
1893 catch (Exception $e)
1894 {
1895 $ilLog->write("EXCEPTION: Could not delete delete question $question_id from a test: $e");
1896 return false;
1897 }
1898
1899 try
1900 {
1901 // delete suggested solutions contained in the question
1902 $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
1903 array('integer'),
1904 array($question_id)
1905 );
1906 }
1907 catch (Exception $e)
1908 {
1909 $ilLog->write("EXCEPTION: Could not delete suggested solutions of question $question_id: $e");
1910 return false;
1911 }
1912
1913 try
1914 {
1915 $directory = CLIENT_WEB_DIR . "/assessment/" . $obj_id . "/$question_id";
1916 if (preg_match("/\d+/", $obj_id) and preg_match("/\d+/", $question_id) and is_dir($directory))
1917 {
1918 include_once "./Services/Utilities/classes/class.ilUtil.php";
1919 ilUtil::delDir($directory);
1920 }
1921 }
1922 catch (Exception $e)
1923 {
1924 $ilLog->write("EXCEPTION: Could not delete question file directory $directory of question $question_id: $e");
1925 return false;
1926 }
1927
1928 try
1929 {
1930 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1931 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $question_id);
1932 // remaining usages are not in text anymore -> delete them
1933 // and media objects (note: delete method of ilObjMediaObject
1934 // checks whether object is used in another context; if yes,
1935 // the object is not deleted!)
1936 foreach($mobs as $mob)
1937 {
1938 ilObjMediaObject::_removeUsage($mob, "qpl:html", $question_id);
1939 if (ilObjMediaObject::_exists($mob))
1940 {
1941 $mob_obj =& new ilObjMediaObject($mob);
1942 $mob_obj->delete();
1943 }
1944 }
1945 }
1946 catch (Exception $e)
1947 {
1948 $ilLog->write("EXCEPTION: Error deleting the media objects of question $question_id: $e");
1949 return false;
1950 }
1951
1952 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
1954
1955 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
1957
1959
1960 try
1961 {
1962 // update question count of question pool
1963 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
1965 }
1966 catch (Exception $e)
1967 {
1968 $ilLog->write("EXCEPTION: Error updating the question pool question count of question pool " . $this->getObjId() . " when deleting question $question_id: $e");
1969 return false;
1970 }
1971
1972 $this->notifyQuestionDeleted($this);
1973
1974 return true;
1975 }
1976
1977 private function deleteTaxonomyAssignments()
1978 {
1979 require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
1980 require_once 'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
1981 $taxIds = ilObjTaxonomy::getUsageOfObject($this->getObjId());
1982
1983 foreach($taxIds as $taxId)
1984 {
1985 $taxNodeAssignment = new ilTaxNodeAssignment('qpl', $this->getObjId(), 'quest', $taxId);
1986 $taxNodeAssignment->deleteAssignmentsOfItem($this->getId());
1987 }
1988 }
1989
1994 {
1995 return $this->_getTotalAnswers($this->id);
1996 }
1997
2004 function _getTotalAnswers($a_q_id)
2005 {
2006 global $ilDB;
2007
2008 // get all question references to the question id
2009 $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
2010 array('integer','integer'),
2011 array($a_q_id, $a_q_id)
2012 );
2013 if ($result->numRows() == 0)
2014 {
2015 return 0;
2016 }
2017 $found_id = array();
2018 while ($row = $ilDB->fetchAssoc($result))
2019 {
2020 array_push($found_id, $row["question_id"]);
2021 }
2022
2023 $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
2024
2025 return $result->numRows();
2026 }
2027
2028
2035 public static function _getTotalRightAnswers($a_q_id)
2036 {
2037 global $ilDB;
2038 $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
2039 array('integer','integer'),
2040 array($a_q_id, $a_q_id)
2041 );
2042 if ($result->numRows() == 0)
2043 {
2044 return 0;
2045 }
2046 $found_id = array();
2047 while ($row = $ilDB->fetchAssoc($result))
2048 {
2049 array_push($found_id, $row["question_id"]);
2050 }
2051 $result = $ilDB->query("SELECT * FROM tst_test_result WHERE " . $ilDB->in('question_fi', $found_id, false, 'integer'));
2052 $answers = array();
2053 while ($row = $ilDB->fetchAssoc($result))
2054 {
2055 $reached = $row["points"];
2056 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2057 $max = assQuestion::_getMaximumPoints($row["question_fi"]);
2058 array_push($answers, array("reached" => $reached, "max" => $max));
2059 }
2060 $max = 0.0;
2061 $reached = 0.0;
2062 foreach ($answers as $key => $value)
2063 {
2064 $max += $value["max"];
2065 $reached += $value["reached"];
2066 }
2067 if ($max > 0)
2068 {
2069 return $reached / $max;
2070 }
2071 else
2072 {
2073 return 0;
2074 }
2075 }
2076
2082 function _getTitle($a_q_id)
2083 {
2084 global $ilDB;
2085 $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE question_id = %s",
2086 array('integer'),
2087 array($a_q_id)
2088 );
2089 if ($result->numRows() == 1)
2090 {
2091 $row = $ilDB->fetchAssoc($result);
2092 return $row["title"];
2093 }
2094 else
2095 {
2096 return "";
2097 }
2098 }
2099
2105 function _getQuestionText($a_q_id)
2106 {
2107 global $ilDB;
2108 $result = $ilDB->queryF("SELECT question_text FROM qpl_questions WHERE question_id = %s",
2109 array('integer'),
2110 array($a_q_id)
2111 );
2112 if ($result->numRows() == 1)
2113 {
2114 $row = $ilDB->fetchAssoc($result);
2115 return $row["question_text"];
2116 }
2117 else
2118 {
2119 return "";
2120 }
2121 }
2122
2123 public static function isFileAvailable($file)
2124 {
2125 if( !file_exists($file) )
2126 {
2127 return false;
2128 }
2129
2130 if( !is_file($file) )
2131 {
2132 return false;
2133 }
2134
2135 if( !is_readable($file) )
2136 {
2137 return false;
2138 }
2139
2140 return true;
2141 }
2142
2144 {
2145 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
2146 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $a_q_id);
2147 foreach ($mobs as $mob)
2148 {
2149 ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->getId());
2150 }
2151 }
2152
2154 {
2155 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
2156 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
2157 foreach ($mobs as $mob)
2158 {
2159 ilObjMediaObject::_saveUsage($mob, "qpl:html", $this->original_id);
2160 }
2161 }
2162
2167 {
2168 $qpl_id = $this->getObjId();
2169
2170 include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
2171 $this->page = new ilAssQuestionPage(0);
2172 $this->page->setId($this->getId());
2173 $this->page->setParentId($qpl_id);
2174 $this->page->setXMLContent("<PageObject><PageContent>".
2175 "<Question QRef=\"il__qst_".$this->getId()."\"/>".
2176 "</PageContent></PageObject>");
2177 $this->page->create();
2178 }
2179
2180 function copyPageOfQuestion($a_q_id)
2181 {
2182 if ($a_q_id > 0)
2183 {
2184 include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
2185 $page = new ilAssQuestionPage($a_q_id);
2186
2187 $xml = str_replace("il__qst_".$a_q_id, "il__qst_".$this->id, $page->getXMLContent());
2188 $this->page->setXMLContent($xml);
2189 $this->page->updateFromXML();
2190 }
2191 }
2192
2194 {
2195 include_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
2196 $page = new ilAssQuestionPage($this->id);
2197 return $page->getXMLContent();
2198 }
2199
2207 function _getQuestionType($question_id)
2208 {
2209 global $ilDB;
2210
2211 if ($question_id < 1) return "";
2212 $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",
2213 array('integer'),
2214 array($question_id)
2215 );
2216 if ($result->numRows() == 1)
2217 {
2218 $data = $ilDB->fetchAssoc($result);
2219 return $data["type_tag"];
2220 }
2221 else
2222 {
2223 return "";
2224 }
2225 }
2226
2234 function _getQuestionTitle($question_id)
2235 {
2236 global $ilDB;
2237
2238 if ($question_id < 1) return "";
2239
2240 $result = $ilDB->queryF("SELECT title FROM qpl_questions WHERE qpl_questions.question_id = %s",
2241 array('integer'),
2242 array($question_id)
2243 );
2244 if ($result->numRows() == 1)
2245 {
2246 $data = $ilDB->fetchAssoc($result);
2247 return $data["title"];
2248 }
2249 else
2250 {
2251 return "";
2252 }
2253 }
2254
2256 {
2257 $this->original_id = $original_id;
2258 }
2259
2260 function getOriginalId()
2261 {
2262 return $this->original_id;
2263 }
2264
2265 protected static $imageSourceFixReplaceMap = array(
2266 'ok.svg' => 'ok.png', 'not_ok.svg' => 'not_ok.png',
2267 'checkbox_checked.svg' => 'checkbox_checked.png',
2268 'checkbox_unchecked.svg' => 'checkbox_unchecked.png',
2269 'radiobutton_checked.svg' => 'radiobutton_checked.png',
2270 'radiobutton_unchecked.svg' => 'radiobutton_unchecked.png'
2271 );
2272
2273 public function fixSvgToPng($imageFilenameContainingString)
2274 {
2275 $needles = array_keys(self::$imageSourceFixReplaceMap);
2276 $replacements = array_values(self::$imageSourceFixReplaceMap);
2277 return str_replace($needles, $replacements, $imageFilenameContainingString);
2278 }
2279
2280
2281 public function fixUnavailableSkinImageSources($html)
2282 {
2283 $matches = null;
2284 if( preg_match_all('/src="(.*?)"/m', $html, $matches) )
2285 {
2286 $sources = $matches[1];
2287
2288 $needleReplacementMap = array();
2289
2290 foreach($sources as $src)
2291 {
2292 $file = ilUtil::removeTrailingPathSeparators( ILIAS_ABSOLUTE_PATH ) . DIRECTORY_SEPARATOR . $src;
2293
2294 if( file_exists($file) )
2295 {
2296 continue;
2297 }
2298
2299 $levels = explode(DIRECTORY_SEPARATOR, $src);
2300 if( count($levels) < 5 || $levels[0] != 'Customizing' || $levels[2] != 'skin' )
2301 {
2302 continue;
2303 }
2304
2305 $component = '';
2306
2307 if( $levels[4] == 'Modules' || $levels[4] == 'Services' )
2308 {
2309 $component = $levels[4] . DIRECTORY_SEPARATOR . $levels[5];
2310 }
2311
2312 $needleReplacementMap[$src] = ilUtil::getImagePath(basename($src), $component);
2313 }
2314
2315 if( count($needleReplacementMap) )
2316 {
2317 $html = str_replace(array_keys($needleReplacementMap), array_values($needleReplacementMap), $html);
2318 }
2319 }
2320
2321 return $html;
2322 }
2323
2330 function loadFromDb($question_id)
2331 {
2332 global $ilDB;
2333
2334 $result = $ilDB->queryF(
2335 "SELECT external_id FROM qpl_questions WHERE question_id = %s",
2336 array("integer"),
2337 array($question_id)
2338 );
2339 if($result->numRows() == 1)
2340 {
2341 $data = $ilDB->fetchAssoc($result);
2342 $this->external_id = $data['external_id'];
2343 }
2344
2345 $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2346 array('integer'),
2347 array($this->getId())
2348 );
2349 $this->suggested_solutions = array();
2350 if ($result->numRows())
2351 {
2352 include_once("./Services/RTE/classes/class.ilRTE.php");
2353 while ($row = $ilDB->fetchAssoc($result))
2354 {
2355 $value = (is_array(unserialize($row["value"]))) ? unserialize($row["value"]) : ilRTE::_replaceMediaObjectImageSrc($row["value"], 1);
2356 $this->suggested_solutions[$row["subquestion_index"]] = array(
2357 "type" => $row["type"],
2358 "value" => $value,
2359 "internal_link" => $row["internal_link"],
2360 "import_id" => $row["import_id"]
2361 );
2362 }
2363 }
2364 }
2365
2372 public function createNewQuestion($a_create_page = true)
2373 {
2374 global $ilDB, $ilUser;
2375
2376 $complete = "0";
2377 $estw_time = $this->getEstimatedWorkingTime();
2378 $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
2379 $obj_id = ($this->getObjId() <= 0) ? (ilObject::_lookupObjId((strlen($_GET["ref_id"])) ? $_GET["ref_id"] : $_POST["sel_qpl"])) : $this->getObjId();
2380 if ($obj_id > 0)
2381 {
2382 if($a_create_page)
2383 {
2384 $tstamp = 0;
2385 }
2386 else
2387 {
2388 // question pool must not try to purge
2389 $tstamp = time();
2390 }
2391
2392 $next_id = $ilDB->nextId('qpl_questions');
2393 $affectedRows = $ilDB->insert("qpl_questions", array(
2394 "question_id" => array("integer", $next_id),
2395 "question_type_fi" => array("integer", $this->getQuestionTypeID()),
2396 "obj_fi" => array("integer", $obj_id),
2397 "title" => array("text", NULL),
2398 "description" => array("text", NULL),
2399 "author" => array("text", $this->getAuthor()),
2400 "owner" => array("integer", $ilUser->getId()),
2401 "question_text" => array("clob", NULL),
2402 "points" => array("float", 0),
2403 "nr_of_tries" => array("integer", $this->getDefaultNrOfTries()), // #10771
2404 "working_time" => array("text", $estw_time),
2405 "complete" => array("text", $complete),
2406 "created" => array("integer", time()),
2407 "original_id" => array("integer", NULL),
2408 "tstamp" => array("integer", $tstamp),
2409 "external_id" => array("text", $this->getExternalId()),
2410 'add_cont_edit_mode' => array('text', $this->getAdditionalContentEditingMode())
2411 ));
2412 $this->setId($next_id);
2413
2414 if($a_create_page)
2415 {
2416 // create page object of question
2417 $this->createPageObject();
2418 }
2419 }
2420
2421 $this->notifyQuestionCreated();
2422
2423 return $this->getId();
2424 }
2425
2427 {
2428 global $ilDB;
2429
2430 $estw_time = $this->getEstimatedWorkingTime();
2431 $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
2432
2433 // cleanup RTE images which are not inserted into the question text
2434 include_once("./Services/RTE/classes/class.ilRTE.php");
2435 if ($this->getId() == -1)
2436 {
2437 // Neuen Datensatz schreiben
2438 $next_id = $ilDB->nextId('qpl_questions');
2439 $affectedRows = $ilDB->insert("qpl_questions", array(
2440 "question_id" => array("integer", $next_id),
2441 "question_type_fi" => array("integer", $this->getQuestionTypeID()),
2442 "obj_fi" => array("integer", $this->getObjId()),
2443 "title" => array("text", $this->getTitle()),
2444 "description" => array("text", $this->getComment()),
2445 "author" => array("text", $this->getAuthor()),
2446 "owner" => array("integer", $this->getOwner()),
2447 "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
2448 "points" => array("float", $this->getMaximumPoints()),
2449 "working_time" => array("text", $estw_time),
2450 "nr_of_tries" => array("integer", $this->getNrOfTries()),
2451 "created" => array("integer", time()),
2452 "original_id" => array("integer", ($original_id) ? $original_id : NULL),
2453 "tstamp" => array("integer", time()),
2454 "external_id" => array("text", $this->getExternalId()),
2455 'add_cont_edit_mode' => array('text', $this->getAdditionalContentEditingMode())
2456 ));
2457 $this->setId($next_id);
2458 // create page object of question
2459 $this->createPageObject();
2460 }
2461 else
2462 {
2463 // Vorhandenen Datensatz aktualisieren
2464 $affectedRows = $ilDB->update("qpl_questions", array(
2465 "obj_fi" => array("integer", $this->getObjId()),
2466 "title" => array("text", $this->getTitle()),
2467 "description" => array("text", $this->getComment()),
2468 "author" => array("text", $this->getAuthor()),
2469 "question_text" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0)),
2470 "points" => array("float", $this->getMaximumPoints()),
2471 "nr_of_tries" => array("integer", $this->getNrOfTries()),
2472 "working_time" => array("text", $estw_time),
2473 "tstamp" => array("integer", time()),
2474 'complete' => array('integer', $this->isComplete()),
2475 "external_id" => array("text", $this->getExternalId())
2476 ), array(
2477 "question_id" => array("integer", $this->getId())
2478 ));
2479 }
2480 }
2481
2488 function saveToDb($original_id = "")
2489 {
2490 global $ilDB;
2491
2492 $this->updateSuggestedSolutions();
2493
2494 // remove unused media objects from ILIAS
2495 $this->cleanupMediaObjectUsage();
2496
2497 $complete = "0";
2498 if ($this->isComplete())
2499 {
2500 $complete = "1";
2501 }
2502
2503 // update the question time stamp and completion status
2504 $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET tstamp = %s, owner = %s, complete = %s WHERE question_id = %s",
2505 array('integer','integer', 'integer','text'),
2506 array(time(), ($this->getOwner() <= 0) ? $this->ilias->account->id : $this->getOwner(), $complete, $this->getId())
2507 );
2508
2509 // update question count of question pool
2510 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
2512
2513 $this->notifyQuestionEdited($this);
2514 }
2515
2516 public function setNewOriginalId($newId) {
2517 global $ilDB;
2518 $ilDB->manipulateF("UPDATE qpl_questions SET tstamp = %s, original_id = %s WHERE question_id = %s",
2519 array('integer','integer', 'text'),
2520 array(time(), $newId, $this->getId())
2521 );
2522 }
2523
2527 protected function onDuplicate($originalParentId, $originalQuestionId, $duplicateParentId, $duplicateQuestionId)
2528 {
2529 $this->duplicateSuggestedSolutionFiles($originalParentId, $originalQuestionId);
2530
2531 // duplicate question feeback
2532 $this->feedbackOBJ->duplicateFeedback($originalQuestionId, $duplicateQuestionId);
2533
2534 // duplicate question hints
2535 $this->duplicateQuestionHints($originalQuestionId, $duplicateQuestionId);
2536 }
2537
2538 protected function beforeSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
2539 {
2540
2541 }
2542
2543 protected function afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
2544 {
2545 // sync question feeback
2546 $this->feedbackOBJ->syncFeedback($origQuestionId, $dupQuestionId);
2547 }
2548
2552 protected function onCopy($sourceParentId, $sourceQuestionId, $targetParentId, $targetQuestionId)
2553 {
2554 $this->copySuggestedSolutionFiles($sourceParentId, $sourceQuestionId);
2555
2556 // duplicate question feeback
2557 $this->feedbackOBJ->duplicateFeedback($sourceQuestionId, $targetQuestionId);
2558
2559 // duplicate question hints
2560 $this->duplicateQuestionHints($sourceQuestionId, $targetQuestionId);
2561 }
2562
2567 {
2568 global $ilDB;
2569 // delete the links in the qpl_sol_sug table
2570 $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
2571 array('integer'),
2572 array($this->getId())
2573 );
2574 // delete the links in the int_link table
2575 include_once "./Services/Link/classes/class.ilInternalLink.php";
2577 $this->suggested_solutions = array();
2579 }
2580
2588 function getSuggestedSolution($subquestion_index = 0)
2589 {
2590 if (array_key_exists($subquestion_index, $this->suggested_solutions))
2591 {
2592 return $this->suggested_solutions[$subquestion_index];
2593 }
2594 else
2595 {
2596 return array();
2597 }
2598 }
2599
2608 function getSuggestedSolutionTitle($subquestion_index = 0)
2609 {
2610 if (array_key_exists($subquestion_index, $this->suggested_solutions))
2611 {
2612 $title = $this->suggested_solutions[$subquestion_index]["internal_link"];
2613 // TO DO: resolve internal link an get link type and title
2614 }
2615 else
2616 {
2617 $title = "";
2618 }
2619 return $title;
2620 }
2621
2631 function setSuggestedSolution($solution_id = "", $subquestion_index = 0, $is_import = false)
2632 {
2633 if (strcmp($solution_id, "") != 0)
2634 {
2635 $import_id = "";
2636 if ($is_import)
2637 {
2638 $import_id = $solution_id;
2639 $solution_id = $this->_resolveInternalLink($import_id);
2640 }
2641 $this->suggested_solutions[$subquestion_index] = array(
2642 "internal_link" => $solution_id,
2643 "import_id" => $import_id
2644 );
2645 }
2646 }
2647
2651 protected function duplicateSuggestedSolutionFiles($parent_id, $question_id)
2652 {
2653 global $ilLog;
2654
2655 foreach ($this->suggested_solutions as $index => $solution)
2656 {
2657 if (strcmp($solution["type"], "file") == 0)
2658 {
2659 $filepath = $this->getSuggestedSolutionPath();
2660 $filepath_original = str_replace(
2661 "/{$this->obj_id}/{$this->id}/solution",
2662 "/$parent_id/$question_id/solution",
2663 $filepath
2664 );
2665 if (!file_exists($filepath))
2666 {
2667 ilUtil::makeDirParents($filepath);
2668 }
2669 $filename = $solution["value"]["name"];
2670 if (strlen($filename))
2671 {
2672 if (!copy($filepath_original . $filename, $filepath . $filename))
2673 {
2674 $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
2675 $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2676 }
2677 }
2678 }
2679 }
2680 }
2681
2686 {
2687 global $ilLog;
2688
2689 $filepath = $this->getSuggestedSolutionPath();
2690 $filepath_original = str_replace("/$this->id/solution", "/$original_id/solution", $filepath);
2691 ilUtil::delDir($filepath_original);
2692 foreach ($this->suggested_solutions as $index => $solution)
2693 {
2694 if (strcmp($solution["type"], "file") == 0)
2695 {
2696 if (!file_exists($filepath_original))
2697 {
2698 ilUtil::makeDirParents($filepath_original);
2699 }
2700 $filename = $solution["value"]["name"];
2701 if (strlen($filename))
2702 {
2703 if (!@copy($filepath . $filename, $filepath_original . $filename))
2704 {
2705 $ilLog->write("File could not be duplicated!!!!", $ilLog->ERROR);
2706 $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2707 }
2708 }
2709 }
2710 }
2711 }
2712
2713 protected function copySuggestedSolutionFiles($source_questionpool_id, $source_question_id)
2714 {
2715 global $ilLog;
2716
2717 foreach ($this->suggested_solutions as $index => $solution)
2718 {
2719 if (strcmp($solution["type"], "file") == 0)
2720 {
2721 $filepath = $this->getSuggestedSolutionPath();
2722 $filepath_original = str_replace("/$this->obj_id/$this->id/solution", "/$source_questionpool_id/$source_question_id/solution", $filepath);
2723 if (!file_exists($filepath))
2724 {
2725 ilUtil::makeDirParents($filepath);
2726 }
2727 $filename = $solution["value"]["name"];
2728 if (strlen($filename))
2729 {
2730 if (!copy($filepath_original . $filename, $filepath . $filename))
2731 {
2732 $ilLog->write("File could not be copied!!!!", $ilLog->ERROR);
2733 $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
2734 }
2735 }
2736 }
2737 }
2738 }
2739
2743 public function updateSuggestedSolutions($original_id = "")
2744 {
2745 global $ilDB;
2746
2747 $id = (strlen($original_id) && is_numeric($original_id)) ? $original_id : $this->getId();
2748 include_once "./Services/Link/classes/class.ilInternalLink.php";
2749 $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s",
2750 array('integer'),
2751 array($id)
2752 );
2754 include_once("./Services/RTE/classes/class.ilRTE.php");
2755 foreach ($this->suggested_solutions as $index => $solution)
2756 {
2757 $next_id = $ilDB->nextId('qpl_sol_sug');
2759 $ilDB->insert('qpl_sol_sug', array(
2760 'suggested_solution_id' => array( 'integer', $next_id ),
2761 'question_fi' => array( 'integer', $id ),
2762 'type' => array( 'text', $solution['type'] ),
2763 'value' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( (is_array( $solution['value'] ) ) ? serialize( $solution[ 'value' ] ) : $solution['value'], 0 ) ),
2764 'internal_link' => array( 'text', $solution['internal_link'] ),
2765 'import_id' => array( 'text', null ),
2766 'subquestion_index' => array( 'integer', $index ),
2767 'tstamp' => array( 'integer', time() ),
2768 )
2769 );
2770 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
2771 {
2772 ilInternalLink::_saveLink("qst", $id, $matches[2], $matches[3], $matches[1]);
2773 }
2774 }
2775 if (strlen($original_id) && is_numeric($original_id)) $this->syncSuggestedSolutionFiles($id);
2776 $this->cleanupMediaObjectUsage();
2777 }
2778
2788 function saveSuggestedSolution($type, $solution_id = "", $subquestion_index = 0, $value = "")
2789 {
2790 global $ilDB;
2791
2792 $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
2793 array("integer", "integer"),
2794 array(
2795 $this->getId(),
2796 $subquestion_index
2797 )
2798 );
2799
2800 $next_id = $ilDB->nextId('qpl_sol_sug');
2801 include_once("./Services/RTE/classes/class.ilRTE.php");
2803 $affectedRows = $ilDB->insert('qpl_sol_sug', array(
2804 'suggested_solution_id' => array( 'integer', $next_id ),
2805 'question_fi' => array( 'integer', $this->getId() ),
2806 'type' => array( 'text', $type ),
2807 'value' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc( (is_array( $value ) ) ? serialize( $value ) : $value, 0 ) ),
2808 'internal_link' => array( 'text', $solution_id ),
2809 'import_id' => array( 'text', null ),
2810 'subquestion_index' => array( 'integer', $subquestion_index ),
2811 'tstamp' => array( 'integer', time() ),
2812 )
2813 );
2814 if ($affectedRows == 1)
2815 {
2816 $this->suggested_solutions[$subquestion_index] = array(
2817 "type" => $type,
2818 "value" => $value,
2819 "internal_link" => $solution_id,
2820 "import_id" => ""
2821 );
2822 }
2823 $this->cleanupMediaObjectUsage();
2824 }
2825
2826 function _resolveInternalLink($internal_link)
2827 {
2828 if (preg_match("/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches))
2829 {
2830 include_once "./Services/Link/classes/class.ilInternalLink.php";
2831 include_once "./Modules/LearningModule/classes/class.ilLMObject.php";
2832 include_once "./Modules/Glossary/classes/class.ilGlossaryTerm.php";
2833 switch ($matches[2])
2834 {
2835 case "lm":
2836 $resolved_link = ilLMObject::_getIdForImportId($internal_link);
2837 break;
2838 case "pg":
2839 $resolved_link = ilInternalLink::_getIdForImportId("PageObject", $internal_link);
2840 break;
2841 case "st":
2842 $resolved_link = ilInternalLink::_getIdForImportId("StructureObject", $internal_link);
2843 break;
2844 case "git":
2845 $resolved_link = ilInternalLink::_getIdForImportId("GlossaryItem", $internal_link);
2846 break;
2847 case "mob":
2848 $resolved_link = ilInternalLink::_getIdForImportId("MediaObject", $internal_link);
2849 break;
2850 }
2851 if (strcmp($resolved_link, "") == 0)
2852 {
2853 $resolved_link = $internal_link;
2854 }
2855 }
2856 else
2857 {
2858 $resolved_link = $internal_link;
2859 }
2860 return $resolved_link;
2861 }
2862
2863 function _resolveIntLinks($question_id)
2864 {
2865 global $ilDB;
2866 $resolvedlinks = 0;
2867 $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2868 array('integer'),
2869 array($question_id)
2870 );
2871 if ($result->numRows())
2872 {
2873 while ($row = $ilDB->fetchAssoc($result))
2874 {
2875 $internal_link = $row["internal_link"];
2876 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
2877 $resolved_link = assQuestion::_resolveInternalLink($internal_link);
2878 if (strcmp($internal_link, $resolved_link) != 0)
2879 {
2880 // internal link was resolved successfully
2881 $affectedRows = $ilDB->manipulateF("UPDATE qpl_sol_sug SET internal_link = %s WHERE suggested_solution_id = %s",
2882 array('text','integer'),
2883 array($resolved_link, $row["suggested_solution_id"])
2884 );
2885 $resolvedlinks++;
2886 }
2887 }
2888 }
2889 if ($resolvedlinks)
2890 {
2891 // there are resolved links -> reenter theses links to the database
2892
2893 // delete all internal links from the database
2894 include_once "./Services/Link/classes/class.ilInternalLink.php";
2895 ilInternalLink::_deleteAllLinksOfSource("qst", $question_id);
2896
2897 $result = $ilDB->queryF("SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
2898 array('integer'),
2899 array($question_id)
2900 );
2901 if ($result->numRows())
2902 {
2903 while ($row = $ilDB->fetchAssoc($result))
2904 {
2905 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $row["internal_link"], $matches))
2906 {
2907 ilInternalLink::_saveLink("qst", $question_id, $matches[2], $matches[3], $matches[1]);
2908 }
2909 }
2910 }
2911 }
2912 }
2913
2914 function _getInternalLinkHref($target = "")
2915 {
2916 global $ilDB;
2917 $linktypes = array(
2918 "lm" => "LearningModule",
2919 "pg" => "PageObject",
2920 "st" => "StructureObject",
2921 "git" => "GlossaryItem",
2922 "mob" => "MediaObject"
2923 );
2924 $href = "";
2925 if (preg_match("/il__(\w+)_(\d+)/", $target, $matches))
2926 {
2927 $type = $matches[1];
2928 $target_id = $matches[2];
2929 include_once "./Services/Utilities/classes/class.ilUtil.php";
2930 switch($linktypes[$matches[1]])
2931 {
2932 case "LearningModule":
2933 $href = "./goto.php?target=" . $type . "_" . $target_id;
2934 break;
2935 case "PageObject":
2936 case "StructureObject":
2937 $href = "./goto.php?target=" . $type . "_" . $target_id;
2938 break;
2939 case "GlossaryItem":
2940 $href = "./goto.php?target=" . $type . "_" . $target_id;
2941 break;
2942 case "MediaObject":
2943 $href = "./ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[$type] . "&cmd=media&ref_id=".$_GET["ref_id"]."&mob_id=".$target_id;
2944 break;
2945 }
2946 }
2947 return $href;
2948 }
2949
2957 public static function _getOriginalId($question_id)
2958 {
2959 global $ilDB;
2960 $result = $ilDB->queryF("SELECT * FROM qpl_questions WHERE question_id = %s",
2961 array('integer'),
2962 array($question_id)
2963 );
2964 if ($result->numRows() > 0)
2965 {
2966 $row = $ilDB->fetchAssoc($result);
2967 if ($row["original_id"] > 0)
2968 {
2969 return $row["original_id"];
2970 }
2971 else
2972 {
2973 return $row["question_id"];
2974 }
2975 }
2976 else
2977 {
2978 return "";
2979 }
2980 }
2981
2982 public static function originalQuestionExists($questionId)
2983 {
2984 global $ilDB;
2985
2986 $query = "
2987 SELECT COUNT(dupl.question_id) cnt
2988 FROM qpl_questions dupl
2989 INNER JOIN qpl_questions orig
2990 ON orig.question_id = dupl.original_id
2991 WHERE dupl.question_id = %s
2992 ";
2993
2994 $res = $ilDB->queryF($query, array('integer'), array($questionId));
2995 $row = $ilDB->fetchAssoc($res);
2996
2997 return $row['cnt'] > 0;
2998 }
2999
3001 {
3002 global $ilDB;
3003
3004 if( !$this->getOriginalId() )
3005 {
3006 return;
3007 }
3008
3009 $originalObjId = self::lookupOriginalParentObjId($this->getOriginalId());
3010
3011 if ( !$originalObjId )
3012 {
3013 return;
3014 }
3015
3016 $id = $this->getId();
3017 $objId = $this->getObjId();
3018 $original = $this->getOriginalId();
3019
3020 $this->beforeSyncWithOriginal($original, $id, $originalObjId, $objId);
3021
3022 $this->setId($this->getOriginalId());
3023 $this->setOriginalId(NULL);
3024 $this->setObjId($originalObjId);
3025 $this->saveToDb();
3026 $this->deletePageOfQuestion($original);
3027 $this->createPageObject();
3028 $this->copyPageOfQuestion($id);
3029
3030 $this->setId($id);
3031 $this->setOriginalId($original);
3032 $this->updateSuggestedSolutions($original);
3034
3035 $this->afterSyncWithOriginal($original, $id, $originalObjId, $objId);
3036 $this->syncHints();
3037 }
3038
3039 function createRandomSolution($test_id, $user_id)
3040 {
3041 }
3042
3050 function _questionExists($question_id)
3051 {
3052 global $ilDB;
3053
3054 if ($question_id < 1)
3055 {
3056 return false;
3057 }
3058
3059 $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE question_id = %s",
3060 array('integer'),
3061 array($question_id)
3062 );
3063 if ($result->numRows() == 1)
3064 {
3065 return true;
3066 }
3067 else
3068 {
3069 return false;
3070 }
3071 }
3072
3080 function _questionExistsInPool($question_id)
3081 {
3082 global $ilDB;
3083
3084 if ($question_id < 1)
3085 {
3086 return false;
3087 }
3088
3089 $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'",
3090 array('integer'),
3091 array($question_id)
3092 );
3093 if ($result->numRows() == 1)
3094 {
3095 return true;
3096 }
3097 else
3098 {
3099 return false;
3100 }
3101 }
3102
3110 public static function _instanciateQuestion($question_id)
3111 {
3112 return self::_instantiateQuestion($question_id);
3113 }
3114
3115 public static function _instantiateQuestion($question_id)
3116 {
3117 global $ilCtrl, $ilDB, $lng;
3118
3119 if (strcmp($question_id, "") != 0)
3120 {
3121 $question_type = assQuestion::_getQuestionType($question_id);
3122 if (!strlen($question_type)) return null;
3123 assQuestion::_includeClass($question_type);
3124 $objectClassname = self::getObjectClassNameByQuestionType($question_type);
3125 $question = new $objectClassname();
3126 $question->loadFromDb($question_id);
3127
3128 $feedbackObjectClassname = self::getFeedbackClassNameByQuestionType($question_type);
3129 $question->feedbackOBJ = new $feedbackObjectClassname($question, $ilCtrl, $ilDB, $lng);
3130
3131 return $question;
3132 }
3133 }
3134
3141 function getPoints()
3142 {
3143 if (strcmp($this->points, "") == 0)
3144 {
3145 return 0;
3146 }
3147 else
3148 {
3149 return $this->points;
3150 }
3151 }
3152
3153
3160 function setPoints($a_points)
3161 {
3162 $this->points = $a_points;
3163 }
3164
3171 function getSolutionMaxPass($active_id)
3172 {
3173 return $this->_getSolutionMaxPass($this->getId(), $active_id);
3174 }
3175
3182 function _getSolutionMaxPass($question_id, $active_id)
3183 {
3184/* include_once "./Modules/Test/classes/class.ilObjTest.php";
3185 $pass = ilObjTest::_getPass($active_id);
3186 return $pass;*/
3187
3188 // the following code was the old solution which added the non answered
3189 // questions of a pass from the answered questions of the previous pass
3190 // with the above solution, only the answered questions of the last pass are counted
3191 global $ilDB;
3192
3193 $result = $ilDB->queryF("SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
3194 array('integer','integer'),
3195 array($active_id, $question_id)
3196 );
3197 if ($result->numRows() == 1)
3198 {
3199 $row = $ilDB->fetchAssoc($result);
3200 return $row["maxpass"];
3201 }
3202 else
3203 {
3204 return 0;
3205 }
3206 }
3207
3216 function _isWriteable($question_id, $user_id)
3217 {
3218 global $ilDB;
3219
3220 if (($question_id < 1) || ($user_id < 1))
3221 {
3222 return false;
3223 }
3224
3225 $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
3226 array('integer'),
3227 array($question_id)
3228 );
3229 if ($result->numRows() == 1)
3230 {
3231 $row = $ilDB->fetchAssoc($result);
3232 $qpl_object_id = $row["obj_fi"];
3233 include_once "./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
3234 return ilObjQuestionPool::_isWriteable($qpl_object_id, $user_id);
3235 }
3236 else
3237 {
3238 return false;
3239 }
3240 }
3241
3248 function _isUsedInRandomTest($question_id = "")
3249 {
3250 global $ilDB;
3251
3252 if ($question_id < 1) return 0;
3253 $result = $ilDB->queryF("SELECT test_random_question_id FROM tst_test_rnd_qst WHERE question_fi = %s",
3254 array('integer'),
3255 array($question_id)
3256 );
3257 return $result->numRows();
3258 }
3259
3271 abstract public function calculateReachedPoints($active_id, $pass = NULL, $returndetails = FALSE);
3272
3274 {
3275 return $this->calculateReachedPointsForSolution($previewSession->getParticipantsSolution());
3276 }
3277
3279 {
3280 $reachedPoints = $this->calculateReachedPointsFromPreviewSession($previewSession);
3281
3282 if( $reachedPoints < $this->getMaximumPoints() )
3283 {
3284 return false;
3285 }
3286
3287 return true;
3288 }
3289
3290
3301 final public function adjustReachedPointsByScoringOptions($points, $active_id, $pass = NULL)
3302 {
3303 include_once "./Modules/Test/classes/class.ilObjTest.php";
3304 $count_system = ilObjTest::_getCountSystem($active_id);
3305 if ($count_system == 1)
3306 {
3307 if (abs($this->getMaximumPoints() - $points) > 0.0000000001)
3308 {
3309 $points = 0;
3310 }
3311 }
3312 $score_cutting = ilObjTest::_getScoreCutting($active_id);
3313 if ($score_cutting == 0)
3314 {
3315 if ($points < 0)
3316 {
3317 $points = 0;
3318 }
3319 }
3320 return $points;
3321 }
3322
3331 public static function _isWorkedThrough($active_id, $question_id, $pass = NULL)
3332 {
3333 global $ilDB;
3334
3335 $points = 0;
3336 if (is_null($pass))
3337 {
3338 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
3339 $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
3340 }
3341 $result = $ilDB->queryF("SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
3342 array('integer','integer','integer'),
3343 array($active_id, $question_id, $pass)
3344 );
3345 if ($result->numRows())
3346 {
3347 return TRUE;
3348 }
3349 else
3350 {
3351 return FALSE;
3352 }
3353 }
3354
3362 public static function _areAnswered($a_user_id,$a_question_ids)
3363 {
3364 global $ilDB;
3365
3366 $res = $ilDB->queryF("SELECT DISTINCT(question_fi) FROM tst_test_result JOIN tst_active ".
3367 "ON (active_id = active_fi) ".
3368 "WHERE " . $ilDB->in('question_fi', $a_question_ids, false, 'integer') .
3369 " AND user_fi = %s",
3370 array('integer'),
3371 array($a_user_id)
3372 );
3373 return ($res->numRows() == count($a_question_ids)) ? true : false;
3374 }
3375
3384 function isHTML($a_text)
3385 {
3386 if (preg_match("/<[^>]*?>/", $a_text))
3387 {
3388 return TRUE;
3389 }
3390 else
3391 {
3392 return FALSE;
3393 }
3394 }
3395
3402 function prepareTextareaOutput($txt_output, $prepare_for_latex_output = FALSE)
3403 {
3404 include_once "./Services/Utilities/classes/class.ilUtil.php";
3405 return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output);
3406 }
3407
3415 function QTIMaterialToString($a_material)
3416 {
3417 $result = "";
3418 for ($i = 0; $i < $a_material->getMaterialCount(); $i++)
3419 {
3420 $material = $a_material->getMaterial($i);
3421 if (strcmp($material["type"], "mattext") == 0)
3422 {
3423 $result .= $material["material"]->getContent();
3424 }
3425 if (strcmp($material["type"], "matimage") == 0)
3426 {
3427 $matimage = $material["material"];
3428 if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches))
3429 {
3430 // import an mediaobject which was inserted using tiny mce
3431 if (!is_array($_SESSION["import_mob_xhtml"])) $_SESSION["import_mob_xhtml"] = array();
3432 array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri()));
3433 }
3434 }
3435 }
3436 return $result;
3437 }
3438
3447 function addQTIMaterial(&$a_xml_writer, $a_material, $close_material_tag = TRUE, $add_mobs = TRUE)
3448 {
3449 include_once "./Services/RTE/classes/class.ilRTE.php";
3450 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
3451
3452 $a_xml_writer->xmlStartTag("material");
3453 $attrs = array(
3454 "texttype" => "text/plain"
3455 );
3456 if ($this->isHTML($a_material))
3457 {
3458 $attrs["texttype"] = "text/xhtml";
3459 }
3460 $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0));
3461 if ($add_mobs)
3462 {
3463 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
3464 foreach ($mobs as $mob)
3465 {
3466 $moblabel = "il_" . IL_INST_ID . "_mob_" . $mob;
3467 if (strpos($a_material, "mm_$mob") !== FALSE)
3468 {
3469 if (ilObjMediaObject::_exists($mob))
3470 {
3471 $mob_obj =& new ilObjMediaObject($mob);
3472 $imgattrs = array(
3473 "label" => $moblabel,
3474 "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle()
3475 );
3476 }
3477 $a_xml_writer->xmlElement("matimage", $imgattrs, NULL);
3478 }
3479 }
3480 }
3481 if ($close_material_tag) $a_xml_writer->xmlEndTag("material");
3482 }
3483
3484 function createNewImageFileName($image_filename, $unique = false)
3485 {
3486 $extension = "";
3487
3488 if (preg_match("/.*\.(png|jpg|gif|jpeg)$/i", $image_filename, $matches))
3489 {
3490 $extension = "." . $matches[1];
3491 }
3492
3493 if($unique)
3494 {
3495 $image_filename = uniqid($image_filename.microtime(true));
3496 }
3497
3498 $image_filename = md5($image_filename) . $extension;
3499
3500 return $image_filename;
3501 }
3502
3513 function _setReachedPoints($active_id, $question_id, $points, $maxpoints, $pass, $manualscoring, $obligationsEnabled)
3514 {
3515 global $ilDB;
3516
3517 if ($points <= $maxpoints)
3518 {
3519 if (is_null($pass))
3520 {
3521 $pass = assQuestion::_getSolutionMaxPass($question_id, $active_id);
3522 }
3523
3524 // retrieve the already given points
3525 $old_points = 0;
3526 $result = $ilDB->queryF("SELECT points FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
3527 array('integer','integer','integer'),
3528 array($active_id, $question_id, $pass)
3529 );
3530 $manual = ($manualscoring) ? 1 : 0;
3531 $rowsnum = $result->numRows();
3532 if($rowsnum)
3533 {
3534 $row = $ilDB->fetchAssoc($result);
3535 $old_points = $row["points"];
3536 if($old_points != $points)
3537 {
3538 $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",
3539 array('float', 'integer', 'integer', 'integer', 'integer', 'integer'),
3540 array($points, $manual, time(), $active_id, $question_id, $pass)
3541 );
3542 }
3543 }
3544 else
3545 {
3546 $next_id = $ilDB->nextId('tst_test_result');
3547 $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)",
3548 array('integer', 'integer','integer', 'float', 'integer', 'integer','integer'),
3549 array($next_id, $active_id, $question_id, $points, $pass, $manual, time())
3550 );
3551 }
3552
3553 if($old_points != $points || !$rowsnum)
3554 {
3555 assQuestion::_updateTestPassResults($active_id, $pass, $obligationsEnabled);
3556 // finally update objective result
3557 include_once "./Modules/Test/classes/class.ilObjTest.php";
3558 include_once './Modules/Course/classes/class.ilCourseObjectiveResult.php';
3560
3561 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3563 {
3564 global $lng, $ilUser;
3565 include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
3566 $username = ilObjTestAccess::_getParticipantData($active_id);
3567 assQuestion::_logAction(sprintf($lng->txtlng("assessment", "log_answer_changed_points", ilObjAssessmentFolder::_getLogLanguage()), $username, $old_points, $points, $ilUser->getFullname() . " (" . $ilUser->getLogin() . ")"), $active_id, $question_id);
3568 }
3569 }
3570
3571 return TRUE;
3572 }
3573 else
3574 {
3575 return FALSE;
3576 }
3577 }
3578
3586 function getQuestion()
3587 {
3588 return $this->question;
3589 }
3590
3598 function setQuestion($question = "")
3599 {
3600 $this->question = $question;
3601 }
3602
3608 abstract public function getQuestionType();
3609
3619 {
3620 global $ilDB;
3621
3622 $result = $ilDB->queryF("SELECT question_type_id FROM qpl_qst_type WHERE type_tag = %s",
3623 array('text'),
3624 array($this->getQuestionType())
3625 );
3626 if ($result->numRows() == 1)
3627 {
3628 $row = $ilDB->fetchAssoc($result);
3629 return $row["question_type_id"];
3630 }
3631 return 0;
3632 }
3633
3634 public function syncHints()
3635 {
3636 global $ilDB;
3637
3638 // delete hints of the original
3639 $ilDB->manipulateF("DELETE FROM qpl_hints WHERE qht_question_fi = %s",
3640 array('integer'),
3641 array($this->original_id)
3642 );
3643
3644 // get hints of the actual question
3645 $result = $ilDB->queryF("SELECT * FROM qpl_hints WHERE qht_question_fi = %s",
3646 array('integer'),
3647 array($this->getId())
3648 );
3649
3650 // save hints to the original
3651 if ($result->numRows())
3652 {
3653 while ($row = $ilDB->fetchAssoc($result))
3654 {
3655 $next_id = $ilDB->nextId('qpl_hints');
3657 $ilDB->insert('qpl_hints', array(
3658 'qht_hint_id' => array('integer', $next_id),
3659 'qht_question_fi' => array('integer', $this->original_id),
3660 'qht_hint_index' => array('integer', $row["qht_hint_index"]),
3661 'qht_hint_points' => array('integer', $row["qht_hint_points"]),
3662 'qht_hint_text' => array('text', $row["qht_hint_text"]),
3663 )
3664 );
3665 }
3666 }
3667 }
3668
3673 protected function getRTETextWithMediaObjects()
3674 {
3675 // must be called in parent classes. add additional RTE text in the parent
3676 // classes and call this method to add the standard RTE text
3677 $collected = $this->getQuestion();
3678 $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->getId(), false);
3679 $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->getId(), true);
3680 $collected .= $this->feedbackOBJ->getAllSpecificAnswerFeedbackContents($this->getId());
3681
3682 foreach ($this->suggested_solutions as $solution_array)
3683 {
3684 $collected .= $solution_array["value"];
3685 }
3686
3687 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
3688 $questionHintList = ilAssQuestionHintList::getListByQuestionId($this->getId());
3689 foreach($questionHintList as $questionHint)
3690 {
3691 /* @var $questionHint ilAssQuestionHint */
3692 $collected .= $questionHint->getText();
3693 }
3694
3695 return $collected;
3696 }
3697
3703 {
3704 $combinedtext = $this->getRTETextWithMediaObjects();
3705 include_once("./Services/RTE/classes/class.ilRTE.php");
3706 ilRTE::_cleanupMediaObjectUsage($combinedtext, "qpl:html", $this->getId());
3707 }
3708
3714 function &getInstances()
3715 {
3716 global $ilDB;
3717
3718 $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE original_id = %s",
3719 array("integer"),
3720 array($this->getId())
3721 );
3722 $instances = array();
3723 $ids = array();
3724 while ($row = $ilDB->fetchAssoc($result))
3725 {
3726 array_push($ids, $row["question_id"]);
3727 }
3728 foreach ($ids as $question_id)
3729 {
3730 // check non random tests
3731 $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",
3732 array("integer"),
3733 array($question_id)
3734 );
3735 while ($row = $ilDB->fetchAssoc($result))
3736 {
3737 $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3738 }
3739 // check random tests
3740 $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",
3741 array("integer"),
3742 array($question_id)
3743 );
3744 while ($row = $ilDB->fetchAssoc($result))
3745 {
3746 $instances[$row['obj_fi']] = ilObject::_lookupTitle($row['obj_fi']);
3747 }
3748 }
3749 include_once "./Modules/Test/classes/class.ilObjTest.php";
3750 foreach ($instances as $key => $value)
3751 {
3752 $instances[$key] = array("obj_id" => $key, "title" => $value, "author" => ilObjTest::_lookupAuthor($key), "refs" => ilObject::_getAllReferences($key));
3753 }
3754 return $instances;
3755 }
3756
3757 function _needsManualScoring($question_id)
3758 {
3759 include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
3761 $questiontype = assQuestion::_getQuestionType($question_id);
3762 if (in_array($questiontype, $scoring))
3763 {
3764 return TRUE;
3765 }
3766 else
3767 {
3768 return FALSE;
3769 }
3770 }
3771
3779 function getActiveUserData($active_id)
3780 {
3781 global $ilDB;
3782 $result = $ilDB->queryF("SELECT * FROM tst_active WHERE active_id = %s",
3783 array('integer'),
3784 array($active_id)
3785 );
3786 if ($result->numRows())
3787 {
3788 $row = $ilDB->fetchAssoc($result);
3789 return array("user_id" => $row["user_fi"], "test_id" => $row["test_fi"]);
3790 }
3791 else
3792 {
3793 return array();
3794 }
3795 }
3796
3804 static function _includeClass($question_type, $gui = 0)
3805 {
3806 if( self::isCoreQuestionType($question_type) )
3807 {
3808 self::includeCoreClass($question_type, $gui);
3809 }
3810 else
3811 {
3812 self::includePluginClass($question_type, $gui);
3813 }
3814 }
3815
3816 public static function getGuiClassNameByQuestionType($questionType)
3817 {
3818 return $questionType.'GUI';
3819 }
3820
3821 public static function getObjectClassNameByQuestionType($questionType)
3822 {
3823 return $questionType;
3824 }
3825
3826 public static function getFeedbackClassNameByQuestionType($questionType)
3827 {
3828 return str_replace('ass', 'ilAss', $questionType).'Feedback';
3829 }
3830
3831 public static function isCoreQuestionType($questionType)
3832 {
3833 $guiClassName = self::getGuiClassNameByQuestionType($questionType);
3834 return file_exists("Modules/TestQuestionPool/classes/class.{$guiClassName}.php");
3835 }
3836
3837 public static function includeCoreClass($questionType, $withGuiClass)
3838 {
3839 if( $withGuiClass )
3840 {
3841 $guiClassName = self::getGuiClassNameByQuestionType($questionType);
3842 require_once "Modules/TestQuestionPool/classes/class.{$guiClassName}.php";
3843
3844 // object class is included by gui classes constructor
3845 }
3846 else
3847 {
3848 $objectClassName = self::getObjectClassNameByQuestionType($questionType);
3849 require_once "Modules/TestQuestionPool/classes/class.{$objectClassName}.php";
3850 }
3851
3852 $feedbackClassName = self::getFeedbackClassNameByQuestionType($questionType);
3853 require_once "Modules/TestQuestionPool/classes/feedback/class.{$feedbackClassName}.php";
3854 }
3855
3856 public static function includePluginClass($questionType, $withGuiClass)
3857 {
3858 global $ilPluginAdmin;
3859
3860 $classes = array(
3861 self::getObjectClassNameByQuestionType($questionType),
3862 self::getFeedbackClassNameByQuestionType($questionType)
3863 );
3864
3865 if( $withGuiClass )
3866 {
3867 $classes[] = self::getGuiClassNameByQuestionType($questionType);
3868 }
3869
3870 $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3871 foreach ($pl_names as $pl_name)
3872 {
3873 $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3874 if (strcmp($pl->getQuestionType(), $questionType) == 0)
3875 {
3876 foreach($classes as $class)
3877 {
3878 $pl->includeClass("class.{$class}.php");
3879 }
3880
3881 break;
3882 }
3883 }
3884 }
3885
3892 static function _getQuestionTypeName($type_tag)
3893 {
3894 if (file_exists("./Modules/TestQuestionPool/classes/class.".$type_tag.".php"))
3895 {
3896 global $lng;
3897 return $lng->txt($type_tag);
3898 }
3899 else
3900 {
3901 global $ilPluginAdmin;
3902 $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
3903 foreach ($pl_names as $pl_name)
3904 {
3905 $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
3906 if (strcmp($pl->getQuestionType(), $type_tag) == 0)
3907 {
3908 return $pl->getQuestionTypeTranslation();
3909 }
3910 }
3911 }
3912 return "";
3913 }
3914
3924 public static function &_instanciateQuestionGUI($question_id)
3925 {
3926 return self::instantiateQuestionGUI($question_id);
3927 }
3928
3936 public static function instantiateQuestionGUI($a_question_id)
3937 {
3938 global $ilCtrl, $ilDB, $lng, $ilUser;
3939
3940 if (strcmp($a_question_id, "") != 0)
3941 {
3942 $question_type = assQuestion::_getQuestionType($a_question_id);
3943
3944 assQuestion::_includeClass($question_type, 1);
3945
3946 $question_type_gui = self::getGuiClassNameByQuestionType($question_type);
3947 $question_gui = new $question_type_gui();
3948 $question_gui->object->loadFromDb($a_question_id);
3949
3950 $feedbackObjectClassname = self::getFeedbackClassNameByQuestionType($question_type);
3951 $question_gui->object->feedbackOBJ = new $feedbackObjectClassname($question_gui->object, $ilCtrl, $ilDB, $lng);
3952
3953 $assSettings = new ilSetting('assessment');
3954 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
3955 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
3956 $processLockerFactory->setQuestionId($question_gui->object->getId());
3957 $processLockerFactory->setUserId($ilUser->getId());
3958 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
3959 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
3960 $question_gui->object->setProcessLocker($processLockerFactory->getLocker());
3961 }
3962 else
3963 {
3964 global $ilLog;
3965 $ilLog->write('Instantiate question called without question id. (instantiateQuestionGUI@assQuestion)', $ilLog->WARNING);
3966 return null;
3967 }
3968 return $question_gui;
3969 }
3970
3983 public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
3984 {
3985 return $startrow;
3986 }
3987
3991 public function __get($value)
3992 {
3993 switch ($value)
3994 {
3995 case "id":
3996 return $this->getId();
3997 break;
3998 case "title":
3999 return $this->getTitle();
4000 break;
4001 case "comment":
4002 return $this->getComment();
4003 break;
4004 case "owner":
4005 return $this->getOwner();
4006 break;
4007 case "author":
4008 return $this->getAuthor();
4009 break;
4010 case "question":
4011 return $this->getQuestion();
4012 break;
4013 case "points":
4014 return $this->getPoints();
4015 break;
4016 case "est_working_time":
4017 return $this->getEstimatedWorkingTime();
4018 break;
4019 case "shuffle":
4020 return $this->getShuffle();
4021 break;
4022 case "test_id":
4023 return $this->getTestId();
4024 break;
4025 case "obj_id":
4026 return $this->getObjId();
4027 break;
4028 case "ilias":
4029 return $this->ilias;
4030 break;
4031 case "tpl":
4032 return $this->tpl;
4033 break;
4034 case "page":
4035 return $this->page;
4036 break;
4037 case "outputType":
4038 return $this->getOutputType();
4039 break;
4040 case "suggested_solutions":
4041 return $this->getSuggestedSolutions();
4042 break;
4043 case "original_id":
4044 return $this->getOriginalId();
4045 break;
4046 default:
4047 if (array_key_exists($value, $this->arrData))
4048 {
4049 return $this->arrData[$value];
4050 }
4051 else
4052 {
4053 return null;
4054 }
4055 break;
4056 }
4057 }
4058
4062 public function __set($key, $value)
4063 {
4064 switch ($key)
4065 {
4066 case "id":
4067 $this->setId($value);
4068 break;
4069 case "title":
4070 $this->setTitle($value);
4071 break;
4072 case "comment":
4073 $this->setComment($value);
4074 break;
4075 case "owner":
4076 $this->setOwner($value);
4077 break;
4078 case "author":
4079 $this->setAuthor($value);
4080 break;
4081 case "question":
4082 $this->setQuestion($value);
4083 break;
4084 case "points":
4085 $this->setPoints($value);
4086 break;
4087 case "est_working_time":
4088 if (is_array($value))
4089 {
4090 $this->setEstimatedWorkingTime($value["h"], $value["m"], $value["s"]);
4091 }
4092 break;
4093 case "shuffle":
4094 $this->setShuffle($value);
4095 break;
4096 case "test_id":
4097 $this->setTestId($value);
4098 break;
4099 case "obj_id":
4100 $this->setObjId($value);
4101 break;
4102 case "outputType":
4103 $this->setOutputType($value);
4104 break;
4105 case "original_id":
4106 $this->setOriginalId($value);
4107 break;
4108 case "page":
4109 $this->page =& $value;
4110 break;
4111 default:
4112 $this->arrData[$key] = $value;
4113 break;
4114 }
4115 }
4116
4117 public function getNrOfTries()
4118 {
4119 return (int)$this->nr_of_tries;
4120 }
4121
4122 public function setNrOfTries($a_nr_of_tries)
4123 {
4124 $this->nr_of_tries = $a_nr_of_tries;
4125 }
4126
4127 public function setExportImagePath($a_path)
4128 {
4129 $this->export_image_path = (string)$a_path;
4130 }
4131
4132 function _questionExistsInTest($question_id, $test_id)
4133 {
4134 global $ilDB;
4135
4136 if ($question_id < 1)
4137 {
4138 return false;
4139 }
4140
4141 $result = $ilDB->queryF("SELECT question_fi FROM tst_test_question WHERE question_fi = %s AND test_fi = %s",
4142 array('integer', 'integer'),
4143 array($question_id, $test_id)
4144 );
4145 if ($result->numRows() == 1)
4146 {
4147 return true;
4148 }
4149 else
4150 {
4151 return false;
4152 }
4153 }
4154
4161 function formatSAQuestion($a_q)
4162 {
4163 return $this->getSelfAssessmentFormatter()->format($a_q);
4164 }
4165
4166 // scorm2004-start ???
4167
4173 function setPreventRteUsage($a_val)
4174 {
4175 $this->prevent_rte_usage = $a_val;
4176 }
4177
4184 {
4186 }
4187
4193 function setSelfAssessmentEditingMode($a_selfassessmenteditingmode)
4194 {
4195 $this->selfassessmenteditingmode = $a_selfassessmenteditingmode;
4196 }
4197
4204 {
4206 }
4207
4213 function setDefaultNrOfTries($a_defaultnroftries)
4214 {
4215 $this->defaultnroftries = $a_defaultnroftries;
4216 }
4217
4224 {
4225 return (int)$this->defaultnroftries;
4226 }
4227
4228 // scorm2004-end ???
4229
4235 public static function lookupParentObjId($questionId)
4236 {
4237 global $ilDB;
4238
4239 $query = "SELECT obj_fi FROM qpl_questions WHERE question_id = %s";
4240
4241 $res = $ilDB->queryF($query, array('integer'), array((int)$questionId));
4242 $row = $ilDB->fetchAssoc($res);
4243
4244 return $row['obj_fi'];
4245 }
4246
4257 public static function lookupOriginalParentObjId($originalQuestionId)
4258 {
4259 return self::lookupParentObjId($originalQuestionId);
4260 }
4261
4262 protected function duplicateQuestionHints($originalQuestionId, $duplicateQuestionId)
4263 {
4264 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
4265 $hintIds = ilAssQuestionHintList::duplicateListForQuestion($originalQuestionId, $duplicateQuestionId);
4266
4268 {
4269 require_once 'Modules/TestQuestionPool/classes/class.ilAssHintPage.php';
4270
4271 foreach($hintIds as $originalHintId => $duplicateHintId)
4272 {
4273 $originalPageObject = new ilAssHintPage($originalHintId);
4274 $originalXML = $originalPageObject->getXMLContent();
4275
4276 $duplicatePageObject = new ilAssHintPage();
4277 $duplicatePageObject->setId($duplicateHintId);
4278 $duplicatePageObject->setParentId($this->getId());
4279 $duplicatePageObject->setXMLContent($originalXML);
4280 $duplicatePageObject->createFromXML();
4281 }
4282 }
4283 }
4284
4297 public function isAnswered($active_id, $pass = null)
4298 {
4299 return true;
4300 }
4301
4314 public static function isObligationPossible($questionId)
4315 {
4316 return false;
4317 }
4318
4325 {
4326 $this->obligationsToBeConsidered = (bool)$obligationsToBeConsidered;
4327 }
4328
4335 {
4337 }
4338
4339 public function isAutosaveable()
4340 {
4341 return TRUE;
4342 }
4343
4356 protected static function getNumExistingSolutionRecords($activeId, $pass, $questionId)
4357 {
4358 global $ilDB;
4359
4360 $query = "
4361 SELECT count(active_fi) cnt
4362
4363 FROM tst_solutions
4364
4365 WHERE active_fi = %s
4366 AND question_fi = %s
4367 AND pass = %s
4368 ";
4369
4370 $res = $ilDB->queryF(
4371 $query, array('integer','integer','integer'),
4372 array($activeId, $questionId, $pass)
4373 );
4374
4375 $row = $ilDB->fetchAssoc($res);
4376
4377 return (int)$row['cnt'];
4378 }
4379
4387 {
4389 }
4390
4398 {
4400 {
4401 require_once 'Modules/TestQuestionPool/exceptions/class.ilTestQuestionPoolException.php';
4402 throw new ilTestQuestionPoolException('invalid additional content editing mode given: '.$additinalContentEditingMode);
4403 }
4404
4405 $this->additinalContentEditingMode = $additinalContentEditingMode;
4406 }
4407
4415 {
4417 }
4418
4426 public function isValidAdditionalContentEditingMode($additionalContentEditingMode)
4427 {
4428 if( in_array($additionalContentEditingMode, $this->getValidAdditionalContentEditingModes()) )
4429 {
4430 return true;
4431 }
4432
4433 return false;
4434 }
4435
4443 {
4444 return array(
4445 self::ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT,
4446 self::ADDITIONAL_CONTENT_EDITING_MODE_PAGE_OBJECT
4447 );
4448 }
4449
4454 {
4455 $this->questionChangeListeners[] = $listener;
4456 }
4457
4462 {
4464 }
4465
4466 private function notifyQuestionCreated()
4467 {
4468 foreach($this->getQuestionChangeListeners() as $listener)
4469 {
4470 $listener->notifyQuestionCreated($this);
4471 }
4472 }
4473
4474 private function notifyQuestionEdited()
4475 {
4476 foreach($this->getQuestionChangeListeners() as $listener)
4477 {
4478 $listener->notifyQuestionEdited($this);
4479 }
4480 }
4481
4482 private function notifyQuestionDeleted()
4483 {
4484 foreach($this->getQuestionChangeListeners() as $listener)
4485 {
4486 $listener->notifyQuestionDeleted($this);
4487 }
4488 }
4489
4494 {
4495 require_once 'Services/Html/classes/class.ilHtmlPurifierFactory.php';
4496 return ilHtmlPurifierFactory::_getInstanceByType('qpl_usersolution');
4497 }
4498
4503 {
4504 require_once 'Services/Html/classes/class.ilHtmlPurifierFactory.php';
4505 return ilHtmlPurifierFactory::_getInstanceByType('qpl_usersolution');
4506 }
4507
4508 protected function buildQuestionDataQuery()
4509 {
4510 return "
4511 SELECT qpl_questions.*,
4512 {$this->getAdditionalTableName()}.*
4513 FROM qpl_questions
4514 LEFT JOIN {$this->getAdditionalTableName()}
4515 ON {$this->getAdditionalTableName()}.question_fi = qpl_questions.question_id
4516 WHERE qpl_questions.question_id = %s
4517 ";
4518 }
4519
4521 {
4522 $this->lastChange = $lastChange;
4523 }
4524
4525 public function getLastChange()
4526 {
4527 return $this->lastChange;
4528 }
4529
4538 protected function getCurrentSolutionResultSet($active_id, $pass)
4539 {
4541 global $ilDB;
4542
4543 if($this->getStep() !== NULL)
4544 {
4545 return $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s AND step = %s",
4546 array('integer','integer','integer', 'integer'),
4547 array($active_id, $this->getId(), $pass, $this->getStep())
4548 );
4549 }
4550 else
4551 {
4552 return $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
4553 array('integer','integer','integer'),
4554 array($active_id, $this->getId(), $pass)
4555 );
4556 }
4557
4558 }
4559
4566 protected function removeCurrentSolution($active_id, $pass)
4567 {
4571 global $ilDB;
4572
4573 if($this->getStep() !== NULL)
4574 {
4575 return $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s AND step = %s",
4576 array('integer','integer','integer', 'integer'),
4577 array($active_id, $this->getId(), $pass, $this->getStep())
4578 );
4579 }
4580 else
4581 {
4582 return $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
4583 array('integer','integer','integer'),
4584 array($active_id, $this->getId(), $pass)
4585 );
4586 }
4587
4588 }
4589
4598 public function saveCurrentSolution($active_id, $pass, $value1, $value2)
4599 {
4601 global $ilDB;
4602
4603 $next_id = $ilDB->nextId("tst_solutions");
4604
4605 $fieldData = array(
4606 "solution_id" => array("integer", $next_id),
4607 "active_fi" => array("integer", $active_id),
4608 "question_fi" => array("integer", $this->getId()),
4609 "value1" => array("clob", $value1),
4610 "value2" => array("clob", $value2),
4611 "pass" => array("integer", $pass),
4612 "tstamp" => array("integer", time())
4613 );
4614
4615 if( $this->getStep() !== null )
4616 {
4617 $fieldData['step'] = array("integer", $this->getStep());
4618 }
4619
4620 $aff = $ilDB->insert("tst_solutions", $fieldData);
4621
4622 return $aff;
4623 }
4624
4625
4629 public static function setResultGateway($resultGateway)
4630 {
4631 self::$resultGateway = $resultGateway;
4632 }
4633
4637 public static function getResultGateway()
4638 {
4639 return self::$resultGateway;
4640 }
4641
4645 public function setStep($step)
4646 {
4647 $this->step = $step;
4648 }
4649
4653 public function getStep()
4654 {
4655 return $this->step;
4656 }
4657
4663 public static function sumTimesInISO8601FormatH_i_s_Extended($time1, $time2)
4664 {
4667 return gmdate('H:i:s', $time);
4668 }
4669
4675 {
4676 $sec = 0;
4677 $time_array = explode(':',$time);
4678 if( sizeof($time_array) == 3)
4679 {
4680 $sec += $time_array[0] * 3600;
4681 $sec += $time_array[1] * 60;
4682 $sec += $time_array[2];
4683 }
4684 return $sec;
4685 }
4686
4690 protected function getSelfAssessmentFormatter()
4691 {
4692 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
4693 return new \ilAssSelfAssessmentQuestionFormatter();
4694 }
4695
4696 public function toJSON()
4697 {
4698 return json_encode(array());
4699 }
4700
4701 abstract public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null);
4702}
$result
print $file
$filename
Definition: buildRTE.php:89
$_GET["client_id"]
const IL_COMP_MODULE
Abstract basic class which is to be extended by the concrete assessment question type classes.
getTotalAnswers()
get total number of answers
_getQuestionTitle($question_id)
Returns the question title of a question with a given id.
$export_image_path
(Web) Path to images
moveUploadedMediaFile($file, $name)
Move an uploaded media file to an public accessible temp dir to present it.
static includePluginClass($questionType, $withGuiClass)
static getFeedbackClassNameByQuestionType($questionType)
setPreventRteUsage($a_val)
Set prevent rte usage.
& getSolutionValues($active_id, $pass=NULL)
Loads solutions of a given user from the database an returns it.
static _getOriginalId($question_id)
Returns the original id of a question.
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
Creates an Excel worksheet for the detailed cumulated results of this question.
setProcessLocker($processLocker)
formatSAQuestion($a_q)
Format self assessment question.
setShuffle($shuffle=true)
Sets the shuffle flag.
setId($id=-1)
Sets the id of the assQuestion object.
keyInArray($searchkey, $array)
returns TRUE if the key occurs in an array
setOriginalId($original_id)
static _instantiateQuestion($question_id)
getQuestionTypeID()
Returns the question type of the question.
setObjId($obj_id=0)
Set the object id of the container object.
static sumTimesInISO8601FormatH_i_s_Extended($time1, $time2)
static instantiateQuestionGUI($a_question_id)
Creates an instance of a question gui with a given question id.
static isAllowedImageFileExtension($mimeType, $fileExtension)
copySuggestedSolutionFiles($source_questionpool_id, $source_question_id)
static originalQuestionExists($questionId)
beforeSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
static isObligationPossible($questionId)
returns boolean wether it is possible to set this question type as obligatory or not considering the ...
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
setSuggestedSolution($solution_id="", $subquestion_index=0, $is_import=false)
Sets a suggested solution for the question.
_getSolutionMaxPass($question_id, $active_id)
Returns the maximum pass a users question solution.
saveQuestionDataToDb($original_id="")
fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
Receives parameters from a QTI parser and creates a valid ILIAS question object.
QTIMaterialToString($a_material)
Reads an QTI material tag an creates a text string.
syncSuggestedSolutionFiles($original_id)
Syncs the files of a suggested solution if the question is synced.
isClone($question_id="")
Checks whether the question is a clone of another question or not.
static fetchMimeTypeIdentifier($contentTypeString)
fixUnavailableSkinImageSources($html)
adjustReachedPointsByScoringOptions($points, $active_id, $pass=NULL)
Adjust the given reached points by checks for all special scoring options in the test container.
deletePageOfQuestion($question_id)
Deletes the page object of a question with a given ID.
_getMaximumPoints($question_id)
Returns the maximum points, a learner can reach answering the question.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
isComplete()
Returns true, if a question is complete for use.
const ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT
constant for additional content editing mode "default"
static _getSuggestedSolutionCount($question_id)
Returns the number of suggested solutions associated with a question.
getAdjustedReachedPoints($active_id, $pass=NULL)
returns the reached points ...
isInUse($question_id="")
Checks whether the question is in use or not.
static _areAnswered($a_user_id, $a_question_ids)
Checks if an array of question ids is answered by an user or not.
isPreviewSolutionCorrect(ilAssQuestionPreviewSession $previewSession)
cleanupMediaObjectUsage()
synchronises appearances of media objects in the question with media object usage table
persistWorkingState($active_id, $pass=NULL, $obligationsEnabled=false)
persists the working state for current testactive and testpass
createNewImageFileName($image_filename, $unique=false)
_questionExistsInTest($question_id, $test_id)
saveWorkingData($active_id, $pass=NULL)
Saves the learners input of the question to the database.
setObligationsToBeConsidered($obligationsToBeConsidered=true)
sets the flag wether obligations are to be considered or not
_getReachedPoints($active_id, $question_id, $pass=NULL)
Returns the points, a learner has reached answering the question.
getId()
Gets the id of the assQuestion object.
_getQuestionText($a_q_id)
Returns question text.
_updateTestResultCache($active_id, ilAssQuestionProcessLocker $processLocker=null)
@TODO Move this to a proper place.
getObjId()
Get the object id of the container object.
questionTitleExists($questionpool_id, $title)
Returns TRUE if the question title exists in the database.
supportsJavascriptOutput()
Returns true if the question type supports JavaScript output.
static _getQuestionTypeName($type_tag)
Return the translation for a given question type tag.
_getInternalLinkHref($target="")
getSuggestedSolutionPath()
Returns the path for a suggested solution.
areObligationsToBeConsidered()
gets the flag wether obligations are to be considered or not
setTitle($title="")
Sets the title string of the assQuestion object.
getOwner()
Gets the creator/owner ID of the assQuestion object.
prepareTextareaOutput($txt_output, $prepare_for_latex_output=FALSE)
Prepares a string for a text area output in tests.
getAdditionalContentEditingMode()
getter for additional content editing mode for this question
isHTML($a_text)
Checks if a given string contains HTML or not.
persistPreviewState(ilAssQuestionPreviewSession $previewSession)
persists the preview state for current user and question
addQuestionChangeListener(ilQuestionChangeListener $listener)
onCopy($sourceParentId, $sourceQuestionId, $targetParentId, $targetQuestionId)
Will be called when a question is copied (into another question pool)
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
getJavaPath()
Returns the image path for web accessable images of a question.
createNewQuestion($a_create_page=true)
Creates a new question without an owner when a new question is created This assures that an ID is giv...
getAdditionalTableName()
Returns the name of the additional question data table in the database.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second.
getSuggestedSolutionTitle($subquestion_index=0)
Returns the title of a suggested solution at a given subquestion_index.
static getObjectClassNameByQuestionType($questionType)
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
setExportImagePath($a_path)
isValidAdditionalContentEditingMode($additionalContentEditingMode)
returns the fact wether the passed additional content mode is valid or not
toXML($a_include_header=true, $a_include_binary=true, $a_shuffle=false, $test_output=false, $force_image_references=false)
Returns a QTI xml representation of the question.
setEstimatedWorkingTimeFromDurationString($durationString)
Sets the estimated working time of a question from a given datetime string.
getSuggestedSolutionPathWeb()
Returns the web path for a suggested solution.
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
setNewOriginalId($newId)
buildImagePath($questionId, $parentObjectId)
addQTIMaterial(&$a_xml_writer, $a_material, $close_material_tag=TRUE, $add_mobs=TRUE)
Creates a QTI material tag from a plain text or xhtml text.
getFlashPath()
Returns the image path for web accessable flash files of a question.
__get($value)
Object getter.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
getSuggestedSolution($subquestion_index=0)
Returns a suggested solution for a given subquestion index.
_isUsedInRandomTest($question_id="")
Checks whether the question is used in a random test or not.
static getNumExistingSolutionRecords($activeId, $pass, $questionId)
returns the number of existing solution records for the given test active / pass and given question i...
static convertISO8601FormatH_i_s_ExtendedToSeconds($time)
duplicateSuggestedSolutionFiles($parent_id, $question_id)
Duplicates the files of a suggested solution if the question is duplicated.
setAuthor($author="")
Sets the authors name of the assQuestion object.
$arrData
Associative array to store properties.
static isFileAvailable($file)
getQuestionType()
Returns the question type of the question.
deleteSuggestedSolutions()
Deletes all suggestes solutions in the database.
getPoints()
Returns the maximum available points for the question.
getOutputType()
Gets the output type.
static isCoreQuestionType($questionType)
_setReachedPoints($active_id, $question_id, $points, $maxpoints, $pass, $manualscoring, $obligationsEnabled)
Sets the points, a learner has reached answering the question Additionally objective results are upda...
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
getActiveUserData($active_id)
Returns the user id and the test id for a given active id.
setExternalId($external_id)
getValidAdditionalContentEditingModes()
getter for valid additional content editing modes
static _getSuggestedSolutionOutput($question_id)
Returns the output of the suggested solution.
_getTotalAnswers($a_q_id)
get number of answers for question id (static) note: do not use $this inside this method
getJavaPathWeb()
Returns the web image path for web accessable java applets of a question.
onDuplicate($originalParentId, $originalQuestionId, $duplicateParentId, $duplicateQuestionId)
Will be called when a question is duplicated (inside a question pool or for insertion in a test)
getTestId()
Gets the test id of the assQuestion object.
__set($key, $value)
Object setter.
calculateResultsFromSolution($active_id, $pass=NULL, $obligationsEnabled=false)
Calculates the question results from a previously saved question solution.
_resolveIntLinks($question_id)
getSelfAssessmentEditingMode()
Get Self-Assessment Editing Mode.
static $allowedCharsetsByMimeType
copyPageOfQuestion($a_q_id)
static lookupOriginalParentObjId($originalQuestionId)
returns the parent object id for given original question id (should be a qpl id, but theoretically it...
_resolveInternalLink($internal_link)
static & _instanciateQuestionGUI($question_id)
Creates an instance of a question gui with a given question id.
_questionExistsInPool($question_id)
Returns true if the question already exists in the database and is assigned to a question pool.
setOutputType($outputType=OUTPUT_HTML)
Sets the output type.
static lookupParentObjId($questionId)
@global ilDB $ilDB
static _getTotalRightAnswers($a_q_id)
get number of answers for question id (static) note: do not use $this inside this method
static $imageSourceFixReplaceMap
static getGuiClassNameByQuestionType($questionType)
& _getQuestionInfo($question_id)
Returns question information from the database.
_isWriteable($question_id, $user_id)
Returns true if the question is writeable by a certain user.
static getAllowedImageFileExtensions()
getDefaultNrOfTries()
Get Default Nr of Tries.
setSelfAssessmentEditingMode($a_selfassessmenteditingmode)
Set Self-Assessment Editing Mode.
static $allowedFileExtensionsByMimeType
static setResultGateway($resultGateway)
getShuffle()
Gets the shuffle flag.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
getFlashPathWeb()
Returns the web image path for web accessable flash applications of a question.
logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
static includeCoreClass($questionType, $withGuiClass)
_needsManualScoring($question_id)
createPageObject()
create page object of question
copyXHTMLMediaObjectsOfQuestion($a_q_id)
const ADDITIONAL_CONTENT_EDITING_MODE_PAGE_OBJECT
constant for additional content editing mode "pageobject"
static _isWorkedThrough($active_id, $question_id, $pass=NULL)
Returns true if the question was worked through in the given pass Worked through means that the user ...
getSuggestedSolutions()
Return the suggested solutions.
_logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
& _getSuggestedSolution($question_id, $subquestion_index=0)
Returns a suggested solution for a given subquestion index.
getAnswerTableName()
Returns the name of the answer table in the database.
fixSvgToPng($imageFilenameContainingString)
calculateReachedPoints($active_id, $pass=NULL, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
_getTitle($a_q_id)
Returns the title of a question.
deleteAdditionalTableData($question_id)
Deletes datasets from the additional question table in the database.
static _includeClass($question_type, $gui=0)
Include the php class file for a given question type.
getTitle()
Gets the title string of the assQuestion object.
setPoints($a_points)
Sets the maximum available points for the question.
afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
isAdditionalContentEditingModePageObject()
isser for additional "pageobject" content editing mode
duplicateQuestionHints($originalQuestionId, $duplicateQuestionId)
setComment($comment="")
Sets the comment string of the assQuestion object.
getComment()
Gets the comment string of the assQuestion object.
setTestId($id=-1)
Sets the test id of the assQuestion object.
getAuthor()
Gets the authors name of the assQuestion object.
_getQuestionType($question_id)
Returns the question type of a question with a given id.
setNrOfTries($a_nr_of_tries)
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assQuestion constructor
getReachedPoints($active_id, $pass=NULL)
Returns the points, a learner has reached answering the question This is the fast way to get the poin...
$nr_of_tries
Number of tries.
getQuestion()
Gets the question string of the question object.
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
static isAllowedImageMimeType($mimeType)
isAnswered($active_id, $pass=null)
returns boolean wether the question is answered during test pass or not
saveToDb($original_id="")
Saves the question to the database.
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
_questionExists($question_id)
Returns true if the question already exists in the database.
pcArrayShuffle($array)
Shuffles the values of a given array.
setQuestion($question="")
Sets the question string of the question object.
getImagePathWeb()
Returns the web image path for web accessable images of a question.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
loadFromDb($question_id)
Loads the question from the database.
static getAllowedFileExtensionsForMimeType($mimeType)
setLastChange($lastChange)
static getResultGateway()
& getInstances()
Gets all instances of the question.
createRandomSolution($test_id, $user_id)
getEstimatedWorkingTime()
Gets the estimated working time of a question.
getQuestionTypeFromDb($question_id)
get question type for question id
getPreventRteUsage()
Get prevent rte usage.
deleteAnswers($question_id)
Deletes datasets from answers tables.
setDefaultNrOfTries($a_defaultnroftries)
Set Default Nr of Tries.
Assessment hint page object.
static deleteHintsByQuestionIds($questionIds)
Deletes all question hints relating to questions included in given question ids.
static duplicateListForQuestion($originalQuestionId, $duplicateQuestionId)
duplicates a hint list from given original question id to given duplicate question id and returns an ...
static getListByQuestionId($questionId)
instantiates a question hint list for the passed question id
deleteRequestsByQuestionIds($questionIds)
Deletes all hint requests relating to a question included in given question ids.
Question page object.
_updateObjectiveResult($a_user_id, $a_active_id, $a_question_id)
static _getInstanceByType($a_type)
Factory method for creating purifier instances.
_getIdForImportId($a_import_id)
get current object id for import id (static)
_addLog($user_id, $object_id, $logtext, $question_id="", $original_id="", $test_only=FALSE, $test_ref_id=NULL)
Add an assessment log entry.
_getLogLanguage()
retrieve the log language for assessment logging
_getManualScoringTypes()
Retrieve the manual scoring settings as type strings.
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
Class ilObjMediaObject.
_saveUsage($a_mob_id, $a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
Save usage of mob within another container (e.g.
_getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
static _exists($a_id)
checks wether a lm content object with specified id exists or not
_removeUsage($a_mob_id, $a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
Remove usage of mob in another container.
_isWriteable($object_id, $user_id)
Returns true, if the question pool is writeable by a given user.
static _updateQuestionCount($object_id)
Updates the number of available questions for a question pool in the database.
static getUsageOfObject($a_obj_id, $a_include_titles=false)
Get usage of object.
_getParticipantData($active_id)
Retrieves a participant name from active id.
_getCountSystem($active_id)
Gets the count system for the calculation of points.
_getPass($active_id)
Retrieves the actual pass of a given user for a given test.
_getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
_lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
static buildExamId($active_id, $pass, $test_obj_id=null)
_getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
static _getUserIdFromActiveId($active_id)
_getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
_getScoreCutting($active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test.
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
_getWorkingTimeOfParticipantForPass($active_id, $pass)
Returns the complete working time in seconds for a test participant.
static _lookupObjId($a_id)
static _lookupTitle($a_id)
lookup object title
static _getAllReferences($a_id)
get all reference ids of object
static getPluginObject($a_ctype, $a_cname, $a_slot_id, $a_pname)
Get plugin object.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
_cleanupMediaObjectUsage($a_text, $a_usage_type, $a_usage_id)
synchronises appearances of media objects in $a_text with media object usage table
ILIAS Setting Class.
Taxonomy node <-> item assignment.
static moveUploadedFile($a_file, $a_name, $a_target, $a_raise_errors=true, $a_mode="move_uploaded")
move uploaded file
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static prepareTextareaOutput($txt_output, $prepare_for_latex_output=FALSE, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free,...
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
static removeTrailingPathSeparators($path)
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms @access public
static createDirectory($a_dir, $a_mod=0755)
create directory
$_POST['username']
Definition: cron.php:12
< a tabindex="-1" style="border-style: none;" href="#" title="Refresh Image" onclick="document.getElementById('siimage').src = './securimage_show.php?sid=' + Math.random(); this.blur(); return false">< img src="./images/refresh.png" alt="Reload Image" height="32" width="32" onclick="this.blur()" align="bottom" border="0"/></a >< br/>< strong > Enter Code *if($_SERVER['REQUEST_METHOD']=='POST' &&@ $_POST['do']=='contact') $_SESSION['ctform']['success']
$target_id
Definition: goto.php:88
global $ilCtrl
Definition: ilias.php:18
const OUTPUT_HTML
const OUTPUT_JAVASCRIPT
redirection script todo: (a better solution should control the processing via a xml file)
global $ilDB
$mobs
global $ilUser
Definition: imgupload.php:15
const ILIAS_ABSOLUTE_PATH