ILIAS  release_8 Revision v8.24
class.ilPCQuestion.php
Go to the documentation of this file.
1<?php
2
25{
26 protected ilLanguage $lng;
27 protected ilCtrl $ctrl;
28 protected ilObjUser $user;
30 protected static bool $initial_done = false;
31
35 public function init(): void
36 {
37 global $DIC;
38
39 $this->lng = $DIC->language();
40 $this->ctrl = $DIC->ctrl();
41 $this->user = $DIC->user();
42 $this->setType("pcqst");
43 }
44
45 public function setNode(php4DOMElement $a_node): void
46 {
47 parent::setNode($a_node); // this is the PageContent node
48 $this->q_node = $a_node->first_child(); //... and this the Question
49 }
50
51 public function setQuestionReference(string $a_questionreference): void
52 {
53 if (is_object($this->q_node)) {
54 $this->q_node->set_attribute("QRef", $a_questionreference);
55 }
56 }
57
58 public function getQuestionReference(): ?string
59 {
60 if (is_object($this->q_node)) {
61 return $this->q_node->get_attribute("QRef");
62 }
63 return null;
64 }
65
66 public function create(
67 ilPageObject $a_pg_obj,
68 string $a_hier_id,
69 string $a_pc_id = ""
70 ): void {
71 $this->createPageContentNode();
72 $a_pg_obj->insertContent($this, $a_hier_id, IL_INSERT_AFTER);
73 $this->q_node = $this->dom->create_element("Question");
74 $this->q_node = $this->node->append_child($this->q_node);
75 $this->q_node->set_attribute("QRef", "");
76 }
77
81 public function copyPoolQuestionIntoPage(
82 string $a_q_id,
83 string $a_hier_id
84 ): void {
85 $question = assQuestion::instantiateQuestion($a_q_id);
86 $duplicate_id = $question->copyObject(0, $question->getTitle());
87 $duplicate = assQuestion::instantiateQuestion($duplicate_id);
88 $duplicate->setObjId(0);
89
91
92 $this->q_node->set_attribute("QRef", "il__qst_" . $duplicate_id);
93 }
94
95 public static function getLangVars(): array
96 {
97 return array("ed_insert_pcqst", "empty_question", "pc_qst");
98 }
99
103 public static function afterPageUpdate(
104 ilPageObject $a_page,
105 DOMDocument $a_domdoc,
106 string $a_xml,
107 bool $a_creation
108 ): void {
109 global $DIC;
110
111 $ilDB = $DIC->database();
112
113 $ilDB->manipulateF(
114 "DELETE FROM page_question WHERE page_parent_type = %s " .
115 " AND page_id = %s AND page_lang = %s",
116 array("text", "integer", "text"),
117 array($a_page->getParentType(), $a_page->getId(), $a_page->getLanguage())
118 );
119
120 $xpath = new DOMXPath($a_domdoc);
121 $nodes = $xpath->query('//Question');
122 $q_ids = array();
123 foreach ($nodes as $node) {
124 $q_ref = $node->getAttribute("QRef");
125
126 $inst_id = ilInternalLink::_extractInstOfTarget($q_ref);
127 if (!($inst_id > 0)) {
129 if ($q_id > 0) {
130 $q_ids[$q_id] = $q_id;
131 }
132 }
133 }
134 foreach ($q_ids as $qid) {
135 $ilDB->replace(
136 "page_question",
137 [
138 "page_parent_type" => ["text", $a_page->getParentType()],
139 "page_id" => ["integer", $a_page->getId()],
140 "page_lang" => ["text", $a_page->getLanguage()],
141 "question_id" => ["integer", $qid]
142 ],
143 []
144 );
145 }
146 }
147
148 public static function beforePageDelete(
149 ilPageObject $a_page
150 ): void {
151 global $DIC;
152
153 $ilDB = $DIC->database();
154
155 $ilDB->manipulateF(
156 "DELETE FROM page_question WHERE page_parent_type = %s " .
157 " AND page_id = %s AND page_lang = %s",
158 array("text", "integer", "text"),
159 array($a_page->getParentType(), $a_page->getId(), $a_page->getLanguage())
160 );
161 }
162
163 public static function _getQuestionIdsForPage(
164 string $a_parent_type,
165 int $a_page_id,
166 string $a_lang = "-"
167 ): array {
168 global $DIC;
169
170 $ilDB = $DIC->database();
171
172 $parent_type_array = explode(':', $a_parent_type);
173
174 $res = $ilDB->queryF(
175 "SELECT * FROM page_question WHERE page_parent_type = %s " .
176 " AND page_id = %s AND page_lang = %s",
177 array("text", "integer", "text"),
178 array($parent_type_array[0], $a_page_id, $a_lang)
179 );
180 $q_ids = array();
181 while ($rec = $ilDB->fetchAssoc($res)) {
182 $q_ids[] = $rec["question_id"];
183 }
184
185 return $q_ids;
186 }
187
188 public static function _getPageForQuestionId(
189 int $a_q_id,
190 string $a_parent_type = ""
191 ): ?array {
192 global $DIC;
193
194 $ilDB = $DIC->database();
195
196 $set = $ilDB->query(
197 "SELECT * FROM page_question " .
198 " WHERE question_id = " . $ilDB->quote($a_q_id, "integer")
199 );
200 while ($rec = $ilDB->fetchAssoc($set)) {
201 if ($a_parent_type == "" || $rec["page_parent_type"] == $a_parent_type) {
202 return array("page_id" => $rec["page_id"], "parent_type" => $rec["page_parent_type"]);
203 }
204 }
205 return null;
206 }
207
209 string $a_output,
210 string $a_mode,
211 bool $a_abstract_only = false
212 ): string {
213 $lng = $this->lng;
214
215 $qhtml = "";
216
217 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
218 // #14154
219 $q_ids = $this->getPage()->getQuestionIds();
220 if (count($q_ids)) {
221 foreach ($q_ids as $q_id) {
222 $q_gui = assQuestionGUI::_getQuestionGUI("", $q_id);
223 // object check due to #16557
224 if (is_object($q_gui->object) && !$q_gui->object->isComplete()) {
225 $a_output = str_replace(
226 "{{{{{Question;il__qst_" . $q_id . "}}}}}",
227 "<i>" . $lng->txt("cont_empty_question") . "</i>",
228 $a_output
229 );
230 }
231 }
232
233 // this exports the questions which is needed below
234 $qhtml = $this->getQuestionJsOfPage($a_mode == "edit", $a_mode);
235
236 $a_output = "<script>" . ilQuestionExporter::questionsJS($q_ids) . "</script>" . $a_output;
237 if (!self::$initial_done) {
238 $a_output = "<script>var ScormApi=null; var questions = new Array();</script>" . $a_output;
239 self::$initial_done = true;
240 }
241 }
242 } else {
243 // set by T&A components
244 $qhtml = $this->getPage()->getPageConfig()->getQuestionHTML();
245
246 // address #19788
247 if (!is_array($qhtml) || count($qhtml) == 0) {
248 // #14154
249 $q_ids = $this->getPage()->getQuestionIds();
250 if (count($q_ids)) {
251 foreach ($q_ids as $k) {
252 $a_output = str_replace("{{{{{Question;il__qst_$k" . "}}}}}", " " . $lng->txt("copg_questions_not_supported_here"), $a_output);
253 }
254 }
255 }
256 }
257
258 if (is_array($qhtml)) {
259 foreach ($qhtml as $k => $h) {
260 $a_output = str_replace("{{{{{Question;il__qst_$k" . "}}}}}", " " . $h, $a_output);
261 }
262 }
263
264 return $a_output;
265 }
266
270 public static function resetInitialState(): void
271 {
272 self::$initial_done = false;
273 }
274
275 public function getJavascriptFiles(string $a_mode): array
276 {
277 $js_files = array();
278
279 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
280 $js_files[] = "./Modules/Scorm2004/scripts/questions/pure.js";
281 $js_files[] = "./Modules/Scorm2004/scripts/questions/question_handling.js";
282 $js_files[] = 'Modules/TestQuestionPool/js/ilAssMultipleChoice.js';
283 $js_files[] = "Modules/TestQuestionPool/js/ilMatchingQuestion.js";
284
285 foreach ($this->getPage()->getQuestionIds() as $qId) {
286 $qstGui = assQuestionGUI::_getQuestionGUI('', $qId);
287 $js_files = array_merge($js_files, $qstGui->getPresentationJavascripts());
288 }
289 }
290
291 if (!$this->getPage()->getPageConfig()->getEnableSelfAssessmentScorm() && $a_mode != ilPageObjectGUI::PREVIEW
292 && $a_mode != "offline") {
293 $js_files[] = "./Services/COPage/js/ilCOPageQuestionHandler.js";
294 }
295
296 return $js_files;
297 }
298
299 public function getCssFiles(string $a_mode): array
300 {
301 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
302 return array("./Modules/Scorm2004/templates/default/question_handling.css",
303 "Modules/TestQuestionPool/templates/default/test_javascript.css");
304 }
305 return array();
306 }
307
308 public function getOnloadCode(string $a_mode): array
309 {
310 $ilCtrl = $this->ctrl;
311 $ilUser = $this->user;
312
313 $code = array();
314
315 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
316 if (!$this->getPage()->getPageConfig()->getEnableSelfAssessmentScorm() && $a_mode != ilPageObjectGUI::PREVIEW
317 && $a_mode != "offline" && $a_mode !== "edit") {
318 $ilCtrl->setParameterByClass(strtolower(get_class($this->getPage())) . "gui", "page_id", $this->getPage()->getId());
319 $url = $ilCtrl->getLinkTargetByClass(strtolower(get_class($this->getPage())) . "gui", "processAnswer", "", true, false);
320 $code[] = "ilCOPageQuestionHandler.initCallback('" . $url . "');";
321 }
322
323 if ($this->getPage()->getPageConfig()->getDisableDefaultQuestionFeedback()) {
324 $code[] = "ilias.questions.default_feedback = false;";
325 }
326
327 $code[] = self::getJSTextInitCode($this->getPage()->getPageConfig()->getLocalizationLanguage()) . ' il.COPagePres.updateQuestionOverviews();';
328 }
329
330 $q_ids = $this->getPage()->getQuestionIds();
331
332 // call renderers
333 foreach ($q_ids as $q_id) {
334 $code[] = "renderILQuestion$q_id();";
335 }
336
337 // init answer status
338 $get_stored_tries = $this->getPage()->getPageConfig()->getUseStoredQuestionTries();
339 if ($get_stored_tries) {
340 if (count($q_ids) > 0) {
341 foreach ($q_ids as $q_id) {
343 $code[] = "ilias.questions.initAnswer(" . $q_id . ", " . (int) ($as["try"] ?? 0) . ", " . ($as["passed"] ? "true" : "null") . ");";
344 }
345 }
346 }
347 return $code;
348 }
349
353 public static function getJSTextInitCode(string $a_lang): string
354 {
355 global $DIC;
356
357 $lng = $DIC->language();
358 $ilUser = $DIC->user();
359
360 if ($a_lang == "") {
361 $a_lang = $ilUser->getLanguage();
362 }
363
364 return
365 '
366 ilias.questions.txt.wrong_answers = "' . $lng->txtlng("content", "cont_wrong_answers", $a_lang) . '";
367 ilias.questions.txt.wrong_answers_single = "' . $lng->txtlng("content", "cont_wrong_answers_single", $a_lang) . '";
368 ilias.questions.txt.tries_remaining = "' . $lng->txtlng("content", "cont_tries_remaining", $a_lang) . '";
369 ilias.questions.txt.please_try_again = "' . $lng->txtlng("content", "cont_please_try_again", $a_lang) . '";
370 ilias.questions.txt.all_answers_correct = "' . $lng->txtlng("content", "cont_all_answers_correct", $a_lang) . '";
371 ilias.questions.txt.enough_answers_correct = "' . $lng->txtlng("content", "cont_enough_answers_correct", $a_lang) . '";
372 ilias.questions.txt.nr_of_tries_exceeded = "' . $lng->txtlng("content", "cont_nr_of_tries_exceeded", $a_lang) . '";
373 ilias.questions.txt.correct_answers_separator = "' . $lng->txtlng("assessment", "or", $a_lang) . '";
374 ilias.questions.txt.correct_answers_shown = "' . $lng->txtlng("content", "cont_correct_answers_shown", $a_lang) . '";
375 ilias.questions.txt.correct_answers_also = "' . $lng->txtlng("content", "cont_correct_answers_also", $a_lang) . '";
376 ilias.questions.txt.correct_answer_also = "' . $lng->txtlng("content", "cont_correct_answer_also", $a_lang) . '";
377 ilias.questions.txt.ov_all_correct = "' . $lng->txtlng("content", "cont_ov_all_correct", $a_lang) . '";
378 ilias.questions.txt.ov_some_correct = "' . $lng->txtlng("content", "cont_ov_some_correct", $a_lang) . '";
379 ilias.questions.txt.ov_wrong_answered = "' . $lng->txtlng("content", "cont_ov_wrong_answered", $a_lang) . '";
380 ilias.questions.txt.please_select = "' . $lng->txtlng("content", "cont_please_select", $a_lang) . '";
381 ilias.questions.txt.ov_preview = "' . $lng->txtlng("content", "cont_ov_preview", $a_lang) . '";
382 ilias.questions.txt.submit_answers = "' . $lng->txtlng("content", "cont_submit_answers", $a_lang) . '";
383 ilias.questions.refresh_lang();
384 ';
385 }
386
387 public function getQuestionJsOfPage(
388 bool $a_no_interaction,
389 string $a_mode
390 ): array {
391 $q_ids = $this->getPage()->getQuestionIds();
392 $js = array();
393 if (count($q_ids) > 0) {
394 foreach ($q_ids as $q_id) {
395 $q_exporter = new ilQuestionExporter($a_no_interaction);
396 $image_path = "";
397 if ($a_mode == "offline") {
398 if ($this->getPage()->getParentType() == "sahs") {
399 $image_path = "./objects/";
400 }
401 if ($this->getPage()->getParentType() == "lm") {
402 $image_path = "./assessment/0/" . $q_id . "/images/";
403 }
404 }
405 $js[$q_id] = $q_exporter->exportQuestion($q_id, $image_path, $a_mode);
406 }
407 }
408 return $js;
409 }
410}
const IL_INSERT_AFTER
static _getQuestionGUI(string $question_type='', int $question_id=-1)
Creates a question gui representation and returns the alias to the question gui.
Abstract basic class which is to be extended by the concrete assessment question type classes.
static instantiateQuestion(int $question_id)
Class ilCtrl provides processing control methods.
language handling
User class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getPageForQuestionId(int $a_q_id, string $a_parent_type="")
modifyPageContentPostXsl(string $a_output, string $a_mode, bool $a_abstract_only=false)
Modify page content after xsl.
getQuestionJsOfPage(bool $a_no_interaction, string $a_mode)
init()
Init page content component.
static afterPageUpdate(ilPageObject $a_page, DOMDocument $a_domdoc, string $a_xml, bool $a_creation)
After page has been updated (or created)
getJavascriptFiles(string $a_mode)
static beforePageDelete(ilPageObject $a_page)
Before page is being deleted.
static getJSTextInitCode(string $a_lang)
Get js txt init code.
static resetInitialState()
Reset initial state (for exports)
static getLangVars()
Get lang vars needed for editing.
setNode(php4DOMElement $a_node)
Set xml node of page content.
setQuestionReference(string $a_questionreference)
copyPoolQuestionIntoPage(string $a_q_id, string $a_hier_id)
Copy question from pool into page.
static _getQuestionIdsForPage(string $a_parent_type, int $a_page_id, string $a_lang="-")
php4DOMElement $q_node
static bool $initial_done
getOnloadCode(string $a_mode)
create(ilPageObject $a_pg_obj, string $a_hier_id, string $a_pc_id="")
getCssFiles(string $a_mode)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
createPageContentNode(bool $a_set_this_node=true)
Create page content node (always use this method first when adding a new element)
setType(string $a_type)
Set Type.
Class ilPageObject Handles PageObjects of ILIAS Learning Modules (see ILIAS DTD)
insertContent(ilPageContent $a_cont_obj, string $a_pos, int $a_mode=IL_INSERT_AFTER, string $a_pcid="", bool $remove_placeholder=true)
insert a content node before/after a sibling or as first child of a parent
static getAnswerStatus( $a_q_id, int $a_user_id=0)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static questionsJS(array $a_qids=null)
global $DIC
Definition: feed.php:28
$ilUser
Definition: imgupload.php:34
$res
Definition: ltiservices.php:69
$url
$lng