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')
 
  283        'image/jpeg' => array(
'jpg', 
'jpeg'), 
'image/png' => array(
'png'), 
'image/gif' => array(
'gif')
 
  317        $this->original_id = 
null;
 
  323        if (!$this->author) {
 
  324            $this->author = $this->
ilias->account->fullname;
 
  327        if ($this->owner <= 0) {
 
  328            $this->owner = $this->
ilias->account->id;
 
  332        $this->suggested_solutions = array();
 
  334        $this->nr_of_tries = 0;
 
  336        $this->arrData = array();
 
  339        $this->questionActionCmd = 
'handleQuestionAction';
 
  341        $this->lastChange = 
null;
 
  343        require_once 
'Services/Randomization/classes/class.ilArrayElementOrderKeeper.php';
 
  363        return (
bool) count(self::getAllowedFileExtensionsForMimeType($mimeType));
 
  368        return current(explode(
';', $contentTypeString));
 
  373        foreach (self::$allowedFileExtensionsByMimeType as $allowedMimeType => $extensions) {
 
  374            $rexCharsets = implode(
'|', self::$allowedCharsetsByMimeType[$allowedMimeType]);
 
  375            $rexMimeType = preg_quote($allowedMimeType, 
'/');
 
  377            $rex = 
'/^' . $rexMimeType . 
'(;(\s)*charset=(' . $rexCharsets . 
'))*$/';
 
  379            if (!preg_match($rex, $mimeType)) {
 
  392            strtolower($fileExtension),
 
  393            self::getAllowedFileExtensionsForMimeType($mimeType)
 
  404        if (!isset(
$_POST[
'cmd']) || !isset(
$_POST[
'cmd'][$this->questionActionCmd])) {
 
  408        if (!is_array(
$_POST[
'cmd'][$this->questionActionCmd]) || !count(
$_POST[
'cmd'][$this->questionActionCmd])) {
 
  412        return key(
$_POST[
'cmd'][$this->questionActionCmd]);
 
  421        if (!isset(
$_POST[$postSubmissionFieldname])) {
 
  425        if (!is_array(
$_POST[$postSubmissionFieldname])) {
 
  429        if (!count(
$_POST[$postSubmissionFieldname])) {
 
  457        require_once 
'Modules/Test/classes/class.ilObjTest.php';
 
  471            "SELECT test_fi FROM tst_active WHERE active_id = %s",
 
  477            return $row[
"test_fi"];
 
  488    protected function log($active_id, $langVar)
 
  501        $extensions = array();
 
  503        foreach (self::$allowedImageMaterialFileExtensionsByMimeType as $mimeType => $mimeExtensions) {
 
  504            $extensions = array_merge($extensions, $mimeExtensions);
 
  506        return array_unique($extensions);
 
  559        array $solutionhints = []
 
  561        include_once 
"./Modules/TestQuestionPool/classes/import/qti12/class." . $this->
getQuestionType() . 
"Import.php";
 
  563        $import = 
new $classname($this);
 
  564        $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
 
  566        foreach ($solutionhints as $hint) {
 
  568            $h->setQuestionId($import->getQuestionId());
 
  569            $h->setIndex($hint[
'index']);
 
  570            $h->setPoints($hint[
'points']);
 
  571            $h->setText($hint[
'txt']);
 
  582    public function toXML($a_include_header = 
true, $a_include_binary = 
true, $a_shuffle = 
false, $test_output = 
false, $force_image_references = 
false)
 
  584        include_once 
"./Modules/TestQuestionPool/classes/export/qti12/class." . $this->
getQuestionType() . 
"Export.php";
 
  586        $export = 
new $classname($this);
 
  587        return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
 
  614            "SELECT * FROM qpl_questions WHERE obj_fi = %s AND title = %s",
 
  615            array(
'integer',
'text'),
 
  616            array($questionpool_id, 
$title)
 
  654        $this->test_id = 
$id;
 
  710        $this->est_working_time = array(
"h" => (
int) $hour, 
"m" => (
int) $min, 
"s" => (
int) $sec);
 
  721        $this->est_working_time = array(
 
  722            'h' => (
int) substr($durationString, 0, 2),
 
  723            'm' => (
int) substr($durationString, 3, 2),
 
  724            's' => (
int) substr($durationString, 6, 2)
 
  738            foreach ($array as $key => $value) {
 
  739                if (strcmp($key, $searchkey) == 0) {
 
  793        require_once 
'Services/Utilities/classes/class.ilUtil.php';
 
  859        return $this->refinery->string()->stripTags()->transform($this->
comment ?? 
'');
 
  892        if (!$this->est_working_time) {
 
  893            $this->est_working_time = array(
"h" => 0, 
"m" => 0, 
"s" => 0);
 
  912        return $this->refinery->string()->stripTags()->transform($this->author);
 
  980        if (!strlen($this->external_id)) {
 
  981            if ($this->
getId() > 0) {
 
  984                return uniqid(
'', 
true);
 
 1004            "SELECT points FROM qpl_questions WHERE question_id = %s",
 
 1008        if (
$result->numRows() == 1) {
 
 1027            "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",
 
 1050            "SELECT suggested_solution_id FROM qpl_sol_sug WHERE question_fi = %s",
 
 1069        return $question->getSuggestedSolutionOutput();
 
 1075        foreach ($this->suggested_solutions as $solution) {
 
 1076            switch ($solution[
"type"]) {
 
 1084                    $possible_texts = array_values(array_filter(array(
 
 1087                        $this->lng->txt(
'tst_show_solution_suggested')
 
 1090                    require_once 
'Services/WebAccessChecker/classes/class.ilWACSignedPath.php';
 
 1095                    $solutionValue = $solution[
"value"];
 
 1096                    $solutionValue = $this->
fixSvgToPng($solutionValue);
 
 1102        return join(
"<br />", $output);
 
 1119            "SELECT * FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
 
 1120            array(
'integer',
'integer'),
 
 1121            array($question_id, $subquestion_index)
 
 1123        if (
$result->numRows() == 1) {
 
 1126                "internal_link" => $row[
"internal_link"],
 
 1127                "import_id" => $row[
"import_id"]
 
 1157        if (is_null(
$pass)) {
 
 1158            include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 1162            "SELECT * FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 1163            array(
'integer',
'integer',
'integer'),
 
 1164            array($active_id, $question_id, 
$pass)
 
 1166        if (
$result->numRows() == 1) {
 
 1183        return round(self::_getReachedPoints($active_id, $this->
getId(), 
$pass), 2);
 
 1210        if (is_null(
$pass)) {
 
 1211            include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1221        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
 
 1223        $requestsStatisticData = $hintTracking->getRequestStatisticDataByQuestionAndTestpass();
 
 1224        $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
 
 1229        return $reached_points;
 
 1247        if (is_null(
$pass)) {
 
 1248            include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1256        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
 
 1258        $requestsStatisticData = $questionHintTracking->getRequestStatisticDataByQuestionAndTestpass();
 
 1259        $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
 
 1270        if (is_null($reached_points)) {
 
 1271            $reached_points = 0;
 
 1275        $existingSolutions = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 1277        $this->
getProcessLocker()->executeUserQuestionResultUpdateOperation(
function () use (
$ilDB, $active_id, 
$pass, $reached_points, $requestsStatisticData, $isAnswered, $existingSolutions) {
 
 1279                        DELETE FROM             tst_test_result 
 1281                        WHERE                   active_fi = %s 
 1282                        AND                             question_fi = %s 
 1286            $types = array(
'integer', 
'integer', 
'integer');
 
 1287            $values = array($active_id, $this->
getId(), 
$pass);
 
 1289            if ($this->
getStep() !== 
null) {
 
 1294                $types[] = 
'integer';
 
 1299            if ($existingSolutions[
'authorized']) {
 
 1300                $next_id = 
$ilDB->nextId(
"tst_test_result");
 
 1302                    'test_result_id' => array(
'integer', $next_id),
 
 1303                    'active_fi' => array(
'integer', $active_id),
 
 1304                    'question_fi' => array(
'integer', $this->
getId()),
 
 1305                    'pass' => array(
'integer', 
$pass),
 
 1306                    'points' => array(
'float', $reached_points),
 
 1307                    'tstamp' => array(
'integer', time()),
 
 1308                    'hint_count' => array(
'integer', $requestsStatisticData->getRequestsCount()),
 
 1309                    'hint_points' => array(
'float', $requestsStatisticData->getRequestsPoints()),
 
 1310                    'answered' => array(
'integer', $isAnswered)
 
 1313                if ($this->
getStep() !== 
null) {
 
 1314                    $fieldData[
'step'] = array(
'integer', $this->
getStep());
 
 1317                $ilDB->insert(
'tst_test_result', $fieldData);
 
 1322        include_once(
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
 
 1329                        "log_user_answered_question",
 
 1343        include_once 
'Modules/Course/classes/class.ilCourseObjectiveResult.php';
 
 1361        $saveStatus = 
false;
 
 1363        $this->
getProcessLocker()->executePersistWorkingStateLockOperation(
function () use ($active_id, 
$pass, $authorized, $obligationsEnabled, &$saveStatus) {
 
 1364            if (
$pass === 
null) {
 
 1365                require_once 
'Modules/Test/classes/class.ilObjTest.php';
 
 1419        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1420        include_once 
"./Modules/Test/classes/class.assMarkSchema.php";
 
 1424        if (
$pass !== 
null) {
 
 1426                        SELECT          tst_pass_result.* 
 1427                        FROM            tst_pass_result 
 1428                        WHERE           active_fi = %s 
 1434                array(
'integer', 
'integer'),
 
 1435                array($active_id, 
$pass)
 
 1440            $max = $row_result[
'maxpoints'];
 
 1441            $reached = $row_result[
'points'];
 
 1443            $obligationsAnswered = (int) $row_result[
'obligations_answered'];
 
 1445            include_once 
"./Modules/Test/classes/class.assMarkSchema.php";
 
 1447            $percentage = (!$max) ? 0 : ($reached / $max) * 100.0;
 
 1449            $mark = ASS_MarkSchema::_getMatchingMarkFromActiveId($active_id, $percentage);
 
 1451            $isPassed = ($mark[
"passed"] ? 1 : 0);
 
 1452            $isFailed = (!$mark[
"passed"] ? 1 : 0);
 
 1454            $userTestResultUpdateCallback = 
function () use (
 
 1462                $obligationsAnswered,
 
 1466                $passedOnceBefore = 0;
 
 1467                $query = 
"SELECT passed_once FROM tst_result_cache WHERE active_fi = %s";
 
 1469                while ($row = 
$ilDB->fetchAssoc(
$res)) {
 
 1470                    $passedOnceBefore = (int) $row[
'passed_once'];
 
 1473                $passedOnce = (int) ($isPassed || $passedOnceBefore);
 
 1476                    "DELETE FROM tst_result_cache WHERE active_fi = %s",
 
 1481                $ilDB->insert(
'tst_result_cache', array(
 
 1482                    'active_fi' => array(
'integer', $active_id),
 
 1483                    'pass' => array(
'integer', strlen(
$pass) ? 
$pass : 0),
 
 1484                    'max_points' => array(
'float', strlen($max) ? $max : 0),
 
 1485                    'reached_points' => array(
'float', strlen($reached) ? $reached : 0),
 
 1486                    'mark_short' => array(
'text', strlen($mark[
"short_name"]) ? $mark[
"short_name"] : 
" "),
 
 1487                    'mark_official' => array(
'text', strlen($mark[
"official_name"]) ? $mark[
"official_name"] : 
" "),
 
 1488                    'passed_once' => array(
'integer', $passedOnce),
 
 1489                    'passed' => array(
'integer', $isPassed),
 
 1490                    'failed' => array(
'integer', $isFailed),
 
 1491                    'tstamp' => array(
'integer', time()),
 
 1492                    'hint_count' => array(
'integer', $row_result[
'hint_count']),
 
 1493                    'hint_points' => array(
'float', $row_result[
'hint_points']),
 
 1494                    'obligations_answered' => array(
'integer', $obligationsAnswered)
 
 1499                $processLocker->executeUserTestResultUpdateLockOperation($userTestResultUpdateCallback);
 
 1501                $userTestResultUpdateCallback();
 
 1512        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 1514        if (self::getResultGateway() !== 
null) {
 
 1527                        SELECT          SUM(points) reachedpoints, 
 1528                                                SUM(hint_count) hint_count, 
 1529                                                SUM(hint_points) hint_points, 
 1530                                                COUNT(DISTINCT(question_fi)) answeredquestions 
 1531                        FROM            tst_test_result 
 1532                        WHERE           active_fi = %s 
 1535            array(
'integer',
'integer'),
 
 1536            array($active_id, 
$pass)
 
 1540            if ($obligationsEnabled) {
 
 1542                                        SELECT          answered answ 
 1543                                        FROM            tst_test_question 
 1544                                          INNER JOIN    tst_active 
 1546                                                AND                     tst_test_question.test_fi = tst_active.test_fi 
 1547                                        LEFT JOIN       tst_test_result 
 1548                                                ON                      tst_test_result.active_fi = %s 
 1549                                                AND                     tst_test_result.pass = %s 
 1550                                                AND                     tst_test_question.question_fi = tst_test_result.question_fi 
 1551                                        WHERE           obligatory = 1';
 
 1553                $result_obligatory = 
$ilDB->queryF(
 
 1555                    array(
'integer',
'integer',
'integer'),
 
 1556                    array($active_id, $active_id, 
$pass)
 
 1559                $obligations_answered = 1;
 
 1561                while ($row_obligatory = 
$ilDB->fetchAssoc($result_obligatory)) {
 
 1562                    if (!(
int) $row_obligatory[
'answ']) {
 
 1563                        $obligations_answered = 0;
 
 1568                $obligations_answered = 1;
 
 1573            if ($row[
'reachedpoints'] === 
null) {
 
 1574                $row[
'reachedpoints'] = 0;
 
 1576            if ($row[
'hint_count'] === 
null) {
 
 1577                $row[
'hint_count'] = 0;
 
 1579            if ($row[
'hint_points'] === 
null) {
 
 1580                $row[
'hint_points'] = 0;
 
 1585            $updatePassResultCallback = 
function () use (
$ilDB, 
$data, $active_id, 
$pass, $row, $time, $obligations_answered, $exam_identifier) {
 
 1591                        'active_fi' => array(
'integer', $active_id),
 
 1592                        'pass' => array(
'integer', strlen(
$pass) ? 
$pass : 0)),
 
 1594                        'points' => array(
'float', $row[
'reachedpoints'] ? $row[
'reachedpoints'] : 0),
 
 1595                        'maxpoints' => array(
'float', 
$data[
'points']),
 
 1596                        'questioncount' => array(
'integer', 
$data[
'count']),
 
 1597                        'answeredquestions' => array(
'integer', $row[
'answeredquestions']),
 
 1598                        'workingtime' => array(
'integer', $time),
 
 1599                        'tstamp' => array(
'integer', time()),
 
 1600                        'hint_count' => array(
'integer', $row[
'hint_count']),
 
 1601                        'hint_points' => array(
'float', $row[
'hint_points']),
 
 1602                        'obligations_answered' => array(
'integer', $obligations_answered),
 
 1603                        'exam_id' => array(
'text', $exam_identifier)
 
 1609                $processLocker->executeUserPassResultUpdateLockOperation($updatePassResultCallback);
 
 1611                $updatePassResultCallback();
 
 1618            'active_fi' => $active_id,
 
 1620            'points' => ($row[
"reachedpoints"]) ? $row[
"reachedpoints"] : 0,
 
 1621            'maxpoints' => 
$data[
"points"],
 
 1622            'questioncount' => 
$data[
"count"],
 
 1623            'answeredquestions' => $row[
"answeredquestions"],
 
 1624            'workingtime' => $time,
 
 1626            'hint_count' => $row[
'hint_count'],
 
 1627            'hint_points' => $row[
'hint_points'],
 
 1628            'obligations_answered' => $obligations_answered,
 
 1629            'exam_id' => $exam_identifier
 
 1640    public static function logAction($logtext = 
"", $active_id = 
"", $question_id = 
"")
 
 1643        if (strlen($question_id)) {
 
 1647        require_once 
'Modules/Test/classes/class.ilObjAssessmentFolder.php';
 
 1648        require_once 
'Modules/Test/classes/class.ilObjTest.php';
 
 1669        if (!@is_dir($mediatempdir)) {
 
 1672        $temp_name = tempnam($mediatempdir, 
$name . 
"_____");
 
 1673        $temp_name = str_replace(
"\\", 
"/", $temp_name);
 
 1674        @unlink($temp_name);
 
 1689        return CLIENT_WEB_DIR . 
"/assessment/$this->obj_id/$this->id/solution/";
 
 1700        return CLIENT_WEB_DIR . 
"/assessment/$this->obj_id/$this->id/java/";
 
 1711        if ($question_id === 
null) {
 
 1715        if ($object_id === 
null) {
 
 1724        return CLIENT_WEB_DIR . 
"/assessment/{$parentObjectId}/{$questionId}/images/";
 
 1735        return CLIENT_WEB_DIR . 
"/assessment/$this->obj_id/$this->id/flash/";
 
 1746        $relative_path = 
"assessment/$this->obj_id/$this->id/java/";
 
 1757        $relative_path = 
"assessment/$this->obj_id/$this->id/solution/";
 
 1771        if (!$this->export_image_path) {
 
 1772            $relative_path = 
"assessment/$this->obj_id/$this->id/images/";
 
 1787        $relative_path = 
"assessment/$this->obj_id/$this->id/flash/";
 
 1808        if (!count($solution)) {
 
 1823        if (is_null(
$pass)) {
 
 1827        if ($this->
getStep() !== 
null) {
 
 1831                                WHERE active_fi = %s 
 1832                                AND question_fi = %s 
 1836                                ORDER BY solution_id";
 
 1840                array(
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 1841                array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
 
 1847                                WHERE active_fi = %s 
 1848                                AND question_fi = %s 
 1851                                ORDER BY solution_id 
 1856                array(
'integer', 
'integer', 
'integer', 
'integer'),
 
 1857                array($active_id, $this->
getId(), $pass, (
int) $authorized)
 
 1881        if ($question_id < 1) {
 
 1882            $question_id = $this->
getId();
 
 1885            "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",
 
 1890        $count = $row[
"question_count"];
 
 1894                        SELECT tst_active.test_fi 
 1896                        INNER JOIN tst_test_rnd_qst ON tst_test_rnd_qst.question_fi = qpl_questions.question_id 
 1897                        INNER JOIN tst_active ON tst_active.active_id = tst_test_rnd_qst.active_fi 
 1898                        WHERE qpl_questions.original_id = %s 
 1899                        GROUP BY tst_active.test_fi",
 
 1919        if ($question_id < 1) {
 
 1923            "SELECT original_id FROM qpl_questions WHERE question_id = %s",
 
 1928        return ($row[
"original_id"] > 0) ? 
true : 
false;
 
 1939        $keys = array_keys($array);
 
 1942        foreach (
$keys as $key) {
 
 1959            "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",
 
 1964        return $data[
"type_tag"];
 
 2001        if (!is_array($answer_table_name)) {
 
 2002            $answer_table_name = array($answer_table_name);
 
 2005        foreach ($answer_table_name as $table) {
 
 2006            if (strlen($table)) {
 
 2007                $affectedRows = 
$ilDB->manipulateF(
 
 2008                    "DELETE FROM $table WHERE question_fi = %s",
 
 2029        if (!is_array($additional_table_name)) {
 
 2030            $additional_table_name = array($additional_table_name);
 
 2033        foreach ($additional_table_name as $table) {
 
 2034            if (strlen($table)) {
 
 2035                $affectedRows = 
$ilDB->manipulateF(
 
 2036                    "DELETE FROM $table WHERE question_fi = %s",
 
 2052        include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 2064    public function delete($question_id)
 
 2068        $ilLog = 
$DIC[
'ilLog'];
 
 2070        if ($question_id < 1) {
 
 2075            "SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
 
 2079        if (
$result->numRows() == 1) {
 
 2087        } 
catch (Exception 
$e) {
 
 2088            $ilLog->write(
"EXCEPTION: Could not delete page of question $question_id: $e");
 
 2092        $affectedRows = 
$ilDB->manipulateF(
 
 2093            "DELETE FROM qpl_questions WHERE question_id = %s",
 
 2097        if ($affectedRows == 0) {
 
 2106        } 
catch (Exception 
$e) {
 
 2107            $ilLog->write(
"EXCEPTION: Could not delete additional table data of question $question_id: $e");
 
 2113            $affectedRows = 
$ilDB->manipulateF(
 
 2114                "DELETE FROM tst_test_question WHERE question_fi = %s",
 
 2118        } 
catch (Exception 
$e) {
 
 2119            $ilLog->write(
"EXCEPTION: Could not delete delete question $question_id from a test: $e");
 
 2125            $affectedRows = 
$ilDB->manipulateF(
 
 2126                "DELETE FROM qpl_sol_sug WHERE question_fi = %s",
 
 2130        } 
catch (Exception 
$e) {
 
 2131            $ilLog->write(
"EXCEPTION: Could not delete suggested solutions of question $question_id: $e");
 
 2137            if (preg_match(
"/\d+/", 
$obj_id) and preg_match(
"/\d+/", $question_id) and is_dir($directory)) {
 
 2138                include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 2141        } 
catch (Exception 
$e) {
 
 2142            $ilLog->write(
"EXCEPTION: Could not delete question file directory $directory of question $question_id: $e");
 
 2147            include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 2153            foreach (
$mobs as $mob) {
 
 2160        } 
catch (Exception 
$e) {
 
 2161            $ilLog->write(
"EXCEPTION: Error deleting the media objects of question $question_id: $e");
 
 2165        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
 
 2166        ilAssQuestionHintTracking::deleteRequestsByQuestionIds(array($question_id));
 
 2168        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
 
 2171        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
 
 2173        $assignmentList->setParentObjId(
$obj_id);
 
 2174        $assignmentList->setQuestionIdFilter($question_id);
 
 2175        $assignmentList->loadFromDb();
 
 2176        foreach ($assignmentList->getAssignmentsByQuestionId($question_id) as $assignment) {
 
 2178            $assignment->deleteFromDb();
 
 2185            include_once 
"./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
 
 2187        } 
catch (Exception 
$e) {
 
 2188            $ilLog->write(
"EXCEPTION: Error updating the question pool question count of question pool " . $this->
getObjId() . 
" when deleting question $question_id: $e");
 
 2199        require_once 
'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
 
 2200        require_once 
'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
 
 2203        foreach ($taxIds as $taxId) {
 
 2205            $taxNodeAssignment->deleteAssignmentsOfItem($this->
getId());
 
 2230            "SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
 
 2231            array(
'integer',
'integer'),
 
 2232            array($a_q_id, $a_q_id)
 
 2234        if (
$result->numRows() == 0) {
 
 2237        $found_id = array();
 
 2239            array_push($found_id, $row[
"question_id"]);
 
 2242        $result = 
$ilDB->query(
"SELECT * FROM tst_test_result WHERE " . 
$ilDB->in(
'question_fi', $found_id, 
false, 
'integer'));
 
 2259            "SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
 
 2260            array(
'integer',
'integer'),
 
 2261            array($a_q_id, $a_q_id)
 
 2263        if (
$result->numRows() == 0) {
 
 2266        $found_id = array();
 
 2268            array_push($found_id, $row[
"question_id"]);
 
 2270        $result = 
$ilDB->query(
"SELECT * FROM tst_test_result WHERE " . 
$ilDB->in(
'question_fi', $found_id, 
false, 
'integer'));
 
 2273            $reached = $row[
"points"];
 
 2274            include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 2276            array_push($answers, array(
"reached" => $reached, 
"max" => $max));
 
 2280        foreach ($answers as $key => $value) {
 
 2281            $max += $value[
"max"];
 
 2282            $reached += $value[
"reached"];
 
 2285            return $reached / $max;
 
 2301            "SELECT title FROM qpl_questions WHERE question_id = %s",
 
 2305        if (
$result->numRows() == 1) {
 
 2307            return $row[
"title"];
 
 2323            "SELECT question_text FROM qpl_questions WHERE question_id = %s",
 
 2327        if (
$result->numRows() == 1) {
 
 2329            return $row[
"question_text"];
 
 2337        if (!file_exists($file)) {
 
 2341        if (!is_file($file)) {
 
 2345        if (!is_readable($file)) {
 
 2354        include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 2356        foreach (
$mobs as $mob) {
 
 2363        include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 2365        foreach (
$mobs as $mob) {
 
 2377        include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 2379        $this->page->setId($this->
getId());
 
 2380        $this->page->setParentId($qpl_id);
 
 2381        $this->page->setXMLContent(
"<PageObject><PageContent>" .
 
 2382            "<Question QRef=\"il__qst_" . $this->
getId() . 
"\"/>" .
 
 2383            "</PageContent></PageObject>");
 
 2384        $this->page->create();
 
 2390            include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 2393            $xml = str_replace(
"il__qst_" . $a_q_id, 
"il__qst_" . $this->
id, 
$page->getXMLContent());
 
 2394            $this->page->setXMLContent(
$xml);
 
 2395            $this->page->updateFromXML();
 
 2401        include_once 
"./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php";
 
 2403        return $page->getXMLContent();
 
 2416        if ($question_id < 1) {
 
 2420            "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",
 
 2424        if (
$result->numRows() == 1) {
 
 2426            return $data[
"type_tag"];
 
 2444        if ($question_id < 1) {
 
 2449            "SELECT title FROM qpl_questions WHERE qpl_questions.question_id = %s",
 
 2453        if (
$result->numRows() == 1) {
 
 2455            return $data[
"title"];
 
 2472        'ok.svg' => 
'ok.png', 
'not_ok.svg' => 
'not_ok.png',
 
 2473        'checkbox_checked.svg' => 
'checkbox_checked.png',
 
 2474        'checkbox_unchecked.svg' => 
'checkbox_unchecked.png',
 
 2475        'radiobutton_checked.svg' => 
'radiobutton_checked.png',
 
 2476        'radiobutton_unchecked.svg' => 
'radiobutton_unchecked.png' 
 2481        $needles = array_keys(self::$imageSourceFixReplaceMap);
 
 2482        $replacements = array_values(self::$imageSourceFixReplaceMap);
 
 2483        return str_replace($needles, $replacements, $imageFilenameContainingString);
 
 2490        if (preg_match_all(
'/src="(.*?)"/m', $html, $matches)) {
 
 2491            $sources = $matches[1];
 
 2493            $needleReplacementMap = array();
 
 2495            foreach ($sources as $src) {
 
 2498                if (file_exists($file)) {
 
 2502                $levels = explode(DIRECTORY_SEPARATOR, $src);
 
 2503                if (count($levels) < 5 || $levels[0] != 
'Customizing' || $levels[2] != 
'skin') {
 
 2509                if ($levels[4] == 
'Modules' || $levels[4] == 
'Services') {
 
 2510                    $component = $levels[4] . DIRECTORY_SEPARATOR . $levels[5];
 
 2516            if (count($needleReplacementMap)) {
 
 2517                $html = str_replace(array_keys($needleReplacementMap), array_values($needleReplacementMap), $html);
 
 2536            "SELECT external_id FROM qpl_questions WHERE question_id = %s",
 
 2540        if (
$result->numRows() == 1) {
 
 2542            $this->external_id = 
$data[
'external_id'];
 
 2546            "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
 
 2548            array($this->
getId())
 
 2550        $this->suggested_solutions = array();
 
 2552            include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 2555                $this->suggested_solutions[$row[
"subquestion_index"]] = array(
 
 2556                    "type" => $row[
"type"],
 
 2558                    "internal_link" => $row[
"internal_link"],
 
 2559                    "import_id" => $row[
"import_id"]
 
 2579        $estw_time = sprintf(
"%02d:%02d:%02d", $estw_time[
'h'], $estw_time[
'm'], $estw_time[
's']);
 
 2582            if ($a_create_page) {
 
 2589            $next_id = 
$ilDB->nextId(
'qpl_questions');
 
 2590            $affectedRows = 
$ilDB->insert(
"qpl_questions", array(
 
 2591                "question_id" => array(
"integer", $next_id),
 
 2593                "obj_fi" => array(
"integer", 
$obj_id),
 
 2594                "title" => array(
"text", 
null),
 
 2595                "description" => array(
"text", 
null),
 
 2596                "author" => array(
"text", $this->
getAuthor()),
 
 2597                "owner" => array(
"integer", 
$ilUser->getId()),
 
 2598                "question_text" => array(
"clob", 
null),
 
 2599                "points" => array(
"float", 0),
 
 2601                "working_time" => array(
"text", $estw_time),
 
 2602                "complete" => array(
"text", $complete),
 
 2603                "created" => array(
"integer", time()),
 
 2604                "original_id" => array(
"integer", 
null),
 
 2605                "tstamp" => array(
"integer", $tstamp),
 
 2609            $this->
setId($next_id);
 
 2611            if ($a_create_page) {
 
 2619        return $this->
getId();
 
 2628        $estw_time = sprintf(
"%02d:%02d:%02d", $estw_time[
'h'], $estw_time[
'm'], $estw_time[
's']);
 
 2631        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 2632        if ($this->
getId() == -1) {
 
 2634            $next_id = 
$ilDB->nextId(
'qpl_questions');
 
 2635            $affectedRows = 
$ilDB->insert(
"qpl_questions", array(
 
 2636                "question_id" => array(
"integer", $next_id),
 
 2638                "obj_fi" => array(
"integer", $this->
getObjId()),
 
 2639                "title" => array(
"text", $this->
getTitle()),
 
 2640                "description" => array(
"text", $this->
getComment()),
 
 2641                "author" => array(
"text", $this->
getAuthor()),
 
 2642                "owner" => array(
"integer", $this->
getOwner()),
 
 2645                "working_time" => array(
"text", $estw_time),
 
 2646                "nr_of_tries" => array(
"integer", $this->
getNrOfTries()),
 
 2647                "created" => array(
"integer", time()),
 
 2649                "tstamp" => array(
"integer", time()),
 
 2653            $this->
setId($next_id);
 
 2658            $affectedRows = 
$ilDB->update(
"qpl_questions", array(
 
 2659                "obj_fi" => array(
"integer", $this->
getObjId()),
 
 2660                "title" => array(
"text", $this->
getTitle()),
 
 2661                "description" => array(
"text", $this->
getComment()),
 
 2662                "author" => array(
"text", $this->
getAuthor()),
 
 2665                "nr_of_tries" => array(
"integer", $this->
getNrOfTries()),
 
 2666                "working_time" => array(
"text", $estw_time),
 
 2667                "tstamp" => array(
"integer", time()),
 
 2668                'complete' => array(
'integer', $this->
isComplete()),
 
 2671            "question_id" => array(
"integer", $this->
getId())
 
 2686        $this->updateSuggestedSolutions();
 
 2696        $DIC->database()->update(
'qpl_questions', array(
 
 2697            'tstamp' => array(
'integer', time()),
 
 2698            'owner' => array(
'integer', ($this->
getOwner() <= 0 ? $this->
ilias->account->id : $this->getOwner())),
 
 2699            'complete' => array(
'integer', $complete),
 
 2700            'lifecycle' => array(
'text', $this->
getLifecycle()->getIdentifier()),
 
 2702            'question_id' => array(
'integer', $this->
getId())
 
 2706        include_once 
"./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
 
 2722        $query = 
"UPDATE qpl_questions SET tstamp = %s, original_id = %s WHERE question_id = %s";
 
 2724        $GLOBALS[
'DIC'][
'ilDB']->manipulateF(
 
 2726            array(
'integer',
'integer', 
'text'),
 
 2727            array(time(), $originalId, $questionId)
 
 2733        $query = 
"UPDATE qpl_questions SET tstamp = %s, original_id = NULL WHERE question_id = %s";
 
 2735        $GLOBALS[
'DIC'][
'ilDB']->manipulateF(
 
 2737            array(
'integer', 
'text'),
 
 2738            array(time(), $questionId)
 
 2745    protected function onDuplicate($originalParentId, $originalQuestionId, $duplicateParentId, $duplicateQuestionId)
 
 2750        $this->feedbackOBJ->duplicateFeedback($originalQuestionId, $duplicateQuestionId);
 
 2766        $this->feedbackOBJ->syncFeedback($origQuestionId, $dupQuestionId);
 
 2772    protected function onCopy($sourceParentId, $sourceQuestionId, $targetParentId, $targetQuestionId)
 
 2777        $this->feedbackOBJ->duplicateFeedback($sourceQuestionId, $targetQuestionId);
 
 2794        $affectedRows = 
$ilDB->manipulateF(
 
 2795            "DELETE FROM qpl_sol_sug WHERE question_fi = %s",
 
 2797            array($this->
getId())
 
 2800        include_once 
"./Services/Link/classes/class.ilInternalLink.php";
 
 2802        $this->suggested_solutions = array();
 
 2815        if (array_key_exists($subquestion_index, $this->suggested_solutions)) {
 
 2816            return $this->suggested_solutions[$subquestion_index];
 
 2832        if (array_key_exists($subquestion_index, $this->suggested_solutions)) {
 
 2833            $title = $this->suggested_solutions[$subquestion_index][
"internal_link"];
 
 2852        if (strcmp($solution_id, 
"") != 0) {
 
 2855                $import_id = $solution_id;
 
 2858            $this->suggested_solutions[$subquestion_index] = array(
 
 2859                "internal_link" => $solution_id,
 
 2860                "import_id" => $import_id
 
 2871        $ilLog = 
$DIC[
'ilLog'];
 
 2873        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2874            if (strcmp($solution[
"type"], 
"file") == 0) {
 
 2876                $filepath_original = str_replace(
 
 2877                    "/{$this->obj_id}/{$this->id}/solution",
 
 2878                    "/$parent_id/$question_id/solution",
 
 2881                if (!file_exists($filepath)) {
 
 2887                        $ilLog->write(
"File could not be duplicated!!!!", $ilLog->ERROR);
 
 2888                        $ilLog->write(
"object: " . print_r($this, 
true), $ilLog->ERROR);
 
 2901        $ilLog = 
$DIC[
'ilLog'];
 
 2904        $filepath_original = str_replace(
"/$this->id/solution", 
"/$original_id/solution", $filepath);
 
 2906        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2907            if (strcmp($solution[
"type"], 
"file") == 0) {
 
 2908                if (!file_exists($filepath_original)) {
 
 2914                        $ilLog->write(
"File could not be duplicated!!!!", $ilLog->ERROR);
 
 2915                        $ilLog->write(
"object: " . print_r($this, 
true), $ilLog->ERROR);
 
 2925        $ilLog = 
$DIC[
'ilLog'];
 
 2927        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2928            if (strcmp($solution[
"type"], 
"file") == 0) {
 
 2930                $filepath_original = str_replace(
"/$this->obj_id/$this->id/solution", 
"/$source_questionpool_id/$source_question_id/solution", $filepath);
 
 2931                if (!file_exists($filepath)) {
 
 2937                        $ilLog->write(
"File could not be copied!!!!", $ilLog->ERROR);
 
 2938                        $ilLog->write(
"object: " . print_r($this, 
true), $ilLog->ERROR);
 
 2948    public function updateSuggestedSolutions(
$original_id = 
"")
 
 2954        include_once 
"./Services/Link/classes/class.ilInternalLink.php";
 
 2955        $affectedRows = 
$ilDB->manipulateF(
 
 2956            "DELETE FROM qpl_sol_sug WHERE question_fi = %s",
 
 2961        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 2962        foreach ($this->suggested_solutions as 
$index => $solution) {
 
 2963            $next_id = 
$ilDB->nextId(
'qpl_sol_sug');
 
 2968                                           'suggested_solution_id' => array( 
'integer',         $next_id ),
 
 2969                                           'question_fi' => array( 
'integer',   
$id ),
 
 2970                                           'type' => array( 
'text',             $solution[
'type'] ),
 
 2972                                           'internal_link' => array( 
'text',            $solution[
'internal_link'] ),
 
 2973                                           'import_id' => array( 
'text',                
null ),
 
 2974                                           'subquestion_index' => array( 
'integer',     
$index ),
 
 2975                                           'tstamp' => array( 
'integer',        time() ),
 
 2978            if (preg_match(
"/il_(\d*?)_(\w+)_(\d+)/", $solution[
"internal_link"], $matches)) {
 
 2997    public function saveSuggestedSolution(
$type, $solution_id = 
"", $subquestion_index = 0, $value = 
"")
 
 3002        $affectedRows = 
$ilDB->manipulateF(
 
 3003            "DELETE FROM qpl_sol_sug WHERE question_fi = %s AND subquestion_index = %s",
 
 3004            array(
"integer", 
"integer"),
 
 3011        $next_id = 
$ilDB->nextId(
'qpl_sol_sug');
 
 3012        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 3014        $affectedRows = 
$ilDB->insert(
 
 3017                                                       'suggested_solution_id' => array( 
'integer',     $next_id ),
 
 3018                                                       'question_fi' => array( 
'integer',       $this->
getId() ),
 
 3019                                                       'type' => array( 
'text',                 
$type ),
 
 3021                                                       'internal_link' => array( 
'text',                $solution_id ),
 
 3022                                                       'import_id' => array( 
'text',            
null ),
 
 3023                                                       'subquestion_index' => array( 
'integer',         $subquestion_index ),
 
 3024                                                       'tstamp' => array( 
'integer',    time() ),
 
 3027        if ($affectedRows == 1) {
 
 3028            $this->suggested_solutions[$subquestion_index] = array(
 
 3031                "internal_link" => $solution_id,
 
 3040        if (preg_match(
"/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches)) {
 
 3041            switch ($matches[2]) {
 
 3058            if (strcmp($resolved_link, 
"") == 0) {
 
 3059                $resolved_link = $internal_link;
 
 3062            $resolved_link = $internal_link;
 
 3064        return $resolved_link;
 
 3073            "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
 
 3079                $internal_link = $row[
"internal_link"];
 
 3080                include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 3082                if (strcmp($internal_link, $resolved_link) != 0) {
 
 3084                    $affectedRows = 
$ilDB->manipulateF(
 
 3085                        "UPDATE qpl_sol_sug SET internal_link = %s WHERE suggested_solution_id = %s",
 
 3086                        array(
'text',
'integer'),
 
 3087                        array($resolved_link, $row[
"suggested_solution_id"])
 
 3093        if ($resolvedlinks) {
 
 3097            include_once 
"./Services/Link/classes/class.ilInternalLink.php";
 
 3101                "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
 
 3107                    if (preg_match(
"/il_(\d*?)_(\w+)_(\d+)/", $row[
"internal_link"], $matches)) {
 
 3120            "lm" => 
"LearningModule",
 
 3121            "pg" => 
"PageObject",
 
 3122            "st" => 
"StructureObject",
 
 3123            "git" => 
"GlossaryItem",
 
 3124            "mob" => 
"MediaObject" 
 3127        if (preg_match(
"/il__(\w+)_(\d+)/", $target, $matches)) {
 
 3128            $type = $matches[1];
 
 3130            include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 3131            switch ($linktypes[$matches[1]]) {
 
 3132                case "LearningModule":
 
 3136                case "StructureObject":
 
 3139                case "GlossaryItem":
 
 3143                    $href = 
"./ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[
$type] . 
"&cmd=media&ref_id=" . 
$_GET[
"ref_id"] . 
"&mob_id=" . 
$target_id;
 
 3162            "SELECT * FROM qpl_questions WHERE question_id = %s",
 
 3168            if ($row[
"original_id"] > 0) {
 
 3169                return $row[
"original_id"];
 
 3171                return $row[
"question_id"];
 
 3184                        SELECT COUNT(dupl.question_id) cnt 
 3185                        FROM qpl_questions dupl 
 3186                        INNER JOIN qpl_questions orig 
 3187                        ON orig.question_id = dupl.original_id 
 3188                        WHERE dupl.question_id = %s 
 3194        return $row[
'cnt'] > 0;
 
 3208        if (!$originalObjId) {
 
 3218        $this->
setId($original);
 
 3232        $this->updateSuggestedSolutions($original);
 
 3251        if ($question_id < 1) {
 
 3256            "SELECT question_id FROM qpl_questions WHERE question_id = %s",
 
 3260        if (
$result->numRows() == 1) {
 
 3279        if ($question_id < 1) {
 
 3284            "SELECT question_id FROM qpl_questions INNER JOIN object_data ON obj_fi = obj_id WHERE question_id = %s AND type = 'qpl'",
 
 3288        if (
$result->numRows() == 1) {
 
 3314        $ilCtrl = 
$DIC[
'ilCtrl'];
 
 3318        if (strcmp($question_id, 
"") != 0) {
 
 3320            if (!strlen($question_type)) {
 
 3343        if (strcmp($this->points, 
"") == 0) {
 
 3359        $this->points = $a_points;
 
 3392            "SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
 
 3393            array(
'integer',
'integer'),
 
 3394            array($active_id, $question_id)
 
 3396        if (
$result->numRows() == 1) {
 
 3398            return $row[
"maxpass"];
 
 3417        if (($question_id < 1) || ($user_id < 1)) {
 
 3422            "SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
 
 3426        if (
$result->numRows() == 1) {
 
 3428            $qpl_object_id = $row[
"obj_fi"];
 
 3429            include_once 
"./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php";
 
 3447        if ($question_id < 1) {
 
 3451            "SELECT test_random_question_id FROM tst_test_rnd_qst WHERE question_fi = %s",
 
 3476        $requestsStatisticData = $hintTracking->getRequestStatisticData();
 
 3477        $reachedPoints = $reachedPoints - $requestsStatisticData->getRequestsPoints();
 
 3479        return $reachedPoints;
 
 3519        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 3521        if ($count_system == 1) {
 
 3527        if ($score_cutting == 0) {
 
 3553        if (is_null(
$pass)) {
 
 3554            include_once 
"./Modules/TestQuestionPool/classes/class.assQuestion.php";
 
 3558            "SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 3559            array(
'integer',
'integer',
'integer'),
 
 3560            array($active_id, $question_id, 
$pass)
 
 3582            "SELECT DISTINCT(question_fi) FROM tst_test_result JOIN tst_active " .
 
 3583            "ON (active_id = active_fi) " .
 
 3584            "WHERE " . 
$ilDB->in(
'question_fi', $a_question_ids, 
false, 
'integer') .
 
 3585            " AND user_fi = %s",
 
 3589        return (
$res->numRows() == count($a_question_ids)) ? 
true : 
false;
 
 3613        include_once 
"./Services/Utilities/classes/class.ilUtil.php";
 
 3627        for (
$i = 0; 
$i < $a_material->getMaterialCount(); 
$i++) {
 
 3628            $material = $a_material->getMaterial(
$i);
 
 3629            if (strcmp($material[
"type"], 
"mattext") == 0) {
 
 3630                $result .= $material[
"material"]->getContent();
 
 3632            if (strcmp($material[
"type"], 
"matimage") == 0) {
 
 3633                $matimage = $material[
"material"];
 
 3634                if (preg_match(
"/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) {
 
 3636                    if (!is_array(
$_SESSION[
"import_mob_xhtml"])) {
 
 3637                        $_SESSION[
"import_mob_xhtml"] = array();
 
 3639                    array_push(
$_SESSION[
"import_mob_xhtml"], array(
"mob" => $matimage->getLabel(), 
"uri" => $matimage->getUri()));
 
 3654    public function addQTIMaterial(&$a_xml_writer, $a_material, $close_material_tag = 
true, $add_mobs = 
true)
 
 3656        include_once 
"./Services/RTE/classes/class.ilRTE.php";
 
 3657        include_once(
"./Services/MediaObjects/classes/class.ilObjMediaObject.php");
 
 3659        $a_xml_writer->xmlStartTag(
"material");
 
 3661            "texttype" => 
"text/plain" 
 3663        if ($this->
isHTML($a_material)) {
 
 3664            $attrs[
"texttype"] = 
"text/xhtml";
 
 3669            foreach (
$mobs as $mob) {
 
 3670                $moblabel = 
"il_" . 
IL_INST_ID . 
"_mob_" . $mob;
 
 3671                if (strpos($a_material, 
"mm_$mob") !== 
false) {
 
 3675                            "label" => $moblabel,
 
 3676                            "uri" => 
"objects/" . 
"il_" . 
IL_INST_ID . 
"_mob_" . $mob . 
"/" . $mob_obj->getTitle()
 
 3679                    $a_xml_writer->xmlElement(
"matimage", $imgattrs, 
null);
 
 3683        if ($close_material_tag) {
 
 3684            $a_xml_writer->xmlEndTag(
"material");
 
 3692        if (preg_match(
"/.*\.(png|jpg|gif|jpeg)$/i", $plain_image_filename, $matches)) {
 
 3693            $extension = 
"." . $matches[1];
 
 3697            $plain_image_filename = uniqid($plain_image_filename . microtime(
true));
 
 3700        $hashed_filename = md5($plain_image_filename) . $extension;
 
 3702        return $hashed_filename;
 
 3721        $float_trafo = 
$refinery->kindlyTo()->float();
 
 3724        } 
catch (
ILIAS\Refinery\ConstraintViolationException 
$e) {
 
 3729            if (is_null(
$pass)) {
 
 3736                "SELECT points FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 3737                array(
'integer',
'integer',
'integer'),
 
 3738                array($active_id, $question_id, 
$pass)
 
 3740            $manual = ($manualscoring) ? 1 : 0;
 
 3741            $rowsnum = 
$result->numRows();
 
 3744                $old_points = $row[
"points"];
 
 3746                    $affectedRows = 
$ilDB->manipulateF(
 
 3747                        "UPDATE tst_test_result SET points = %s, manual = %s, tstamp = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
 
 3748                        array(
'float', 
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 3749                        array(
$points, $manual, time(), $active_id, $question_id, 
$pass)
 
 3753                $next_id = 
$ilDB->nextId(
'tst_test_result');
 
 3754                $affectedRows = 
$ilDB->manipulateF(
 
 3755                    "INSERT INTO tst_test_result (test_result_id, active_fi, question_fi, points, pass, manual, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s)",
 
 3756                    array(
'integer', 
'integer',
'integer', 
'float', 
'integer', 
'integer',
'integer'),
 
 3757                    array($next_id, $active_id, $question_id, 
$points, 
$pass, $manual, time())
 
 3761            if (self::isForcePassResultUpdateEnabled() || $old_points != 
$points || !$rowsnum) {
 
 3762                assQuestion::_updateTestPassResults($active_id, 
$pass, $obligationsEnabled);
 
 3764                include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 3765                include_once 
'./Modules/Course/classes/class.ilCourseObjectiveResult.php';
 
 3768                include_once(
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
 
 3773                    include_once 
"./Modules/Test/classes/class.ilObjTestAccess.php";
 
 3818            || !(
new ilSetting(
'advanced_editing'))->
get(
'advanced_editing_javascript_editor') === 
'tinymce') {
 
 3819            $purified_content = nl2br($purified_content);
 
 3849            "SELECT question_type_id FROM qpl_qst_type WHERE type_tag = %s",
 
 3853        if (
$result->numRows() == 1) {
 
 3855            return $row[
"question_type_id"];
 
 3860    public function syncHints()
 
 3867            "DELETE FROM qpl_hints WHERE qht_question_fi = %s",
 
 3869            array($this->original_id)
 
 3874            "SELECT * FROM qpl_hints WHERE qht_question_fi = %s",
 
 3876            array($this->
getId())
 
 3882                $next_id = 
$ilDB->nextId(
'qpl_hints');
 
 3887                        'qht_hint_id' => array(
'integer', $next_id),
 
 3888                        'qht_question_fi' => array(
'integer', $this->original_id),
 
 3889                        'qht_hint_index' => array(
'integer', $row[
"qht_hint_index"]),
 
 3890                        'qht_hint_points' => array(
'integer', $row[
"qht_hint_points"]),
 
 3891                        'qht_hint_text' => array(
'text', $row[
"qht_hint_text"]),
 
 3907        $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->
getId(), 
false);
 
 3908        $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->
getId(), 
true);
 
 3909        $collected .= $this->feedbackOBJ->getAllSpecificAnswerFeedbackContents($this->
getId());
 
 3911        foreach ($this->suggested_solutions as $solution_array) {
 
 3912            $collected .= $solution_array[
"value"];
 
 3915        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
 
 3917        foreach ($questionHintList as $questionHint) {
 
 3919            $collected .= $questionHint->getText();
 
 3932        include_once(
"./Services/RTE/classes/class.ilRTE.php");
 
 3947            "SELECT question_id FROM qpl_questions WHERE original_id = %s",
 
 3949            array($this->
getId())
 
 3951        $instances = array();
 
 3954            array_push($ids, $row[
"question_id"]);
 
 3956        foreach ($ids as $question_id) {
 
 3959                "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",
 
 3968                "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",
 
 3976        include_once 
"./Modules/Test/classes/class.ilObjTest.php";
 
 3977        foreach ($instances as $key => $value) {
 
 3985        include_once 
"./Modules/Test/classes/class.ilObjAssessmentFolder.php";
 
 3988        if (in_array($questiontype, $scoring)) {
 
 4007            "SELECT * FROM tst_active WHERE active_id = %s",
 
 4013            return array(
"user_id" => $row[
"user_fi"], 
"test_id" => $row[
"test_fi"]);
 
 4028        if (self::isCoreQuestionType($question_type)) {
 
 4037        return $questionType . 
'GUI';
 
 4042        return $questionType;
 
 4047        return str_replace(
'ass', 
'ilAss', $questionType) . 
'Feedback';
 
 4053        return file_exists(
"Modules/TestQuestionPool/classes/class.{$guiClassName}.php");
 
 4058        if ($withGuiClass) {
 
 4060            require_once 
"Modules/TestQuestionPool/classes/class.{$guiClassName}.php";
 
 4065            require_once 
"Modules/TestQuestionPool/classes/class.{$objectClassName}.php";
 
 4069        require_once 
"Modules/TestQuestionPool/classes/feedback/class.{$feedbackClassName}.php";
 
 4075        $ilPluginAdmin = 
$DIC[
'ilPluginAdmin'];
 
 4078            self::getObjectClassNameByQuestionType($questionType),
 
 4079            self::getFeedbackClassNameByQuestionType($questionType)
 
 4082        if ($withGuiClass) {
 
 4086        $pl_names = $ilPluginAdmin->getActivePluginsForSlot(
IL_COMP_MODULE, 
"TestQuestionPool", 
"qst");
 
 4087        foreach ($pl_names as $pl_name) {
 
 4089            if (strcmp($pl->getQuestionType(), $questionType) == 0) {
 
 4090                foreach ($classes as $class) {
 
 4091                    $pl->includeClass(
"class.{$class}.php");
 
 4107        if (file_exists(
"./Modules/TestQuestionPool/classes/class." . $type_tag . 
".php")) {
 
 4110            return $lng->txt($type_tag);
 
 4113            $ilPluginAdmin = 
$DIC[
'ilPluginAdmin'];
 
 4114            $pl_names = $ilPluginAdmin->getActivePluginsForSlot(
IL_COMP_MODULE, 
"TestQuestionPool", 
"qst");
 
 4115            foreach ($pl_names as $pl_name) {
 
 4117                if (strcmp($pl->getQuestionType(), $type_tag) == 0) {
 
 4118                    return $pl->getQuestionTypeTranslation();
 
 4149        $ilCtrl = 
$DIC[
'ilCtrl'];
 
 4154        if (strcmp($a_question_id, 
"") != 0) {
 
 4160            $question_gui = 
new $question_type_gui();
 
 4161            $question_gui->object->loadFromDb($a_question_id);
 
 4164            $question_gui->object->feedbackOBJ = 
new $feedbackObjectClassname($question_gui->object, $ilCtrl, 
$ilDB, 
$lng);
 
 4166            $assSettings = 
new ilSetting(
'assessment');
 
 4167            require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
 
 4169            $processLockerFactory->setQuestionId($question_gui->object->getId());
 
 4170            $processLockerFactory->setUserId(
$ilUser->getId());
 
 4171            include_once(
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
 
 4173            $question_gui->object->setProcessLocker($processLockerFactory->getLocker());
 
 4176            $ilLog = 
$DIC[
'ilLog'];
 
 4177            $ilLog->write(
'Instantiate question called without question id. (instantiateQuestionGUI@assQuestion)', $ilLog->WARNING);
 
 4180        return $question_gui;
 
 4195        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord(0) . $startrow, $this->lng->txt($this->getQuestionType()));
 
 4196        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord(1) . $startrow, $this->getTitle());
 
 4208                return $this->
getId();
 
 4228            case "est_working_time":
 
 4252            case "suggested_solutions":
 
 4259                if (array_key_exists($value, $this->arrData)) {
 
 4260                    return $this->arrData[$value];
 
 4275                $this->
setId($value);
 
 4295            case "est_working_time":
 
 4296                if (is_array($value)) {
 
 4316                $this->page = &$value;
 
 4319                $this->arrData[$key] = $value;
 
 4331        $this->nr_of_tries = $a_nr_of_tries;
 
 4336        $this->export_image_path = (string) $a_path;
 
 4344        if ($question_id < 1) {
 
 4349            "SELECT question_fi FROM tst_test_question WHERE question_fi = %s AND test_fi = %s",
 
 4350            array(
'integer', 
'integer'),
 
 4353        if (
$result->numRows() == 1) {
 
 4376        require_once 
'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
 
 4377        return new \ilAssSelfAssessmentQuestionFormatter();
 
 4389        $this->prevent_rte_usage = $a_val;
 
 4411        $this->feedbackOBJ->migrateContentForLearningModule($migrator, $this->
getId());
 
 4437        $this->selfassessmenteditingmode = $a_selfassessmenteditingmode;
 
 4457        $this->defaultnroftries = $a_defaultnroftries;
 
 4482        $query = 
"SELECT obj_fi FROM qpl_questions WHERE question_id = %s";
 
 4484        $res = 
$ilDB->queryF(
$query, array(
'integer'), array((
int) $questionId));
 
 4487        return $row[
'obj_fi'];
 
 4507        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionHintList.php';
 
 4511            require_once 
'Modules/TestQuestionPool/classes/class.ilAssHintPage.php';
 
 4513            foreach ($hintIds as $originalHintId => $duplicateHintId) {
 
 4515                $originalXML = $originalPageObject->getXMLContent();
 
 4518                $duplicatePageObject->setId($duplicateHintId);
 
 4519                $duplicatePageObject->setParentId($this->
getId());
 
 4520                $duplicatePageObject->setXMLContent($originalXML);
 
 4521                $duplicatePageObject->createFromXML();
 
 4531        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
 
 4533        $assignmentList->setParentObjId($srcParentId);
 
 4534        $assignmentList->setQuestionIdFilter($srcQuestionId);
 
 4535        $assignmentList->loadFromDb();
 
 4537        foreach ($assignmentList->getAssignmentsByQuestionId($srcQuestionId) as $assignment) {
 
 4540            $assignment->setParentObjId($trgParentId);
 
 4541            $assignment->setQuestionId($trgQuestionId);
 
 4542            $assignment->saveToDb();
 
 4551        require_once 
'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
 
 4553        $assignmentList->setParentObjId($trgParentId);
 
 4554        $assignmentList->setQuestionIdFilter($trgQuestionId);
 
 4555        $assignmentList->loadFromDb();
 
 4557        foreach ($assignmentList->getAssignmentsByQuestionId($trgQuestionId) as $assignment) {
 
 4560            $assignment->deleteFromDb();
 
 4623                        SELECT          count(active_fi) cnt 
 4627                        WHERE           active_fi = %s 
 4628                        AND                     question_fi = %s 
 4634            array(
'integer',
'integer',
'integer'),
 
 4635            array($activeId, $questionId, 
$pass)
 
 4640        return (
int) $row[
'cnt'];
 
 4663            require_once 
'Modules/TestQuestionPool/exceptions/class.ilTestQuestionPoolException.php';
 
 4706            self::ADDITIONAL_CONTENT_EDITING_MODE_RTE,
 
 4707            self::ADDITIONAL_CONTENT_EDITING_MODE_IPE
 
 4716        $this->questionChangeListeners[] = $listener;
 
 4730            $listener->notifyQuestionCreated($this);
 
 4737            $listener->notifyQuestionEdited($this);
 
 4744            $listener->notifyQuestionDeleted($this);
 
 4753        require_once 
'Services/Html/classes/class.ilHtmlPurifierFactory.php';
 
 4765                        SELECT          qpl_questions.*, 
 4766                                                {$this->getAdditionalTableName()}.* 
 4768                        LEFT JOIN       {$this->getAdditionalTableName()} 
 4769                        ON                      {$this->getAdditionalTableName()}.question_fi = qpl_questions.question_id 
 4770                        WHERE                   qpl_questions.question_id = %s 
 4799        if ($this->
getStep() !== 
null) {
 
 4803                                WHERE active_fi = %s 
 4804                                AND question_fi = %s 
 4810            return $ilDB->queryF(
 
 4812                array(
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 4813                array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
 
 4819                                WHERE active_fi = %s 
 4820                                AND question_fi = %s 
 4825            return $ilDB->queryF(
 
 4827                array(
'integer', 
'integer', 
'integer', 
'integer'),
 
 4828                array($active_id, $this->
getId(), $pass, (
int) $authorized)
 
 4844        return $ilDB->manipulateF(
 
 4845            "DELETE FROM tst_solutions WHERE solution_id = %s",
 
 4864            "SELECT * FROM tst_solutions WHERE solution_id = %s",
 
 4869        while ($row = 
$ilDB->fetchAssoc(
$res)) {
 
 4885        $this->
getProcessLocker()->executeUserSolutionUpdateLockOperation(
function () use ($active_id, 
$pass) {
 
 4903        if ($this->
getStep() !== 
null) {
 
 4905                                DELETE FROM tst_solutions 
 4906                                WHERE active_fi = %s 
 4907                                AND question_fi = %s 
 4913            return $ilDB->manipulateF(
 
 4915                array(
'integer', 
'integer', 
'integer', 
'integer', 
'integer'),
 
 4916                array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
 
 4920                                DELETE FROM tst_solutions 
 4921                                WHERE active_fi = %s 
 4922                                AND question_fi = %s 
 4927            return $ilDB->manipulateF(
 
 4929                array(
'integer', 
'integer', 
'integer', 
'integer'),
 
 4930                array($active_id, $this->
getId(), $pass, (
int) $authorized)
 
 4952        $next_id = 
$ilDB->nextId(
"tst_solutions");
 
 4955            "solution_id" => array(
"integer", $next_id),
 
 4956            "active_fi" => array(
"integer", $active_id),
 
 4957            "question_fi" => array(
"integer", $this->
getId()),
 
 4958            "value1" => array(
"clob", $value1),
 
 4959            "value2" => array(
"clob", $value2),
 
 4960            "pass" => array(
"integer", 
$pass),
 
 4961            "tstamp" => array(
"integer", isset($tstamp) ? $tstamp : time()),
 
 4962            'authorized' => array(
'integer', (
int) $authorized)
 
 4965        if ($this->
getStep() !== 
null) {
 
 4966            $fieldData[
'step'] = array(
"integer", $this->
getStep());
 
 4969        return $ilDB->insert(
"tst_solutions", $fieldData);
 
 4989            "value1" => array(
"clob", $value1),
 
 4990            "value2" => array(
"clob", $value2),
 
 4991            "tstamp" => array(
"integer", time()),
 
 4992            'authorized' => array(
'integer', (
int) $authorized)
 
 4995        if ($this->
getStep() !== 
null) {
 
 4996            $fieldData[
'step'] = array(
"integer", $this->
getStep());
 
 4999        return $ilDB->update(
"tst_solutions", $fieldData, array(
 
 5000            'solution_id' => array(
'integer', $solutionId)
 
 5011            'authorized' => array(
'integer', (
int) $authorized)
 
 5015            $fieldData[
'tstamp'] = array(
'integer', time());
 
 5019            'question_fi' => array(
'integer', $this->
getId()),
 
 5020            'active_fi' => array(
'integer', $activeId),
 
 5021            'pass' => array(
'integer', 
$pass)
 
 5024        if ($this->
getStep() !== 
null) {
 
 5025            $whereData[
'step'] = array(
"integer", $this->
getStep());
 
 5028        return $ilDB->update(
'tst_solutions', $fieldData, $whereData);
 
 5040        return implode(self::getKeyValuesImplosionSeparator(), $keyValues);
 
 5044        return explode(self::getKeyValuesImplosionSeparator(), $keyValues);
 
 5049        foreach ($this->
getSolutionValues($activeId, $passIndex, 
false) as $solutionRec) {
 
 5050            if (0 == strlen($solutionRec[
'value1']) && 0 == strlen($solutionRec[
'value2'])) {
 
 5058        return !strlen($solutionRecord[
'value1']) && !strlen($solutionRecord[
'value2']);
 
 5066        $types = array(
"integer", 
"integer", 
"integer", 
"integer");
 
 5067        $values = array($activeId, $this->
getId(), $passIndex, (
int) $authorized);
 
 5068        $valuesCondition = array();
 
 5070        foreach ($matchValues as $valueField => $value) {
 
 5071            switch ($valueField) {
 
 5074                    $valuesCondition[] = 
"{$valueField} = %s";
 
 5080                    require_once 
'Modules/TestQuestionPool/exceptions/class.ilTestQuestionPoolException.php';
 
 5085        $valuesCondition = implode(
' AND ', $valuesCondition);
 
 5088                        DELETE FROM tst_solutions 
 5089                        WHERE active_fi = %s 
 5090                        AND question_fi = %s 
 5093                        AND $valuesCondition 
 5096        if ($this->
getStep() !== 
null) {
 
 5097            $query .= 
" AND step = %s ";
 
 5098            $types[] = 
'integer';
 
 5108            $this->
saveCurrentSolution($activeId, $passIndex, $rec[
'value1'], $rec[
'value2'], 
true, $rec[
'tstamp']);
 
 5116        if (!count($intermediateSolution)) {
 
 5124            if ($considerDummyRecordCreation) {
 
 5154        $this->step = 
$step;
 
 5174        return gmdate(
'H:i:s', $time);
 
 5184        $time_array = explode(
':', $time);
 
 5185        if (
sizeof($time_array) == 3) {
 
 5186            $sec += $time_array[0] * 3600;
 
 5187            $sec += $time_array[1] * 60;
 
 5188            $sec += $time_array[2];
 
 5195        return json_encode(array());
 
 5203        $solutionAvailability = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 5204        return (
bool) $solutionAvailability[
'intermediate'];
 
 5208        $solutionAvailability = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 5209        return (
bool) $solutionAvailability[
'authorized'];
 
 5213        $solutionAvailability = $this->lookupForExistingSolutions($active_id, 
$pass);
 
 5214        return (
bool) $solutionAvailability[
'authorized'] || (bool) $solutionAvailability[
'intermediate'];
 
 5223    protected function lookupMaxStep($active_id, 
$pass)
 
 5230            "SELECT MAX(step) max_step FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
 
 5231            array(
"integer", 
"integer", 
"integer"),
 
 5237        $maxStep = $row[
'max_step'];
 
 5249    public function lookupForExistingSolutions($activeId, 
$pass)
 
 5256            'authorized' => 
false,
 
 5257            'intermediate' => 
false 
 5261                        SELECT authorized, COUNT(*) cnt 
 5263                        WHERE active_fi = %s 
 5264                        AND question_fi = %s 
 5268        if ($this->
getStep() !== 
null) {
 
 5276        $result = 
$ilDB->queryF(
$query, array(
'integer', 
'integer', 
'integer'), array($activeId, $this->
getId(), $pass));
 
 5279            if ($row[
'authorized']) {
 
 5280                $return[
'authorized'] = $row[
'cnt'] > 0;
 
 5282                $return[
'intermediate'] = $row[
'cnt'] > 0;
 
 5302        $query = 
"DELETE FROM tst_solutions WHERE question_fi = %s";
 
 5304        $DIC->database()->manipulateF(
$query, array(
'integer'), array($this->
getId()));
 
 5313                        DELETE FROM tst_solutions 
 5314                        WHERE active_fi = %s 
 5315                        AND question_fi = %s 
 5319        if ($this->
getStep() !== 
null) {
 
 5323        return $ilDB->manipulateF(
 
 5325            array(
'integer', 
'integer', 
'integer'),
 
 5326            array($activeId, $this->
getId(), $pass)
 
 5335        $this->
log($activeId, 
"log_user_solution_willingly_deleted");
 
 5337        self::_updateTestPassResults(
 
 5352                        DELETE FROM tst_test_result 
 5353                        WHERE active_fi = %s 
 5354                        AND question_fi = %s 
 5358        if ($this->
getStep() !== 
null) {
 
 5362        return $ilDB->manipulateF(
 
 5364            array(
'integer', 
'integer', 
'integer'),
 
 5365            array($activeId, $this->
getId(), $pass)
 
 5374        $IN_questionIds = 
$ilDB->in(
'question_fi', $questionIds, 
false, 
'integer');
 
 5378                        FROM tst_test_result 
 5379                        WHERE active_fi = %s 
 5386            array(
'integer', 
'integer'),
 
 5387            array($activeId, 
$pass)
 
 5390        return $row[
'cnt'] < count($questionIds);
 
 5398        $IN_questionIds = 
$ilDB->in(
'question_fi', $questionIds, 
false, 
'integer');
 
 5402                        FROM tst_test_result 
 5403                        WHERE active_fi = %s 
 5410            array(
'integer', 
'integer'),
 
 5411            array($activeId, 
$pass)
 
 5414        $questionsHavingResultRecord = array();
 
 5416        while ($row = 
$ilDB->fetchAssoc(
$res)) {
 
 5417            $questionsHavingResultRecord[] = $row[
'question_fi'];
 
 5420        $questionsMissingResultRecordt = array_diff(
 
 5422            $questionsHavingResultRecord
 
 5425        return $questionsMissingResultRecordt;
 
 5435                        FROM tst_test_result 
 5436                        WHERE active_fi = %s 
 5437                        AND question_fi = %s 
 5441        $row = 
$ilDB->fetchAssoc(
$ilDB->queryF(
$query, array(
'integer', 
'integer', 
'integer'), array($activeId, $questionId, 
$pass)));
 
 5443        return $row[
'cnt'] > 0;
 
 5452        $valuePairs = array();
 
 5454        foreach ($indexedValues as $value1 => $value2) {
 
 5455            $valuePairs[] = array(
'value1' => $value1, 
'value2' => $value2);
 
 5467        $indexedValues = array();
 
 5469        foreach ($valuePairs as $valuePair) {
 
 5470            $indexedValues[ $valuePair[
'value1'] ] = $valuePair[
'value2'];
 
 5473        return $indexedValues;
 
 5498            "UPDATE qpl_questions SET tstamp = %s  WHERE question_id = %s",
 
 5499            array(
'integer', 
'integer'),
 
 5500            array(time(), $this->
getId())
 
 5521        if ($this->testQuestionConfigInstance === 
null) {
 
 5538        include_once(
'Modules/TestQuestionPool/classes/class.ilTestQuestionConfig.php');
 
 5552        $query = 
'SELECT user_fi FROM tst_active ' . PHP_EOL
 
 5553            . 
'JOIN tst_test_question ON tst_test_question.test_fi = tst_active.test_fi ' . PHP_EOL
 
 5554            . 
'JOIN qpl_questions ON qpl_questions.question_id = tst_test_question.question_fi ' . PHP_EOL
 
 5555            . 
'WHERE qpl_questions.obj_fi = ' . $this->db->quote($this->
getObjId(), 
'integer');
 
 5558        return $res->numRows() > 0;
 
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
An exception for terminatinating execution or to throw for unit testing.
return true
Flag indicating whether or not HTTP headers will be sent when outputting captcha image/audio.
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)
const ADDITIONAL_CONTENT_EDITING_MODE_RTE
constant for additional content editing mode "default"
getQuestionTypeID()
Returns the question type of the question.
getDescriptionForHTMLOutput()
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.
const ADDITIONAL_CONTENT_EDITING_MODE_IPE
constant for additional content editing mode "pageobject"
static _getMaximumPoints($question_id)
Returns the maximum points, a learner can reach answering the question.
saveQuestionDataToDb($original_id="")
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
getQuestionForHTMLOutput()
deleteSolutionRecordByValues($activeId, $passIndex, $authorized, $matchValues)
isComplete()
Returns true, if a question is complete for use.
getHtmlQuestionContentPurifier()
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.
fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping, array $solutionhints=[])
Receives parameters from a QTI parser and creates a valid ILIAS question object.
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.
purifyAndPrepareTextAreaOutput(string $content)
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)
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)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
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)
$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)
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
static getDraftInstance()
getParticipantsSolution()
setParticipantsSolution($participantSolution)
static _updateObjectiveResult($a_user_id, $a_active_id, $a_question_id)
static _getInstanceByType(string $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 getDataWebPath(string $relative_path='')
This is originally a fix for https://mantis.ilias.de/view.php?id=35707; in general,...
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 moveUploadedFile($a_file, $a_name, $a_target, $a_raise_errors=true, $a_mode="move_uploaded")
move uploaded file
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static 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)
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
Class ChatMainBarProvider \MainMenu\Provider.
redirection script todo: (a better solution should control the processing via a xml file)
foreach($_POST as $key=> $value) $res