4include_once 
"./Modules/Test/classes/inc.AssessmentConstants.php";
 
   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')
 
   33        self::IMG_MIME_TYPE_JPG => array(
'binary'),
 
   34        self::IMG_MIME_TYPE_PNG => array(
'binary'),
 
   35        self::IMG_MIME_TYPE_GIF => array(
'binary')
 
  273        'image/jpeg' => array(
'jpg', 
'jpeg'), 
'image/png' => array(
'png'), 
'image/gif' => array(
'gif')
 
  304        $this->original_id = 
null;
 
  310        if (!$this->author) {
 
  311            $this->author = $this->
ilias->account->fullname;
 
  314        if ($this->owner <= 0) {
 
  315            $this->owner = $this->
ilias->account->id;
 
  319        $this->suggested_solutions = array();
 
  321        $this->nr_of_tries = 0;
 
  323        $this->arrData = array();
 
  326        $this->questionActionCmd = 
'handleQuestionAction';
 
  328        $this->lastChange = 
null;
 
  330        require_once 
'Services/Randomization/classes/class.ilArrayElementOrderKeeper.php';
 
  348        return (
bool) count(self::getAllowedFileExtensionsForMimeType($mimeType));
 
  353        return current(explode(
';', $contentTypeString));
 
  358        foreach (self::$allowedFileExtensionsByMimeType as $allowedMimeType => $extensions) {
 
  359            $rexCharsets = implode(
'|', self::$allowedCharsetsByMimeType[$allowedMimeType]);
 
  360            $rexMimeType = preg_quote($allowedMimeType, 
'/');
 
  362            $rex = 
'/^' . $rexMimeType . 
'(;(\s)*charset=(' . $rexCharsets . 
'))*$/';
 
  364            if (!preg_match($rex, $mimeType)) {
 
  377            strtolower($fileExtension),
 
  378            self::getAllowedFileExtensionsForMimeType($mimeType)
 
  389        if (!isset(
$_POST[
'cmd']) || !isset(
$_POST[
'cmd'][$this->questionActionCmd])) {
 
  393        if (!is_array(
$_POST[
'cmd'][$this->questionActionCmd]) || !count(
$_POST[
'cmd'][$this->questionActionCmd])) {
 
  397        return key(
$_POST[
'cmd'][$this->questionActionCmd]);
 
  406        if (!isset(
$_POST[$postSubmissionFieldname])) {
 
  410        if (!is_array(
$_POST[$postSubmissionFieldname])) {
 
  414        if (!count(
$_POST[$postSubmissionFieldname])) {
 
  442        require_once 
'Modules/Test/classes/class.ilObjTest.php';
 
  456            "SELECT test_fi FROM tst_active WHERE active_id = %s",
 
  462            return $row[
"test_fi"];
 
  473    protected function log($active_id, $langVar)
 
  486        $extensions = array();
 
  488        foreach (self::$allowedImageMaterialFileExtensionsByMimeType as $mimeType => $mimeExtensions) {
 
  489            $extensions = array_merge($extensions, $mimeExtensions);
 
  491        return array_unique($extensions);
 
  537    public function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
 
  539        include_once 
"./Modules/TestQuestionPool/classes/import/qti12/class." . $this->
getQuestionType() . 
"Import.php";
 
  541        $import = 
new $classname($this);
 
  542        $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
 
  551    public function toXML($a_include_header = 
true, $a_include_binary = 
true, $a_shuffle = 
false, $test_output = 
false, $force_image_references = 
false)
 
  553        include_once 
"./Modules/TestQuestionPool/classes/export/qti12/class." . $this->
getQuestionType() . 
"Export.php";
 
  555        $export = 
new $classname($this);
 
  556        return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
 
  583            "SELECT * FROM qpl_questions WHERE obj_fi = %s AND title = %s",
 
  584            array(
'integer',
'text'),
 
  585            array($questionpool_id, 
$title)
 
  587        return (
$result->numRows() > 0) ? true : 
false;
 
  623        $this->test_id = 
$id;
 
  679        $this->est_working_time = array(
"h" => (
int) $hour, 
"m" => (
int) $min, 
"s" => (
int) $sec);
 
  690        $this->est_working_time = array(
 
  691            'h' => (
int) substr($durationString, 0, 2),
 
  692            'm' => (
int) substr($durationString, 3, 2),
 
  693            's' => (
int) substr($durationString, 6, 2)
 
  707            foreach ($array as 
$key => $value) {
 
  708                if (strcmp(
$key, $searchkey) == 0) {
 
  762        require_once 
'Services/Utilities/classes/class.ilUtil.php';
 
  856        if (!$this->est_working_time) {
 
  857            $this->est_working_time = array(
"h" => 0, 
"m" => 0, 
"s" => 0);
 
  923        if (!strlen($this->external_id)) {
 
  924            if ($this->
getId() > 0) {
 
  925                return 'il_' . IL_INST_ID . 
'_qst_' . $this->
getId();
 
  927                return uniqid(
'', 
true);
 
  947            "SELECT points FROM qpl_questions WHERE question_id = %s",
 
  970            "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",
 
  993            "SELECT suggested_solution_id FROM qpl_sol_sug WHERE question_fi = %s",
 
 1012        return $question->getSuggestedSolutionOutput();
 
 1018        foreach ($this->suggested_solutions as $solution) {
 
 1019            switch ($solution[
"type"]) {
 
 1027                    $possible_texts = array_values(array_filter(array(
 
 1030                        $this->lng->txt(
'tst_show_solution_suggested')
 
 1033                    require_once 
'Services/WebAccessChecker/classes/class.ilWACSignedPath.php';
 
 1038                    $solutionValue = $solution[
"value"];
 
 1039                    $solutionValue = $this->
fixSvgToPng($solutionValue);
 
 1045        return join(
"<br />", 
$output);
 
 1062            "SELECT * FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
 
 1063            array(
'integer',
'integer'),
 
 1064            array($question_id, $subquestion_index)
 
 1066        if (
$result->numRows() == 1) {
 
 1069                "internal_link" => 
$row[
"internal_link"],
 
 1070                "import_id" => 
$row[
"import_id"]
 
 1100        if (is_null(
$pass)) {
 
 1101            include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 1105            "SELECT * FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 1106            array(
'integer',
'integer',
'integer'),
 
 1107            array($active_id, $question_id, 
$pass)
 
 1109        if (
$result->numRows() == 1) {
 
 1126        return round(self::_getReachedPoints($active_id, $this->
getId(), 
$pass), 2);
 
 1153        if (is_null(
$pass)) {
 
 1154            include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1164        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
 
 1166        $requestsStatisticData = $hintTracking->getRequestStatisticDataByQuestionAndTestpass();
 
 1167        $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
 
 1172        return $reached_points;
 
 1190        if (is_null(
$pass)) {
 
 1191            include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1199        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
 
 1201        $requestsStatisticData = $questionHintTracking->getRequestStatisticDataByQuestionAndTestpass();
 
 1202        $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
 
 1213        if (is_null($reached_points)) {
 
 1214            $reached_points = 0;
 
 1218        $existingSolutions = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 1220        $this->
getProcessLocker()->executeUserQuestionResultUpdateOperation(
function () use (
$ilDB, $active_id, 
$pass, $reached_points, $requestsStatisticData, $isAnswered, $existingSolutions) {
 
 1222                        DELETE FROM             tst_test_result 
 1224                        WHERE                   active_fi = %s 
 1225                        AND                             question_fi = %s 
 1229            $types = array(
'integer', 
'integer', 
'integer');
 
 1232            if ($this->
getStep() !== 
null) {
 
 1237                $types[] = 
'integer';
 
 1242            if ($existingSolutions[
'authorized']) {
 
 1243                $next_id = 
$ilDB->nextId(
"tst_test_result");
 
 1245                    'test_result_id' => array(
'integer', $next_id),
 
 1246                    'active_fi' => array(
'integer', $active_id),
 
 1247                    'question_fi' => array(
'integer', $this->
getId()),
 
 1248                    'pass' => array(
'integer', 
$pass),
 
 1249                    'points' => array(
'float', $reached_points),
 
 1250                    'tstamp' => array(
'integer', time()),
 
 1251                    'hint_count' => array(
'integer', $requestsStatisticData->getRequestsCount()),
 
 1252                    'hint_points' => array(
'float', $requestsStatisticData->getRequestsPoints()),
 
 1253                    'answered' => array(
'integer', $isAnswered)
 
 1256                if ($this->
getStep() !== 
null) {
 
 1257                    $fieldData[
'step'] = array(
'integer', $this->
getStep());
 
 1260                $ilDB->insert(
'tst_test_result', $fieldData);
 
 1265        include_once(
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
 
 1272                        "log_user_answered_question",
 
 1286        include_once 
'Modules/Course/classes/class.ilCourseObjectiveResult.php';
 
 1304        $saveStatus = 
false;
 
 1306        $this->
getProcessLocker()->executePersistWorkingStateLockOperation(
function () use ($active_id, 
$pass, $authorized, $obligationsEnabled, &$saveStatus) {
 
 1308            if (
$pass === 
null) {
 
 1309                require_once 
'Modules/Test/classes/class.ilObjTest.php';
 
 1363        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1364        include_once 
"./Modules/Test/classes/class.assMarkSchema.php";
 
 1369                        SELECT          tst_pass_result.* 
 1370                        FROM            tst_pass_result 
 1371                        WHERE           active_fi = %s 
 1377            array(
'integer',
'integer'),
 
 1378            array($active_id, 
$pass)
 
 1383        $max = 
$row[
'maxpoints'];
 
 1384        $reached = 
$row[
'points'];
 
 1386        $obligationsAnswered = (int) 
$row[
'obligations_answered'];
 
 1388        include_once 
"./Modules/Test/classes/class.assMarkSchema.php";
 
 1390        $percentage = (!$max) ? 0 : ($reached / $max) * 100.0;
 
 1392        $mark = ASS_MarkSchema::_getMatchingMarkFromActiveId($active_id, $percentage);
 
 1394        $isPassed = ($mark[
"passed"] ? 1 : 0);
 
 1395        $isFailed = (!$mark[
"passed"] ? 1 : 0);
 
 1397        $userTestResultUpdateCallback = 
function () use (
$ilDB, $active_id, 
$pass, $max, $reached, $isFailed, $isPassed, $obligationsAnswered, 
$row, $mark) {
 
 1398            $passedOnceBefore = 0;
 
 1399            $query = 
"SELECT passed_once FROM tst_result_cache WHERE active_fi = %s";
 
 1402                $passedOnceBefore = (int) 
$row[
'passed_once'];
 
 1405            $passedOnce = (int) ($isPassed || $passedOnceBefore);
 
 1408                "DELETE FROM tst_result_cache WHERE active_fi = %s",
 
 1413            $ilDB->insert(
'tst_result_cache', array(
 
 1414                'active_fi' => array(
'integer', $active_id),
 
 1415                'pass' => array(
'integer', strlen(
$pass) ? 
$pass : 0),
 
 1416                'max_points' => array(
'float', strlen($max) ? $max : 0),
 
 1417                'reached_points' => array(
'float', strlen($reached) ? $reached : 0),
 
 1418                'mark_short' => array(
'text', strlen($mark[
"short_name"]) ? $mark[
"short_name"] : 
" "),
 
 1419                'mark_official' => array(
'text', strlen($mark[
"official_name"]) ? $mark[
"official_name"] : 
" "),
 
 1420                'passed_once' => array(
'integer', $passedOnce),
 
 1421                'passed' => array(
'integer', $isPassed),
 
 1422                'failed' => array(
'integer', $isFailed),
 
 1423                'tstamp' => array(
'integer', time()),
 
 1424                'hint_count' => array(
'integer', 
$row[
'hint_count']),
 
 1425                'hint_points' => array(
'float', 
$row[
'hint_points']),
 
 1426                'obligations_answered' => array(
'integer', $obligationsAnswered)
 
 1431            $processLocker->executeUserTestResultUpdateLockOperation($userTestResultUpdateCallback);
 
 1433            $userTestResultUpdateCallback();
 
 1443        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1445        if (self::getResultGateway() !== 
null) {
 
 1458                        SELECT          SUM(points) reachedpoints, 
 1459                                                SUM(hint_count) hint_count, 
 1460                                                SUM(hint_points) hint_points, 
 1461                                                COUNT(DISTINCT(question_fi)) answeredquestions 
 1462                        FROM            tst_test_result 
 1463                        WHERE           active_fi = %s 
 1466            array(
'integer',
'integer'),
 
 1467            array($active_id, 
$pass)
 
 1471            if ($obligationsEnabled) {
 
 1473                                        SELECT          answered answ 
 1474                                        FROM            tst_test_question 
 1475                                          INNER JOIN    tst_active 
 1477                                                AND                     tst_test_question.test_fi = tst_active.test_fi 
 1478                                        LEFT JOIN       tst_test_result 
 1479                                                ON                      tst_test_result.active_fi = %s 
 1480                                                AND                     tst_test_result.pass = %s 
 1481                                                AND                     tst_test_question.question_fi = tst_test_result.question_fi 
 1482                                        WHERE           obligatory = 1';
 
 1484                $result_obligatory = 
$ilDB->queryF(
 
 1486                    array(
'integer',
'integer',
'integer'),
 
 1487                    array($active_id, $active_id, 
$pass)
 
 1490                $obligations_answered = 1;
 
 1492                while ($row_obligatory = 
$ilDB->fetchAssoc($result_obligatory)) {
 
 1493                    if (!(
int) $row_obligatory[
'answ']) {
 
 1494                        $obligations_answered = 0;
 
 1499                $obligations_answered = 1;
 
 1504            if (
$row[
'reachedpoints'] === 
null) {
 
 1505                $row[
'reachedpoints'] = 0;
 
 1507            if (
$row[
'hint_count'] === 
null) {
 
 1508                $row[
'hint_count'] = 0;
 
 1510            if (
$row[
'hint_points'] === 
null) {
 
 1511                $row[
'hint_points'] = 0;
 
 1516            $updatePassResultCallback = 
function () use (
$ilDB, 
$data, $active_id, 
$pass, 
$row, 
$time, $obligations_answered, $exam_identifier) {
 
 1522                        'active_fi' => array(
'integer', $active_id),
 
 1523                        'pass' => array(
'integer', strlen(
$pass) ? 
$pass : 0)),
 
 1525                        'points' => array(
'float', 
$row[
'reachedpoints'] ? 
$row[
'reachedpoints'] : 0),
 
 1526                        'maxpoints' => array(
'float', 
$data[
'points']),
 
 1527                        'questioncount' => array(
'integer', 
$data[
'count']),
 
 1528                        'answeredquestions' => array(
'integer', 
$row[
'answeredquestions']),
 
 1529                        'workingtime' => array(
'integer', 
$time),
 
 1530                        'tstamp' => array(
'integer', time()),
 
 1531                        'hint_count' => array(
'integer', 
$row[
'hint_count']),
 
 1532                        'hint_points' => array(
'float', 
$row[
'hint_points']),
 
 1533                        'obligations_answered' => array(
'integer', $obligations_answered),
 
 1534                        'exam_id' => array(
'text', $exam_identifier)
 
 1540                $processLocker->executeUserPassResultUpdateLockOperation($updatePassResultCallback);
 
 1542                $updatePassResultCallback();
 
 1549            'active_fi' => $active_id,
 
 1551            'points' => (
$row[
"reachedpoints"]) ? 
$row[
"reachedpoints"] : 0,
 
 1552            'maxpoints' => 
$data[
"points"],
 
 1553            'questioncount' => 
$data[
"count"],
 
 1554            'answeredquestions' => 
$row[
"answeredquestions"],
 
 1555            'workingtime' => 
$time,
 
 1557            'hint_count' => 
$row[
'hint_count'],
 
 1558            'hint_points' => 
$row[
'hint_points'],
 
 1559            'obligations_answered' => $obligations_answered,
 
 1560            'exam_id' => $exam_identifier
 
 1571    public static function logAction($logtext = 
"", $active_id = 
"", $question_id = 
"")
 
 1574        if (strlen($question_id)) {
 
 1578        require_once 
'Modules/Test/classes/class.ilObjAssessmentFolder.php';
 
 1579        require_once 
'Modules/Test/classes/class.ilObjTest.php';
 
 1599        $mediatempdir = CLIENT_WEB_DIR . 
"/assessment/temp";
 
 1600        if (!@is_dir($mediatempdir)) {
 
 1603        $temp_name = tempnam($mediatempdir, 
$name . 
"_____");
 
 1604        $temp_name = str_replace(
"\\", 
"/", $temp_name);
 
 1605        @unlink($temp_name);
 
 1606        if (!ilUtil::moveUploadedFile($file, 
$name, $temp_name)) {
 
 1620        return CLIENT_WEB_DIR . 
"/assessment/$this->obj_id/$this->id/solution/";
 
 1631        return CLIENT_WEB_DIR . 
"/assessment/$this->obj_id/$this->id/java/";
 
 1642        if ($question_id === 
null) {
 
 1646        if ($object_id === 
null) {
 
 1655        return CLIENT_WEB_DIR . 
"/assessment/{$parentObjectId}/{$questionId}/images/";
 
 1666        return CLIENT_WEB_DIR . 
"/assessment/$this->obj_id/$this->id/flash/";
 
 1677        include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 1689        include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 1704        if (!$this->export_image_path) {
 
 1705            include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 1721        include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 1743        if (!count($solution)) {
 
 1758        if (is_null(
$pass)) {
 
 1762        if ($this->
getStep() !== 
null) {
 
 1766                                WHERE active_fi = %s 
 1767                                AND question_fi = %s 
 1771                                ORDER BY solution_id";
 
 1775                array(
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 1776                array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
 
 1782                                WHERE active_fi = %s 
 1783                                AND question_fi = %s  
 1786                                ORDER BY solution_id 
 1791                array(
'integer', 
'integer', 
'integer', 
'integer'),
 
 1792                array($active_id, $this->
getId(), $pass, (
int) $authorized)
 
 1816        if ($question_id < 1) {
 
 1817            $question_id = $this->
getId();
 
 1820            "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",
 
 1825        $count = 
$row[
"question_count"];
 
 1829                        SELECT tst_active.test_fi 
 1831                        INNER JOIN tst_test_rnd_qst ON tst_test_rnd_qst.question_fi = qpl_questions.question_id 
 1832                        INNER JOIN tst_active ON tst_active.active_id = tst_test_rnd_qst.active_fi 
 1833                        WHERE qpl_questions.original_id = %s 
 1834                        GROUP BY tst_active.test_fi",
 
 1854        if ($question_id < 1) {
 
 1858            "SELECT original_id FROM qpl_questions WHERE question_id = %s",
 
 1863        return (
$row[
"original_id"] > 0) ? true : 
false;
 
 1874        $keys = array_keys($array);
 
 1894            "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",
 
 1899        return $data[
"type_tag"];
 
 1936        if (!is_array($answer_table_name)) {
 
 1937            $answer_table_name = array($answer_table_name);
 
 1940        foreach ($answer_table_name as 
$table) {
 
 1942                $affectedRows = 
$ilDB->manipulateF(
 
 1943                    "DELETE FROM $table WHERE question_fi = %s",
 
 1964        if (!is_array($additional_table_name)) {
 
 1965            $additional_table_name = array($additional_table_name);
 
 1968        foreach ($additional_table_name as 
$table) {
 
 1970                $affectedRows = 
$ilDB->manipulateF(
 
 1971                    "DELETE FROM $table WHERE question_fi = %s",
 
 1987        include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 1999    public function delete($question_id)
 
 2005        if ($question_id < 1) {
 
 2010            "SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
 
 2014        if (
$result->numRows() == 1) {
 
 2022        } 
catch (Exception $e) {
 
 2023            $ilLog->write(
"EXCEPTION: Could not delete page of question $question_id: $e");
 
 2027        $affectedRows = 
$ilDB->manipulateF(
 
 2028            "DELETE FROM qpl_questions WHERE question_id = %s",
 
 2032        if ($affectedRows == 0) {
 
 2041        } 
catch (Exception $e) {
 
 2042            $ilLog->write(
"EXCEPTION: Could not delete additional table data of question $question_id: $e");
 
 2048            $affectedRows = 
$ilDB->manipulateF(
 
 2049                "DELETE FROM tst_test_question WHERE question_fi = %s",
 
 2053        } 
catch (Exception $e) {
 
 2054            $ilLog->write(
"EXCEPTION: Could not delete delete question $question_id from a test: $e");
 
 2060            $affectedRows = 
$ilDB->manipulateF(
 
 2061                "DELETE FROM qpl_sol_sug WHERE question_fi = %s",
 
 2065        } 
catch (Exception $e) {
 
 2066            $ilLog->write(
"EXCEPTION: Could not delete suggested solutions of question $question_id: $e");
 
 2071            $directory = CLIENT_WEB_DIR . 
"/assessment/" . 
$obj_id . 
"/$question_id";
 
 2072            if (preg_match(
"/\d+/", 
$obj_id) and preg_match(
"/\d+/", $question_id) and is_dir($directory)) {
 
 2073                include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 2076        } 
catch (Exception $e) {
 
 2077            $ilLog->write(
"EXCEPTION: Could not delete question file directory $directory of question $question_id: $e");
 
 2082            include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 2088            foreach (
$mobs as $mob) {
 
 2095        } 
catch (Exception $e) {
 
 2096            $ilLog->write(
"EXCEPTION: Error deleting the media objects of question $question_id: $e");
 
 2100        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
 
 2101        ilAssQuestionHintTracking::deleteRequestsByQuestionIds(array($question_id));
 
 2103        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
 
 2106        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
 
 2108        $assignmentList->setParentObjId(
$obj_id);
 
 2109        $assignmentList->setQuestionIdFilter($question_id);
 
 2110        $assignmentList->loadFromDb();
 
 2111        foreach ($assignmentList->getAssignmentsByQuestionId($question_id) as $assignment) {
 
 2113            $assignment->deleteFromDb();
 
 2120            include_once 
"./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
 
 2122        } 
catch (Exception $e) {
 
 2123            $ilLog->write(
"EXCEPTION: Error updating the question pool question count of question pool " . $this->
getObjId() . 
" when deleting question $question_id: $e");
 
 2134        require_once 
'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
 
 2135        require_once 
'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
 
 2138        foreach ($taxIds as $taxId) {
 
 2140            $taxNodeAssignment->deleteAssignmentsOfItem($this->
getId());
 
 2165            "SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
 
 2166            array(
'integer',
'integer'),
 
 2167            array($a_q_id, $a_q_id)
 
 2169        if (
$result->numRows() == 0) {
 
 2172        $found_id = array();
 
 2174            array_push($found_id, 
$row[
"question_id"]);
 
 2177        $result = 
$ilDB->query(
"SELECT * FROM tst_test_result WHERE " . 
$ilDB->in(
'question_fi', $found_id, 
false, 
'integer'));
 
 2194            "SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
 
 2195            array(
'integer',
'integer'),
 
 2196            array($a_q_id, $a_q_id)
 
 2198        if (
$result->numRows() == 0) {
 
 2201        $found_id = array();
 
 2203            array_push($found_id, 
$row[
"question_id"]);
 
 2205        $result = 
$ilDB->query(
"SELECT * FROM tst_test_result WHERE " . 
$ilDB->in(
'question_fi', $found_id, 
false, 
'integer'));
 
 2208            $reached = 
$row[
"points"];
 
 2209            include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 2211            array_push($answers, array(
"reached" => $reached, 
"max" => $max));
 
 2215        foreach ($answers as 
$key => $value) {
 
 2216            $max += $value[
"max"];
 
 2217            $reached += $value[
"reached"];
 
 2220            return $reached / $max;
 
 2236            "SELECT title FROM qpl_questions WHERE question_id = %s",
 
 2240        if (
$result->numRows() == 1) {
 
 2242            return $row[
"title"];
 
 2258            "SELECT question_text FROM qpl_questions WHERE question_id = %s",
 
 2262        if (
$result->numRows() == 1) {
 
 2264            return $row[
"question_text"];
 
 2272        if (!file_exists($file)) {
 
 2276        if (!is_file($file)) {
 
 2280        if (!is_readable($file)) {
 
 2289        include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 2291        foreach (
$mobs as $mob) {
 
 2298        include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 2300        foreach (
$mobs as $mob) {
 
 2312        include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 2314        $this->page->setId($this->
getId());
 
 2315        $this->page->setParentId($qpl_id);
 
 2316        $this->page->setXMLContent(
"<PageObject><PageContent>" .
 
 2317            "<Question QRef=\"il__qst_" . $this->
getId() . 
"\"/>" .
 
 2318            "</PageContent></PageObject>");
 
 2319        $this->page->create();
 
 2325            include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 2328            $xml = str_replace(
"il__qst_" . $a_q_id, 
"il__qst_" . $this->
id, 
$page->getXMLContent());
 
 2329            $this->page->setXMLContent(
$xml);
 
 2330            $this->page->updateFromXML();
 
 2336        include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 2338        return $page->getXMLContent();
 
 2351        if ($question_id < 1) {
 
 2355            "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",
 
 2359        if (
$result->numRows() == 1) {
 
 2361            return $data[
"type_tag"];
 
 2379        if ($question_id < 1) {
 
 2384            "SELECT title FROM qpl_questions WHERE qpl_questions.question_id = %s",
 
 2388        if (
$result->numRows() == 1) {
 
 2390            return $data[
"title"];
 
 2407        'ok.svg' => 
'ok.png', 
'not_ok.svg' => 
'not_ok.png',
 
 2408        'checkbox_checked.svg' => 
'checkbox_checked.png',
 
 2409        'checkbox_unchecked.svg' => 
'checkbox_unchecked.png',
 
 2410        'radiobutton_checked.svg' => 
'radiobutton_checked.png',
 
 2411        'radiobutton_unchecked.svg' => 
'radiobutton_unchecked.png' 
 2416        $needles = array_keys(self::$imageSourceFixReplaceMap);
 
 2417        $replacements = array_values(self::$imageSourceFixReplaceMap);
 
 2418        return str_replace($needles, $replacements, $imageFilenameContainingString);
 
 2425        if (preg_match_all(
'/src="(.*?)"/m', 
$html, $matches)) {
 
 2426            $sources = $matches[1];
 
 2428            $needleReplacementMap = array();
 
 2430            foreach ($sources as $src) {
 
 2433                if (file_exists($file)) {
 
 2437                $levels = explode(DIRECTORY_SEPARATOR, $src);
 
 2438                if (count($levels) < 5 || $levels[0] != 
'Customizing' || $levels[2] != 
'skin') {
 
 2444                if ($levels[4] == 
'Modules' || $levels[4] == 
'Services') {
 
 2445                    $component = $levels[4] . DIRECTORY_SEPARATOR . $levels[5];
 
 2451            if (count($needleReplacementMap)) {
 
 2452                $html = str_replace(array_keys($needleReplacementMap), array_values($needleReplacementMap), 
$html);
 
 2471            "SELECT external_id FROM qpl_questions WHERE question_id = %s",
 
 2475        if (
$result->numRows() == 1) {
 
 2477            $this->external_id = 
$data[
'external_id'];
 
 2481            "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
 
 2483            array($this->
getId())
 
 2485        $this->suggested_solutions = array();
 
 2487            include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 2490                $this->suggested_solutions[
$row[
"subquestion_index"]] = array(
 
 2491                    "type" => 
$row[
"type"],
 
 2493                    "internal_link" => 
$row[
"internal_link"],
 
 2494                    "import_id" => 
$row[
"import_id"]
 
 2514        $estw_time = sprintf(
"%02d:%02d:%02d", $estw_time[
'h'], $estw_time[
'm'], $estw_time[
's']);
 
 2517            if ($a_create_page) {
 
 2524            $next_id = 
$ilDB->nextId(
'qpl_questions');
 
 2525            $affectedRows = 
$ilDB->insert(
"qpl_questions", array(
 
 2526                "question_id" => array(
"integer", $next_id),
 
 2528                "obj_fi" => array(
"integer", 
$obj_id),
 
 2529                "title" => array(
"text", 
null),
 
 2530                "description" => array(
"text", 
null),
 
 2531                "author" => array(
"text", $this->
getAuthor()),
 
 2532                "owner" => array(
"integer", 
$ilUser->getId()),
 
 2533                "question_text" => array(
"clob", 
null),
 
 2534                "points" => array(
"float", 0),
 
 2536                "working_time" => array(
"text", $estw_time),
 
 2537                "complete" => array(
"text", $complete),
 
 2538                "created" => array(
"integer", time()),
 
 2539                "original_id" => array(
"integer", 
null),
 
 2540                "tstamp" => array(
"integer", $tstamp),
 
 2544            $this->
setId($next_id);
 
 2546            if ($a_create_page) {
 
 2554        return $this->
getId();
 
 2563        $estw_time = sprintf(
"%02d:%02d:%02d", $estw_time[
'h'], $estw_time[
'm'], $estw_time[
's']);
 
 2566        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 2567        if ($this->
getId() == -1) {
 
 2569            $next_id = 
$ilDB->nextId(
'qpl_questions');
 
 2570            $affectedRows = 
$ilDB->insert(
"qpl_questions", array(
 
 2571                "question_id" => array(
"integer", $next_id),
 
 2573                "obj_fi" => array(
"integer", $this->
getObjId()),
 
 2574                "title" => array(
"text", $this->
getTitle()),
 
 2575                "description" => array(
"text", $this->
getComment()),
 
 2576                "author" => array(
"text", $this->
getAuthor()),
 
 2577                "owner" => array(
"integer", $this->
getOwner()),
 
 2580                "working_time" => array(
"text", $estw_time),
 
 2581                "nr_of_tries" => array(
"integer", $this->
getNrOfTries()),
 
 2582                "created" => array(
"integer", time()),
 
 2584                "tstamp" => array(
"integer", time()),
 
 2588            $this->
setId($next_id);
 
 2593            $affectedRows = 
$ilDB->update(
"qpl_questions", array(
 
 2594                "obj_fi" => array(
"integer", $this->
getObjId()),
 
 2595                "title" => array(
"text", $this->
getTitle()),
 
 2596                "description" => array(
"text", $this->
getComment()),
 
 2597                "author" => array(
"text", $this->
getAuthor()),
 
 2600                "nr_of_tries" => array(
"integer", $this->
getNrOfTries()),
 
 2601                "working_time" => array(
"text", $estw_time),
 
 2602                "tstamp" => array(
"integer", time()),
 
 2603                'complete' => array(
'integer', $this->
isComplete()),
 
 2606            "question_id" => array(
"integer", $this->
getId())
 
 2622        $this->updateSuggestedSolutions();
 
 2633        $affectedRows = 
$ilDB->manipulateF(
 
 2634            "UPDATE qpl_questions SET tstamp = %s, owner = %s, complete = %s WHERE question_id = %s",
 
 2635            array(
'integer',
'integer', 
'integer',
'text'),
 
 2636            array(time(), ($this->
getOwner() <= 0) ? $this->
ilias->account->id : $this->getOwner(), $complete, $this->getId())
 
 2640        include_once 
"./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
 
 2656        $query = 
"UPDATE qpl_questions SET tstamp = %s, original_id = %s WHERE question_id = %s";
 
 2658        $GLOBALS[
'DIC'][
'ilDB']->manipulateF(
 
 2660            array(
'integer',
'integer', 
'text'),
 
 2661            array(time(), $originalId, $questionId)
 
 2667        $query = 
"UPDATE qpl_questions SET tstamp = %s, original_id = NULL WHERE question_id = %s";
 
 2669        $GLOBALS[
'DIC'][
'ilDB']->manipulateF(
 
 2671            array(
'integer', 
'text'),
 
 2672            array(time(), $questionId)
 
 2679    protected function onDuplicate($originalParentId, $originalQuestionId, $duplicateParentId, $duplicateQuestionId)
 
 2684        $this->feedbackOBJ->duplicateFeedback($originalQuestionId, $duplicateQuestionId);
 
 2700        $this->feedbackOBJ->syncFeedback($origQuestionId, $dupQuestionId);
 
 2706    protected function onCopy($sourceParentId, $sourceQuestionId, $targetParentId, $targetQuestionId)
 
 2711        $this->feedbackOBJ->duplicateFeedback($sourceQuestionId, $targetQuestionId);
 
 2728        $affectedRows = 
$ilDB->manipulateF(
 
 2729            "DELETE FROM qpl_sol_sug WHERE question_fi = %s",
 
 2731            array($this->
getId())
 
 2734        include_once 
"./Services/Link/classes/class.ilInternalLink.php";
 
 2736        $this->suggested_solutions = array();
 
 2749        if (array_key_exists($subquestion_index, $this->suggested_solutions)) {
 
 2750            return $this->suggested_solutions[$subquestion_index];
 
 2766        if (array_key_exists($subquestion_index, $this->suggested_solutions)) {
 
 2767            $title = $this->suggested_solutions[$subquestion_index][
"internal_link"];
 
 2786        if (strcmp($solution_id, 
"") != 0) {
 
 2789                $import_id = $solution_id;
 
 2792            $this->suggested_solutions[$subquestion_index] = array(
 
 2793                "internal_link" => $solution_id,
 
 2794                "import_id" => $import_id
 
 2807        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2808            if (strcmp($solution[
"type"], 
"file") == 0) {
 
 2810                $filepath_original = str_replace(
 
 2811                    "/{$this->obj_id}/{$this->id}/solution",
 
 2812                    "/$parent_id/$question_id/solution",
 
 2815                if (!file_exists($filepath)) {
 
 2821                        $ilLog->write(
"File could not be duplicated!!!!", 
$ilLog->ERROR);
 
 2822                        $ilLog->write(
"object: " . print_r($this, 
true), 
$ilLog->ERROR);
 
 2838        $filepath_original = str_replace(
"/$this->id/solution", 
"/$original_id/solution", $filepath);
 
 2840        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2841            if (strcmp($solution[
"type"], 
"file") == 0) {
 
 2842                if (!file_exists($filepath_original)) {
 
 2848                        $ilLog->write(
"File could not be duplicated!!!!", 
$ilLog->ERROR);
 
 2849                        $ilLog->write(
"object: " . print_r($this, 
true), 
$ilLog->ERROR);
 
 2861        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2862            if (strcmp($solution[
"type"], 
"file") == 0) {
 
 2864                $filepath_original = str_replace(
"/$this->obj_id/$this->id/solution", 
"/$source_questionpool_id/$source_question_id/solution", $filepath);
 
 2865                if (!file_exists($filepath)) {
 
 2871                        $ilLog->write(
"File could not be copied!!!!", 
$ilLog->ERROR);
 
 2872                        $ilLog->write(
"object: " . print_r($this, 
true), 
$ilLog->ERROR);
 
 2882    public function updateSuggestedSolutions(
$original_id = 
"")
 
 2888        include_once 
"./Services/Link/classes/class.ilInternalLink.php";
 
 2889        $affectedRows = 
$ilDB->manipulateF(
 
 2890            "DELETE FROM qpl_sol_sug WHERE question_fi = %s",
 
 2895        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 2896        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2897            $next_id = 
$ilDB->nextId(
'qpl_sol_sug');
 
 2902                                           'suggested_solution_id' => array( 
'integer',         $next_id ),
 
 2903                                           'question_fi' => array( 
'integer',   
$id ),
 
 2904                                           'type' => array( 
'text',             $solution[
'type'] ),
 
 2906                                           'internal_link' => array( 
'text',            $solution[
'internal_link'] ),
 
 2907                                           'import_id' => array( 
'text',                
null ),
 
 2908                                           'subquestion_index' => array( 
'integer',     
$index ),
 
 2909                                           'tstamp' => array( 
'integer',        time() ),
 
 2912            if (preg_match(
"/il_(\d*?)_(\w+)_(\d+)/", $solution[
"internal_link"], $matches)) {
 
 2931    public function saveSuggestedSolution(
$type, $solution_id = 
"", $subquestion_index = 0, $value = 
"")
 
 2936        $affectedRows = 
$ilDB->manipulateF(
 
 2937            "DELETE FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
 
 2938            array(
"integer", 
"integer"),
 
 2945        $next_id = 
$ilDB->nextId(
'qpl_sol_sug');
 
 2946        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 2948        $affectedRows = 
$ilDB->insert(
 
 2951                                                       'suggested_solution_id' => array( 
'integer',     $next_id ),
 
 2952                                                       'question_fi' => array( 
'integer',       $this->
getId() ),
 
 2953                                                       'type' => array( 
'text',                 
$type ),
 
 2955                                                       'internal_link' => array( 
'text',                $solution_id ),
 
 2956                                                       'import_id' => array( 
'text',            
null ),
 
 2957                                                       'subquestion_index' => array( 
'integer',         $subquestion_index ),
 
 2958                                                       'tstamp' => array( 
'integer',    time() ),
 
 2961        if ($affectedRows == 1) {
 
 2962            $this->suggested_solutions[$subquestion_index] = array(
 
 2965                "internal_link" => $solution_id,
 
 2974        if (preg_match(
"/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches)) {
 
 2975            include_once 
"./Services/Link/classes/class.ilInternalLink.php";
 
 2976            include_once 
"./Modules/LearningModule/classes/class.ilLMObject.php";
 
 2977            include_once 
"./Modules/Glossary/classes/class.ilGlossaryTerm.php";
 
 2978            switch ($matches[2]) {
 
 2995            if (strcmp($resolved_link, 
"") == 0) {
 
 2996                $resolved_link = $internal_link;
 
 2999            $resolved_link = $internal_link;
 
 3001        return $resolved_link;
 
 3010            "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
 
 3016                $internal_link = 
$row[
"internal_link"];
 
 3017                include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 3019                if (strcmp($internal_link, $resolved_link) != 0) {
 
 3021                    $affectedRows = 
$ilDB->manipulateF(
 
 3022                        "UPDATE qpl_sol_sug SET internal_link = %s WHERE suggested_solution_id = %s",
 
 3023                        array(
'text',
'integer'),
 
 3024                        array($resolved_link, 
$row[
"suggested_solution_id"])
 
 3030        if ($resolvedlinks) {
 
 3034            include_once 
"./Services/Link/classes/class.ilInternalLink.php";
 
 3038                "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
 
 3044                    if (preg_match(
"/il_(\d*?)_(\w+)_(\d+)/", 
$row[
"internal_link"], $matches)) {
 
 3057            "lm" => 
"LearningModule",
 
 3058            "pg" => 
"PageObject",
 
 3059            "st" => 
"StructureObject",
 
 3060            "git" => 
"GlossaryItem",
 
 3061            "mob" => 
"MediaObject" 
 3064        if (preg_match(
"/il__(\w+)_(\d+)/", 
$target, $matches)) {
 
 3065            $type = $matches[1];
 
 3067            include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 3068            switch ($linktypes[$matches[1]]) {
 
 3069                case "LearningModule":
 
 3073                case "StructureObject":
 
 3076                case "GlossaryItem":
 
 3080                    $href = 
"./ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[
$type] . 
"&cmd=media&ref_id=" . 
$_GET[
"ref_id"] . 
"&mob_id=" . 
$target_id;
 
 3099            "SELECT * FROM qpl_questions WHERE question_id = %s",
 
 3105            if (
$row[
"original_id"] > 0) {
 
 3106                return $row[
"original_id"];
 
 3108                return $row[
"question_id"];
 
 3121                        SELECT COUNT(dupl.question_id) cnt 
 3122                        FROM qpl_questions dupl 
 3123                        INNER JOIN qpl_questions orig 
 3124                        ON orig.question_id = dupl.original_id 
 3125                        WHERE dupl.question_id = %s 
 3131        return $row[
'cnt'] > 0;
 
 3145        if (!$originalObjId) {
 
 3155        $this->
setId($original);
 
 3169        $this->updateSuggestedSolutions($original);
 
 3192        if ($question_id < 1) {
 
 3197            "SELECT question_id FROM qpl_questions WHERE question_id = %s",
 
 3201        if (
$result->numRows() == 1) {
 
 3220        if ($question_id < 1) {
 
 3225            "SELECT question_id FROM qpl_questions INNER JOIN object_data ON obj_fi = obj_id WHERE question_id = %s AND type = 'qpl'",
 
 3229        if (
$result->numRows() == 1) {
 
 3259        if (strcmp($question_id, 
"") != 0) {
 
 3261            if (!strlen($question_type)) {
 
 3284        if (strcmp($this->points, 
"") == 0) {
 
 3300        $this->points = $a_points;
 
 3333            "SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
 
 3334            array(
'integer',
'integer'),
 
 3335            array($active_id, $question_id)
 
 3337        if (
$result->numRows() == 1) {
 
 3339            return $row[
"maxpass"];
 
 3358        if (($question_id < 1) || ($user_id < 1)) {
 
 3363            "SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
 
 3367        if (
$result->numRows() == 1) {
 
 3369            $qpl_object_id = 
$row[
"obj_fi"];
 
 3370            include_once 
"./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
 
 3388        if ($question_id < 1) {
 
 3392            "SELECT test_random_question_id FROM tst_test_rnd_qst WHERE question_fi = %s",
 
 3417        $requestsStatisticData = $hintTracking->getRequestStatisticData();
 
 3418        $reachedPoints = $reachedPoints - $requestsStatisticData->getRequestsPoints();
 
 3420        return $reachedPoints;
 
 3460        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 3462        if ($count_system == 1) {
 
 3468        if ($score_cutting == 0) {
 
 3494        if (is_null(
$pass)) {
 
 3495            include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 3499            "SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 3500            array(
'integer',
'integer',
'integer'),
 
 3501            array($active_id, $question_id, 
$pass)
 
 3523            "SELECT DISTINCT(question_fi) FROM tst_test_result JOIN tst_active " .
 
 3524            "ON (active_id = active_fi) " .
 
 3525            "WHERE " . 
$ilDB->in(
'question_fi', $a_question_ids, 
false, 
'integer') .
 
 3526            " AND user_fi = %s",
 
 3530        return (
$res->numRows() == count($a_question_ids)) ? true : 
false;
 
 3554        include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 3568        for (
$i = 0; 
$i < $a_material->getMaterialCount(); 
$i++) {
 
 3569            $material = $a_material->getMaterial(
$i);
 
 3570            if (strcmp($material[
"type"], 
"mattext") == 0) {
 
 3571                $result .= $material[
"material"]->getContent();
 
 3573            if (strcmp($material[
"type"], 
"matimage") == 0) {
 
 3574                $matimage = $material[
"material"];
 
 3575                if (preg_match(
"/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) {
 
 3577                    if (!is_array(
$_SESSION[
"import_mob_xhtml"])) {
 
 3578                        $_SESSION[
"import_mob_xhtml"] = array();
 
 3580                    array_push(
$_SESSION[
"import_mob_xhtml"], array(
"mob" => $matimage->getLabel(), 
"uri" => $matimage->getUri()));
 
 3595    public function addQTIMaterial(&$a_xml_writer, $a_material, $close_material_tag = 
true, $add_mobs = 
true)
 
 3597        include_once 
"./Services/RTE/classes/class.ilRTE.php";
 
 3598        include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 3600        $a_xml_writer->xmlStartTag(
"material");
 
 3602            "texttype" => 
"text/plain" 
 3604        if ($this->
isHTML($a_material)) {
 
 3605            $attrs[
"texttype"] = 
"text/xhtml";
 
 3610            foreach (
$mobs as $mob) {
 
 3611                $moblabel = 
"il_" . IL_INST_ID . 
"_mob_" . $mob;
 
 3612                if (strpos($a_material, 
"mm_$mob") !== 
false) {
 
 3616                            "label" => $moblabel,
 
 3617                            "uri" => 
"objects/" . 
"il_" . IL_INST_ID . 
"_mob_" . $mob . 
"/" . $mob_obj->getTitle()
 
 3620                    $a_xml_writer->xmlElement(
"matimage", $imgattrs, 
null);
 
 3624        if ($close_material_tag) {
 
 3625            $a_xml_writer->xmlEndTag(
"material");
 
 3633        if (preg_match(
"/.*\.(png|jpg|gif|jpeg)$/i", $plain_image_filename, $matches)) {
 
 3634            $extension = 
"." . $matches[1];
 
 3638            $plain_image_filename = uniqid($plain_image_filename . microtime(
true));
 
 3641        $hashed_filename = md5($plain_image_filename) . $extension;
 
 3643        return $hashed_filename;
 
 3662            if (is_null(
$pass)) {
 
 3669                "SELECT points FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 3670                array(
'integer',
'integer',
'integer'),
 
 3671                array($active_id, $question_id, 
$pass)
 
 3673            $manual = ($manualscoring) ? 1 : 0;
 
 3674            $rowsnum = 
$result->numRows();
 
 3677                $old_points = 
$row[
"points"];
 
 3679                    $affectedRows = 
$ilDB->manipulateF(
 
 3680                        "UPDATE tst_test_result SET points = %s, manual = %s, tstamp = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 3681                        array(
'float', 
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 3682                        array(
$points, $manual, time(), $active_id, $question_id, 
$pass)
 
 3686                $next_id = 
$ilDB->nextId(
'tst_test_result');
 
 3687                $affectedRows = 
$ilDB->manipulateF(
 
 3688                    "INSERT INTO tst_test_result (test_result_id, active_fi, question_fi, points, pass, manual, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s)",
 
 3689                    array(
'integer', 
'integer',
'integer', 
'float', 
'integer', 
'integer',
'integer'),
 
 3690                    array($next_id, $active_id, $question_id, 
$points, 
$pass, $manual, time())
 
 3694            if (self::isForcePassResultUpdateEnabled() || $old_points != 
$points || !$rowsnum) {
 
 3695                assQuestion::_updateTestPassResults($active_id, 
$pass, $obligationsEnabled);
 
 3697                include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 3698                include_once 
'./Modules/Course/classes/class.ilCourseObjectiveResult.php';
 
 3701                include_once(
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
 
 3706                    include_once 
"./Modules/Test/classes/class.ilObjTestAccess.php";
 
 3763            "SELECT question_type_id FROM qpl_qst_type WHERE type_tag = %s",
 
 3767        if (
$result->numRows() == 1) {
 
 3769            return $row[
"question_type_id"];
 
 3774    public function syncHints()
 
 3781            "DELETE FROM qpl_hints WHERE qht_question_fi = %s",
 
 3783            array($this->original_id)
 
 3788            "SELECT * FROM qpl_hints WHERE qht_question_fi = %s",
 
 3790            array($this->
getId())
 
 3796                $next_id = 
$ilDB->nextId(
'qpl_hints');
 
 3801                        'qht_hint_id' => array(
'integer', $next_id),
 
 3802                        'qht_question_fi' => array(
'integer', $this->original_id),
 
 3803                        'qht_hint_index' => array(
'integer', 
$row[
"qht_hint_index"]),
 
 3804                        'qht_hint_points' => array(
'integer', 
$row[
"qht_hint_points"]),
 
 3805                        'qht_hint_text' => array(
'text', 
$row[
"qht_hint_text"]),
 
 3821        $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->
getId(), 
false);
 
 3822        $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->
getId(), 
true);
 
 3823        $collected .= $this->feedbackOBJ->getAllSpecificAnswerFeedbackContents($this->
getId());
 
 3825        foreach ($this->suggested_solutions as $solution_array) {
 
 3826            $collected .= $solution_array[
"value"];
 
 3829        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
 
 3831        foreach ($questionHintList as $questionHint) {
 
 3833            $collected .= $questionHint->getText();
 
 3846        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 3861            "SELECT question_id FROM qpl_questions WHERE original_id = %s",
 
 3863            array($this->
getId())
 
 3865        $instances = array();
 
 3868            array_push($ids, 
$row[
"question_id"]);
 
 3870        foreach ($ids as $question_id) {
 
 3873                "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",
 
 3882                "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",
 
 3890        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 3891        foreach ($instances as 
$key => $value) {
 
 3899        include_once 
"./Modules/Test/classes/class.ilObjAssessmentFolder.php";
 
 3902        if (in_array($questiontype, $scoring)) {
 
 3921            "SELECT * FROM tst_active WHERE active_id = %s",
 
 3927            return array(
"user_id" => 
$row[
"user_fi"], 
"test_id" => 
$row[
"test_fi"]);
 
 3942        if (self::isCoreQuestionType($question_type)) {
 
 3951        return $questionType . 
'GUI';
 
 3956        return $questionType;
 
 3961        return str_replace(
'ass', 
'ilAss', $questionType) . 
'Feedback';
 
 3967        return file_exists(
"Modules/TestQuestionPool/classes/class.{$guiClassName}.php");
 
 3972        if ($withGuiClass) {
 
 3974            require_once 
"Modules/TestQuestionPool/classes/class.{$guiClassName}.php";
 
 3979            require_once 
"Modules/TestQuestionPool/classes/class.{$objectClassName}.php";
 
 3983        require_once 
"Modules/TestQuestionPool/classes/feedback/class.{$feedbackClassName}.php";
 
 3989        $ilPluginAdmin = 
$DIC[
'ilPluginAdmin'];
 
 3992            self::getObjectClassNameByQuestionType($questionType),
 
 3993            self::getFeedbackClassNameByQuestionType($questionType)
 
 3996        if ($withGuiClass) {
 
 4000        $pl_names = $ilPluginAdmin->getActivePluginsForSlot(
IL_COMP_MODULE, 
"TestQuestionPool", 
"qst");
 
 4001        foreach ($pl_names as $pl_name) {
 
 4003            if (strcmp($pl->getQuestionType(), $questionType) == 0) {
 
 4004                foreach ($classes as $class) {
 
 4005                    $pl->includeClass(
"class.{$class}.php");
 
 4021        if (file_exists(
"./Modules/TestQuestionPool/classes/class." . $type_tag . 
".php")) {
 
 4024            return $lng->txt($type_tag);
 
 4027            $ilPluginAdmin = 
$DIC[
'ilPluginAdmin'];
 
 4028            $pl_names = $ilPluginAdmin->getActivePluginsForSlot(
IL_COMP_MODULE, 
"TestQuestionPool", 
"qst");
 
 4029            foreach ($pl_names as $pl_name) {
 
 4031                if (strcmp($pl->getQuestionType(), $type_tag) == 0) {
 
 4032                    return $pl->getQuestionTypeTranslation();
 
 4068        if (strcmp($a_question_id, 
"") != 0) {
 
 4074            $question_gui = 
new $question_type_gui();
 
 4075            $question_gui->object->loadFromDb($a_question_id);
 
 4078            $question_gui->object->feedbackOBJ = 
new $feedbackObjectClassname($question_gui->object, 
$ilCtrl, 
$ilDB, 
$lng);
 
 4080            $assSettings = 
new ilSetting(
'assessment');
 
 4081            require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
 
 4083            $processLockerFactory->setQuestionId($question_gui->object->getId());
 
 4084            $processLockerFactory->setUserId(
$ilUser->getId());
 
 4085            include_once(
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
 
 4087            $question_gui->object->setProcessLocker($processLockerFactory->getLocker());
 
 4091            $ilLog->write(
'Instantiate question called without question id. (instantiateQuestionGUI@assQuestion)', 
$ilLog->WARNING);
 
 4094        return $question_gui;
 
 4109        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord(0) . $startrow, $this->lng->txt($this->getQuestionType()));
 
 4110        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord(1) . $startrow, $this->getTitle());
 
 4122                return $this->
getId();
 
 4142            case "est_working_time":
 
 4166            case "suggested_solutions":
 
 4173                if (array_key_exists($value, $this->arrData)) {
 
 4174                    return $this->arrData[$value];
 
 4189                $this->
setId($value);
 
 4209            case "est_working_time":
 
 4210                if (is_array($value)) {
 
 4230                $this->page = &$value;
 
 4233                $this->arrData[
$key] = $value;
 
 4245        $this->nr_of_tries = $a_nr_of_tries;
 
 4250        $this->export_image_path = (string) $a_path;
 
 4258        if ($question_id < 1) {
 
 4263            "SELECT question_fi FROM tst_test_question WHERE question_fi = %s AND test_fi = %s",
 
 4264            array(
'integer', 
'integer'),
 
 4267        if (
$result->numRows() == 1) {
 
 4290        require_once 
'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
 
 4291        return new \ilAssSelfAssessmentQuestionFormatter();
 
 4303        $this->prevent_rte_usage = $a_val;
 
 4325        $this->feedbackOBJ->migrateContentForLearningModule($migrator, $this->
getId());
 
 4351        $this->selfassessmenteditingmode = $a_selfassessmenteditingmode;
 
 4371        $this->defaultnroftries = $a_defaultnroftries;
 
 4396        $query = 
"SELECT obj_fi FROM qpl_questions WHERE question_id = %s";
 
 4398        $res = 
$ilDB->queryF(
$query, array(
'integer'), array((
int) $questionId));
 
 4401        return $row[
'obj_fi'];
 
 4421        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
 
 4425            require_once 
'Modules/TestQuestionPool/classes/class.ilAssHintPage.php';
 
 4427            foreach ($hintIds as $originalHintId => $duplicateHintId) {
 
 4429                $originalXML = $originalPageObject->getXMLContent();
 
 4432                $duplicatePageObject->setId($duplicateHintId);
 
 4433                $duplicatePageObject->setParentId($this->
getId());
 
 4434                $duplicatePageObject->setXMLContent($originalXML);
 
 4435                $duplicatePageObject->createFromXML();
 
 4445        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
 
 4447        $assignmentList->setParentObjId($srcParentId);
 
 4448        $assignmentList->setQuestionIdFilter($srcQuestionId);
 
 4449        $assignmentList->loadFromDb();
 
 4451        foreach ($assignmentList->getAssignmentsByQuestionId($srcQuestionId) as $assignment) {
 
 4454            $assignment->setParentObjId($trgParentId);
 
 4455            $assignment->setQuestionId($trgQuestionId);
 
 4456            $assignment->saveToDb();
 
 4465        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
 
 4467        $assignmentList->setParentObjId($trgParentId);
 
 4468        $assignmentList->setQuestionIdFilter($trgQuestionId);
 
 4469        $assignmentList->loadFromDb();
 
 4471        foreach ($assignmentList->getAssignmentsByQuestionId($trgQuestionId) as $assignment) {
 
 4474            $assignment->deleteFromDb();
 
 4537                        SELECT          count(active_fi) cnt 
 4541                        WHERE           active_fi = %s 
 4542                        AND                     question_fi = %s 
 4548            array(
'integer',
'integer',
'integer'),
 
 4549            array($activeId, $questionId, 
$pass)
 
 4554        return (
int) 
$row[
'cnt'];
 
 4577            require_once 
'Modules/TestQuestionPool/exceptions/class.ilTestQuestionPoolException.php';
 
 4620            self::ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT,
 
 4621            self::ADDITIONAL_CONTENT_EDITING_MODE_PAGE_OBJECT
 
 4630        $this->questionChangeListeners[] = $listener;
 
 4644            $listener->notifyQuestionCreated($this);
 
 4651            $listener->notifyQuestionEdited($this);
 
 4658            $listener->notifyQuestionDeleted($this);
 
 4667        require_once 
'Services/Html/classes/class.ilHtmlPurifierFactory.php';
 
 4676        require_once 
'Services/Html/classes/class.ilHtmlPurifierFactory.php';
 
 4683                        SELECT          qpl_questions.*, 
 4684                                                {$this->getAdditionalTableName()}.* 
 4686                        LEFT JOIN       {$this->getAdditionalTableName()} 
 4687                        ON                      {$this->getAdditionalTableName()}.question_fi = qpl_questions.question_id 
 4688                        WHERE                   qpl_questions.question_id = %s 
 4717        if ($this->
getStep() !== 
null) {
 
 4721                                WHERE active_fi = %s 
 4722                                AND question_fi = %s 
 4728            return $ilDB->queryF(
 
 4730                array(
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 4731                array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
 
 4737                                WHERE active_fi = %s 
 4738                                AND question_fi = %s 
 4743            return $ilDB->queryF(
 
 4745                array(
'integer', 
'integer', 
'integer', 
'integer'),
 
 4746                array($active_id, $this->
getId(), $pass, (
int) $authorized)
 
 4762        return $ilDB->manipulateF(
 
 4763            "DELETE FROM tst_solutions WHERE solution_id = %s",
 
 4782            "SELECT * FROM tst_solutions WHERE solution_id = %s",
 
 4803        $this->
getProcessLocker()->executeUserSolutionUpdateLockOperation(
function () use ($active_id, 
$pass) {
 
 4821        if ($this->
getStep() !== 
null) {
 
 4823                                DELETE FROM tst_solutions 
 4824                                WHERE active_fi = %s 
 4825                                AND question_fi = %s 
 4831            return $ilDB->manipulateF(
 
 4833                array(
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 4834                array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
 
 4838                                DELETE FROM tst_solutions 
 4839                                WHERE active_fi = %s 
 4840                                AND question_fi = %s 
 4845            return $ilDB->manipulateF(
 
 4847                array(
'integer', 
'integer', 
'integer', 
'integer'),
 
 4848                array($active_id, $this->
getId(), $pass, (
int) $authorized)
 
 4870        $next_id = 
$ilDB->nextId(
"tst_solutions");
 
 4873            "solution_id" => array(
"integer", $next_id),
 
 4874            "active_fi" => array(
"integer", $active_id),
 
 4875            "question_fi" => array(
"integer", $this->
getId()),
 
 4876            "value1" => array(
"clob", $value1),
 
 4877            "value2" => array(
"clob", $value2),
 
 4878            "pass" => array(
"integer", 
$pass),
 
 4879            "tstamp" => array(
"integer", isset($tstamp) ? $tstamp : time()),
 
 4880            'authorized' => array(
'integer', (
int) $authorized)
 
 4883        if ($this->
getStep() !== 
null) {
 
 4884            $fieldData[
'step'] = array(
"integer", $this->
getStep());
 
 4887        return $ilDB->insert(
"tst_solutions", $fieldData);
 
 4907            "value1" => array(
"clob", $value1),
 
 4908            "value2" => array(
"clob", $value2),
 
 4909            "tstamp" => array(
"integer", time()),
 
 4910            'authorized' => array(
'integer', (
int) $authorized)
 
 4913        if ($this->
getStep() !== 
null) {
 
 4914            $fieldData[
'step'] = array(
"integer", $this->
getStep());
 
 4917        return $ilDB->update(
"tst_solutions", $fieldData, array(
 
 4918            'solution_id' => array(
'integer', $solutionId)
 
 4929            'authorized' => array(
'integer', (
int) $authorized)
 
 4933            $fieldData[
'tstamp'] = array(
'integer', time());
 
 4937            'question_fi' => array(
'integer', $this->
getId()),
 
 4938            'active_fi' => array(
'integer', $activeId),
 
 4939            'pass' => array(
'integer', 
$pass)
 
 4942        if ($this->
getStep() !== 
null) {
 
 4943            $whereData[
'step'] = array(
"integer", $this->
getStep());
 
 4946        return $ilDB->update(
'tst_solutions', $fieldData, $whereData);
 
 4958        return implode(self::getKeyValuesImplosionSeparator(), $keyValues);
 
 4962        return explode(self::getKeyValuesImplosionSeparator(), $keyValues);
 
 4967        foreach ($this->
getSolutionValues($activeId, $passIndex, 
false) as $solutionRec) {
 
 4968            if (0 == strlen($solutionRec[
'value1']) && 0 == strlen($solutionRec[
'value2'])) {
 
 4976        return !strlen($solutionRecord[
'value1']) && !strlen($solutionRecord[
'value2']);
 
 4984        $types = array(
"integer", 
"integer", 
"integer", 
"integer");
 
 4985        $values = array($activeId, $this->
getId(), $passIndex, (
int) $authorized);
 
 4986        $valuesCondition = array();
 
 4988        foreach ($matchValues as $valueField => $value) {
 
 4989            switch ($valueField) {
 
 4992                    $valuesCondition[] = 
"{$valueField} = %s";
 
 4998                    require_once 
'Modules/TestQuestionPool/exceptions/class.ilTestQuestionPoolException.php';
 
 5003        $valuesCondition = implode(
' AND ', $valuesCondition);
 
 5006                        DELETE FROM tst_solutions 
 5007                        WHERE active_fi = %s 
 5008                        AND question_fi = %s 
 5011                        AND $valuesCondition 
 5014        if ($this->
getStep() !== 
null) {
 
 5015            $query .= 
" AND step = %s ";
 
 5016            $types[] = 
'integer';
 
 5026            $this->
saveCurrentSolution($activeId, $passIndex, $rec[
'value1'], $rec[
'value2'], 
true, $rec[
'tstamp']);
 
 5034        if (!count($intermediateSolution)) {
 
 5042            if ($considerDummyRecordCreation) {
 
 5072        $this->step = 
$step;
 
 5092        return gmdate(
'H:i:s', 
$time);
 
 5102        $time_array = explode(
':', 
$time);
 
 5103        if (
sizeof($time_array) == 3) {
 
 5104            $sec += $time_array[0] * 3600;
 
 5105            $sec += $time_array[1] * 60;
 
 5106            $sec += $time_array[2];
 
 5113        return json_encode(array());
 
 5121        $solutionAvailability = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 5122        return (
bool) $solutionAvailability[
'intermediate'];
 
 5126        $solutionAvailability = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 5127        return (
bool) $solutionAvailability[
'authorized'];
 
 5131        $solutionAvailability = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 5132        return (
bool) $solutionAvailability[
'authorized'] || (bool) $solutionAvailability[
'intermediate'];
 
 5141    protected function lookupMaxStep($active_id, 
$pass)
 
 5148            "SELECT MAX(step) max_step FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
 
 5149            array(
"integer", 
"integer", 
"integer"),
 
 5155        $maxStep = 
$row[
'max_step'];
 
 5167    public function lookupForExistingSolutions($activeId, 
$pass)
 
 5174            'authorized' => 
false,
 
 5175            'intermediate' => 
false 
 5179                        SELECT authorized, COUNT(*) cnt 
 5181                        WHERE active_fi = %s 
 5182                        AND question_fi = %s 
 5186        if ($this->
getStep() !== 
null) {
 
 5194        $result = 
$ilDB->queryF(
$query, array(
'integer', 
'integer', 
'integer'), array($activeId, $this->
getId(), $pass));
 
 5197            if (
$row[
'authorized']) {
 
 5198                $return[
'authorized'] = 
$row[
'cnt'] > 0;
 
 5200                $return[
'intermediate'] = 
$row[
'cnt'] > 0;
 
 5220        $query = 
"DELETE FROM tst_solutions WHERE question_fi = %s";
 
 5222        $DIC->database()->manipulateF(
$query, array(
'integer'), array($this->
getId()));
 
 5231                        DELETE FROM tst_solutions 
 5232                        WHERE active_fi = %s 
 5233                        AND question_fi = %s 
 5237        if ($this->
getStep() !== 
null) {
 
 5241        return $ilDB->manipulateF(
 
 5243            array(
'integer', 
'integer', 
'integer'),
 
 5244            array($activeId, $this->
getId(), $pass)
 
 5253        $this->
log($activeId, 
"log_user_solution_willingly_deleted");
 
 5255        self::_updateTestPassResults(
 
 5270                        DELETE FROM tst_test_result 
 5271                        WHERE active_fi = %s 
 5272                        AND question_fi = %s 
 5276        if ($this->
getStep() !== 
null) {
 
 5280        return $ilDB->manipulateF(
 
 5282            array(
'integer', 
'integer', 
'integer'),
 
 5283            array($activeId, $this->
getId(), $pass)
 
 5292        $IN_questionIds = 
$ilDB->in(
'question_fi', $questionIds, 
false, 
'integer');
 
 5296                        FROM tst_test_result 
 5297                        WHERE active_fi = %s 
 5304            array(
'integer', 
'integer'),
 
 5305            array($activeId, 
$pass)
 
 5308        return $row[
'cnt'] < count($questionIds);
 
 5316        $IN_questionIds = 
$ilDB->in(
'question_fi', $questionIds, 
false, 
'integer');
 
 5320                        FROM tst_test_result 
 5321                        WHERE active_fi = %s 
 5328            array(
'integer', 
'integer'),
 
 5329            array($activeId, 
$pass)
 
 5332        $questionsHavingResultRecord = array();
 
 5335            $questionsHavingResultRecord[] = 
$row[
'question_fi'];
 
 5338        $questionsMissingResultRecordt = array_diff(
 
 5340            $questionsHavingResultRecord
 
 5343        return $questionsMissingResultRecordt;
 
 5353                        FROM tst_test_result 
 5354                        WHERE active_fi = %s 
 5355                        AND question_fi = %s 
 5359        $row = 
$ilDB->fetchAssoc(
$ilDB->queryF(
$query, array(
'integer', 
'integer', 
'integer'), array($activeId, $questionId, 
$pass)));
 
 5361        return $row[
'cnt'] > 0;
 
 5370        $valuePairs = array();
 
 5372        foreach ($indexedValues as $value1 => $value2) {
 
 5373            $valuePairs[] = array(
'value1' => $value1, 
'value2' => $value2);
 
 5385        $indexedValues = array();
 
 5387        foreach ($valuePairs as $valuePair) {
 
 5388            $indexedValues[ $valuePair[
'value1'] ] = $valuePair[
'value2'];
 
 5391        return $indexedValues;
 
 5416            "UPDATE qpl_questions SET tstamp = %s  WHERE question_id = %s",
 
 5417            array(
'integer', 
'integer'),
 
 5418            array(time(), $this->
getId())
 
 5439        if ($this->testQuestionConfigInstance === 
null) {
 
 5456        include_once(
'Modules/TestQuestionPool/classes/class.ilTestQuestionConfig.php');
 
An exception for terminatinating execution or to throw for unit testing.
Abstract basic class which is to be extended by the concrete assessment question type classes.
getTotalAnswers()
get total number of answers
$export_image_path
(Web) Path to images
moveUploadedMediaFile($file, $name)
Move an uploaded media file to an public accessible temp dir to present it.
isNonEmptyItemListPostSubmission($postSubmissionFieldname)
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass.
static includePluginClass($questionType, $withGuiClass)
getSolutionValues($active_id, $pass=null, $authorized=true)
Loads solutions of a given user from the database an returns it.
static getFeedbackClassNameByQuestionType($questionType)
setPreventRteUsage($a_val)
Set prevent rte usage.
removeResultRecord($activeId, $pass)
static _getOriginalId($question_id)
Returns the original id of a question.
$additinalContentEditingMode
const KEY_VALUES_IMPLOSION_SEPARATOR
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.
static _getReachedPoints($active_id, $question_id, $pass=null)
Returns the points, a learner has reached answering 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)
setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
Creates an Excel worksheet for the detailed cumulated results of this question.
copySuggestedSolutionFiles($source_questionpool_id, $source_question_id)
getReachedPoints($active_id, $pass=null)
Returns the points, a learner has reached answering the question This is the fast way to get the poin...
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 ...
static setForcePassResultUpdateEnabled($forcePassResultsUpdateEnabled)
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.
static _getMaximumPoints($question_id)
Returns the maximum points, a learner can reach answering the question.
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.
static _getSolutionMaxPass($question_id, $active_id)
Returns the maximum pass a users question solution.
isClone($question_id="")
Checks whether the question is a clone of another question or not.
static fetchMimeTypeIdentifier($contentTypeString)
fixUnavailableSkinImageSources($html)
deletePageOfQuestion($question_id)
Deletes the page object of a question with a given ID.
lmMigrateQuestionTypeGenericContent(ilAssSelfAssessmentMigrator $migrator)
duplicateSkillAssignments($srcParentId, $srcQuestionId, $trgParentId, $trgQuestionId)
savePreviewData(ilAssQuestionPreviewSession $previewSession)
persistWorkingState($active_id, $pass=null, $obligationsEnabled=false, $authorized=true)
persists the working state for current testactive and testpass
deleteSolutionRecordByValues($activeId, $passIndex, $authorized, $matchValues)
isComplete()
Returns true, if a question is complete for use.
getHtmlQuestionContentPurifier()
const ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT
constant for additional content editing mode "default"
addAnswerOptionValue($qIndex, $answerOptionValue, $points)
log($active_id, $langVar)
static _getSuggestedSolutionCount($question_id)
Returns the number of suggested solutions associated with a question.
adjustReachedPointsByScoringOptions($points, $active_id, $pass=null)
Adjust the given reached points by checks for all special scoring options in the test container.
isInUse($question_id="")
Checks whether the question is in use or not.
static resetOriginalId($questionId)
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
deleteDummySolutionRecord($activeId, $passIndex)
getId()
Gets the id of the assQuestion object.
static saveOriginalId($questionId, $originalId)
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true, $tstamp=null)
fetchValuePairsFromIndexedValues(array $indexedValues)
lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigrator $migrator)
getObjId()
Get the object id of the container object.
isDummySolutionRecord($solutionRecord)
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.
getSuggestedSolutionPath()
Returns the path for a suggested solution.
removeExistingSolutions($activeId, $pass)
areObligationsToBeConsidered()
setTitle($title="")
Sets the title string of the assQuestion object.
static _getTitle($a_q_id)
Returns the title of a question.
getOwner()
Gets the creator/owner ID of the assQuestion object.
getAdditionalContentEditingMode()
getter for additional content editing mode for this question
static _isUsedInRandomTest($question_id="")
Checks whether the question is used in a random test or not.
getSolutionRecordById($solutionId)
$testQuestionConfigInstance
isHTML($a_text)
Checks if a given string contains HTML or not.
buildTestPresentationConfig()
build basic test question configuration instance
setObligationsToBeConsidered($obligationsToBeConsidered)
persistPreviewState(ilAssQuestionPreviewSession $previewSession)
persists the preview state for current user and question
static $forcePassResultsUpdateEnabled
addQuestionChangeListener(ilQuestionChangeListener $listener)
syncXHTMLMediaObjectsOfQuestion()
onCopy($sourceParentId, $sourceQuestionId, $targetParentId, $targetQuestionId)
Will be called when a question is copied (into another question pool)
duplicateIntermediateSolutionAuthorized($activeId, $passIndex)
authorizedOrIntermediateSolutionExists($active_id, $pass)
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.
resetUsersAnswer($activeId, $pass)
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...
migrateContentForLearningModule(ilAssSelfAssessmentMigrator $migrator)
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.
getHtmlUserSolutionPurifier()
fetchIndexedValuesFromValuePairs(array $valuePairs)
getSuggestedSolutionTitle($subquestion_index=0)
Returns the title of a suggested solution at a given subquestion_index.
static getObjectClassNameByQuestionType($questionType)
deductHintPointsFromReachedPoints(ilAssQuestionPreviewSession $previewSession, $reachedPoints)
static $allowedImageMaterialFileExtensionsByMimeType
setExportImagePath($a_path)
isValidAdditionalContentEditingMode($additionalContentEditingMode)
returns the fact wether the passed additional content mode is valid or not
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
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)
buildImagePath($questionId, $parentObjectId)
removeAllExistingSolutions()
static explodeKeyValues($keyValues)
getFlashPath()
Returns the image path for web accessable flash files of a question.
__get($value)
Object getter.
static logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
removeCurrentSolution($active_id, $pass, $authorized=true)
getSuggestedSolution($subquestion_index=0)
Returns a suggested solution for a given subquestion index.
calculateResultsFromSolution($active_id, $pass=null, $obligationsEnabled=false)
Calculates the question results from a previously saved question solution.
$obligationsToBeConsidered
buildHashedImageFilename($plain_image_filename, $unique=false)
updateCurrentSolution($solutionId, $value1, $value2, $authorized=true)
removeSolutionRecordById($solutionId)
static getNumExistingSolutionRecords($activeId, $pass, $questionId)
returns the number of existing solution records for the given test active / pass and given question i...
static implodeKeyValues($keyValues)
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.
ensureCurrentTestPass($active_id, $pass)
static isCoreQuestionType($questionType)
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.
static _updateTestResultCache($active_id, ilAssQuestionProcessLocker $processLocker=null)
@TODO Move this to a proper place.
setExternalId($external_id)
getValidAdditionalContentEditingModes()
getter for valid additional content editing modes
deleteTaxonomyAssignments()
static _getSuggestedSolutionOutput($question_id)
Returns the output of the suggested solution.
static _needsManualScoring($question_id)
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
getQuestionChangeListeners()
intermediateSolutionExists($active_id, $pass)
_getTotalAnswers($a_q_id)
get number of answers for question id (static) note: do not use $this inside this method
static _questionExistsInTest($question_id, $test_id)
authorizedSolutionExists($active_id, $pass)
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.
setShuffler(ilArrayElementShuffler $shuffler)
__set($key, $value)
Object setter.
getTestOutputSolutions($activeId, $pass)
removeIntermediateSolution($active_id, $pass)
_resolveIntLinks($question_id)
static _getInternalLinkHref($target="")
getSelfAssessmentEditingMode()
Get Self-Assessment Editing Mode.
static $allowedCharsetsByMimeType
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename
copyPageOfQuestion($a_q_id)
static isForcePassResultUpdateEnabled()
static lookupOriginalParentObjId($originalQuestionId)
returns the parent object id for given original question id (should be a qpl id, but theoretically it...
_resolveInternalLink($internal_link)
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
getTestPresentationConfig()
Get the test question configuration (initialised once)
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 ilDBInterface $ilDB
forceExistingIntermediateSolution($activeId, $passIndex, $considerDummyRecordCreation)
static _getTotalRightAnswers($a_q_id)
get number of answers for question id (static) note: do not use $this inside this method
getSelfAssessmentFormatter()
static _getQuestionText($a_q_id)
Returns question text.
static $imageSourceFixReplaceMap
static getGuiClassNameByQuestionType($questionType)
getDefaultNrOfTries()
Get Default Nr of Tries.
static _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...
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.
static includeCoreClass($questionType, $withGuiClass)
createPageObject()
create page object of question
static missingResultRecordExists($activeId, $pass, $questionIds)
static getKeyValuesImplosionSeparator()
getUserSolutionPreferingIntermediate($active_id, $pass=null)
copyXHTMLMediaObjectsOfQuestion($a_q_id)
const ADDITIONAL_CONTENT_EDITING_MODE_PAGE_OBJECT
constant for additional content editing mode "pageobject"
getSuggestedSolutions()
Return the suggested solutions.
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 ...
& _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.
isAddableAnswerOptionValue($qIndex, $answerOptionValue)
fixSvgToPng($imageFilenameContainingString)
syncSkillAssignments($srcParentId, $srcQuestionId, $trgParentId, $trgQuestionId)
updateCurrentSolutionsAuthorization($activeId, $pass, $authorized, $keepTime=false)
static getQuestionsMissingResultRecord($activeId, $pass, $questionIds)
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.
$selfassessmenteditingmode
getTitle()
Gets the title string of the assQuestion object.
static _getQuestionTitle($question_id)
Returns the question title of a question with a given id.
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.
static _getQuestionInfo($question_id)
Returns question information from the database.
getAdjustedReachedPoints($active_id, $pass=null, $authorizedSolution=true)
returns the reached points ...
getSuggestedSolutionOutput()
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.
static getQuestionTypeFromDb($question_id)
get question type for question id
setNrOfTries($a_nr_of_tries)
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assQuestion constructor
$nr_of_tries
Number of tries.
static _getQuestionType($question_id)
Returns the question type of a question with a given id.
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.
static _isWriteable($question_id, $user_id)
Returns true if the question is writeable by a certain user.
_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)
static lookupResultRecordExist($activeId, $questionId, $pass)
setLastChange($lastChange)
static getResultGateway()
& getInstances()
Gets all instances of the question.
static getAllowedImageMaterialFileExtensions()
lookupCurrentTestPass($active_id, $pass)
createRandomSolution($test_id, $user_id)
getEstimatedWorkingTime()
Gets the estimated working time of a question.
getPreventRteUsage()
Get prevent rte usage.
deleteAnswers($question_id)
Deletes datasets from answers tables.
setDefaultNrOfTries($a_defaultnroftries)
Set Default Nr of Tries.
ensureNonNegativePoints($points)
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
getParticipantsSolution()
setParticipantsSolution($participantSolution)
static _updateObjectiveResult($a_user_id, $a_active_id, $a_question_id)
static _getInstanceByType($a_type)
Factory method for creating purifier instances.
static _saveLink( $a_source_type, $a_source_id, $a_target_type, $a_target_id, $a_target_inst=0, $a_source_lang="-")
save internal link information
static _deleteAllLinksOfSource($a_source_type, $a_source_id, $a_lang="-")
Delete all links of a given source.
static _getIdForImportId($a_type, $a_target)
Get current id for an import id.
static _getIdForImportId($a_import_id)
get current object id for import id (static)
static _addLog($user_id, $object_id, $logtext, $question_id="", $original_id="", $test_only=false, $test_ref_id=null)
Add an assessment log entry.
static _getLogLanguage()
retrieve the log language for assessment logging
static _getManualScoringTypes()
Retrieve the manual scoring settings as type strings.
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
static _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.
static _getParticipantData($active_id)
Retrieves a participant name from active id.
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
static _getCountSystem($active_id)
Gets the count system for the calculation of points.
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
static _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static buildExamId($active_id, $pass, $test_obj_id=null)
static _getWorkingTimeOfParticipantForPass($active_id, $pass)
Returns the complete working time in seconds for a test participant.
static _getUserIdFromActiveId($active_id)
static _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
static _lookupObjId($a_id)
static _lookupTitle($a_id)
lookup object title
static _getAllReferences($a_id)
get all reference ids of object
static getPluginObject(string $a_ctype, string $a_cname, string $a_slot_id, string $a_pname)
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...
static _cleanupMediaObjectUsage($a_text, $a_usage_type, $a_usage_id)
Synchronises appearances of media objects in $a_text with media object usage table.
Taxonomy node <-> item assignment.
Test Question configuration.
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static isHTML($a_text)
Checks if a given string contains HTML or not.
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 getASCIIFilename($a_filename)
convert utf8 to ascii filename
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
static signFile($path_to_file)
static setTokenMaxLifetimeInSeconds($token_max_lifetime_in_seconds)
migrateToLmContent($content)
catch(Exception $e) $message
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
redirection script todo: (a better solution should control the processing via a xml file)
if(empty($password)) $table
foreach($_POST as $key=> $value) $res