ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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;
29 protected static bool $initial_done = false;
30
34 public function init(): void
35 {
36 global $DIC;
37
38 $this->lng = $DIC->language();
39 $this->ctrl = $DIC->ctrl();
40 $this->user = $DIC->user();
41 $this->setType("pcqst");
42 }
43
44 public function setQuestionReference(string $a_questionreference): void
45 {
46 if (is_object($this->getChildNode())) {
47 $this->getChildNode()->setAttribute("QRef", $a_questionreference);
48 }
49 }
50
51 public function getQuestionReference(): ?string
52 {
53 if (is_object($this->getChildNode())) {
54 return $this->getChildNode()->getAttribute("QRef");
55 }
56 return null;
57 }
58
59 public function create(
60 ilPageObject $a_pg_obj,
61 string $a_hier_id,
62 string $a_pc_id = ""
63 ): void {
65 $a_hier_id,
66 $a_pc_id,
67 "Question",
68 ["QRef" => ""]
69 );
70 }
71
75 public function copyPoolQuestionIntoPage(
76 string $a_q_id,
77 string $a_hier_id
78 ): void {
79 $question = assQuestion::instantiateQuestion($a_q_id);
80 $duplicate_id = $question->copyObject(0, $question->getTitle());
81 $duplicate = assQuestion::instantiateQuestion($duplicate_id);
82 $duplicate->setObjId(0);
83
85
86 $this->getChildNode()->setAttribute("QRef", "il__qst_" . $duplicate_id);
87 }
88
89 public static function getLangVars(): array
90 {
91 return array("ed_insert_pcqst", "empty_question", "pc_qst");
92 }
93
97 public static function afterPageUpdate(
98 ilPageObject $a_page,
99 DOMDocument $a_domdoc,
100 string $a_xml,
101 bool $a_creation
102 ): void {
103 global $DIC;
104
105 $ilDB = $DIC->database();
106
107 $ilDB->manipulateF(
108 "DELETE FROM page_question WHERE page_parent_type = %s " .
109 " AND page_id = %s AND page_lang = %s",
110 array("text", "integer", "text"),
111 array($a_page->getParentType(), $a_page->getId(), $a_page->getLanguage())
112 );
113
114 $xpath = new DOMXPath($a_domdoc);
115 $nodes = $xpath->query('//Question');
116 $q_ids = array();
117 foreach ($nodes as $node) {
118 $q_ref = $node->getAttribute("QRef");
119
120 $inst_id = ilInternalLink::_extractInstOfTarget($q_ref);
121 if (!($inst_id > 0)) {
123 if ($q_id > 0) {
124 $q_ids[$q_id] = $q_id;
125 }
126 }
127 }
128 foreach ($q_ids as $qid) {
129 $ilDB->replace(
130 "page_question",
131 [
132 "page_parent_type" => ["text", $a_page->getParentType()],
133 "page_id" => ["integer", $a_page->getId()],
134 "page_lang" => ["text", $a_page->getLanguage()],
135 "question_id" => ["integer", $qid]
136 ],
137 []
138 );
139 }
140 }
141
142 public static function beforePageDelete(
143 ilPageObject $a_page
144 ): void {
145 global $DIC;
146
147 $ilDB = $DIC->database();
148
149 $ilDB->manipulateF(
150 "DELETE FROM page_question WHERE page_parent_type = %s " .
151 " AND page_id = %s AND page_lang = %s",
152 array("text", "integer", "text"),
153 array($a_page->getParentType(), $a_page->getId(), $a_page->getLanguage())
154 );
155 }
156
157 public static function _getQuestionIdsForPage(
158 string $a_parent_type,
159 int $a_page_id,
160 string $a_lang = "-"
161 ): array {
162 global $DIC;
163
164 $ilDB = $DIC->database();
165
166 $parent_type_array = explode(':', $a_parent_type);
167
168 $res = $ilDB->queryF(
169 "SELECT * FROM page_question WHERE page_parent_type = %s " .
170 " AND page_id = %s AND page_lang = %s",
171 array("text", "integer", "text"),
172 array($parent_type_array[0], $a_page_id, $a_lang)
173 );
174 $q_ids = array();
175 while ($rec = $ilDB->fetchAssoc($res)) {
176 $q_ids[] = $rec["question_id"];
177 }
178
179 return $q_ids;
180 }
181
182 public static function _getPageForQuestionId(
183 int $a_q_id,
184 string $a_parent_type = ""
185 ): ?array {
186 global $DIC;
187
188 $ilDB = $DIC->database();
189
190 $set = $ilDB->query(
191 "SELECT * FROM page_question " .
192 " WHERE question_id = " . $ilDB->quote($a_q_id, "integer")
193 );
194 while ($rec = $ilDB->fetchAssoc($set)) {
195 if ($a_parent_type == "" || $rec["page_parent_type"] == $a_parent_type) {
196 return array("page_id" => $rec["page_id"], "parent_type" => $rec["page_parent_type"]);
197 }
198 }
199 return null;
200 }
201
203 string $a_output,
204 string $a_mode,
205 bool $a_abstract_only = false
206 ): string {
207 $lng = $this->lng;
208
209 $qhtml = "";
210
211 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
212 // #14154
213 $q_ids = $this->getQuestionIds();
214 if (count($q_ids)) {
215 foreach ($q_ids as $q_id) {
216 $q_gui = assQuestionGUI::_getQuestionGUI("", $q_id);
217 // object check due to #16557
218 if (is_object($q_gui->getObject()) && !$q_gui->getObject()->isComplete()) {
219 $a_output = str_replace(
220 "{{{{{Question;il__qst_" . $q_id . "}}}}}",
221 "<i>" . $lng->txt("cont_empty_question") . "</i>",
222 $a_output
223 );
224 }
225 }
226
227 // this exports the questions which is needed below
228 $qhtml = $this->getQuestionJsOfPage($a_mode == "edit", $a_mode);
229
230 $a_output = "<script>" . ilQuestionExporter::questionsJS($q_ids) . "</script>" . $a_output;
231 if (!self::$initial_done) {
232 $a_output = "<script>var ScormApi=null; var questions = new Array();</script>" . $a_output;
233 self::$initial_done = true;
234 }
235 }
236 } else {
237 // set by T&A components
238 $qhtml = $this->getPage()->getPageConfig()->getQuestionHTML();
239
240 // address #19788
241 if (!is_array($qhtml) || count($qhtml) == 0) {
242 // #14154
243 $q_ids = $this->getQuestionIds();
244 if (count($q_ids)) {
245 foreach ($q_ids as $k) {
246 $a_output = str_replace("{{{{{Question;il__qst_$k" . "}}}}}", " " . $lng->txt("copg_questions_not_supported_here"), $a_output);
247 }
248 }
249 }
250 }
251
252 if (is_array($qhtml)) {
253 foreach ($qhtml as $k => $h) {
254 $a_output = str_replace("{{{{{Question;il__qst_$k" . "}}}}}", " " . $h, $a_output);
255 }
256 }
257
258 return $a_output;
259 }
260
264 public static function resetInitialState(): void
265 {
266 self::$initial_done = false;
267 }
268
269 public function getJavascriptFiles(string $a_mode): array
270 {
271 $js_files = array();
272
273 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
274 $js_files[] = 'assets/js/pure_rendering.js';
275 $js_files[] = 'assets/js/question_handling.js';
276 $js_files[] = 'assets/js/matchinginput.js';
277 $js_files[] = 'assets/js/orderinghorizontal.js';
278 $js_files[] = 'assets/js/orderingvertical.js';
279 $js_files[] = 'assets/js/matching.js';
280
281 foreach ($this->getQuestionIds() as $qId) {
282 $qstGui = assQuestionGUI::_getQuestionGUI('', $qId);
283 $js_files = array_merge($js_files, $qstGui->getPresentationJavascripts());
284 }
285 }
286
287 if (!$this->getPage()->getPageConfig()->getEnableSelfAssessmentScorm() && $a_mode != ilPageObjectGUI::PREVIEW
288 && $a_mode != "offline") {
289 $js_files[] = "./components/ILIAS/COPage/js/ilCOPageQuestionHandler.js";
290 }
291
292 return $js_files;
293 }
294
295 public function getCssFiles(string $a_mode): array
296 {
297 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
298 return array("./components/ILIAS/TestQuestionPool/resources/js/dist/question_handling.css",
299 "components/ILIAS/TestQuestionPool/templates/default/test_javascript.css");
300 }
301 return array();
302 }
303
304 public function getOnloadCode(string $a_mode): array
305 {
306 $ilCtrl = $this->ctrl;
307 $ilUser = $this->user;
308
309 $code = array();
310
311 if ($this->getPage()->getPageConfig()->getEnableSelfAssessment()) {
312 if (!$this->getPage()->getPageConfig()->getEnableSelfAssessmentScorm() && $a_mode != ilPageObjectGUI::PREVIEW
313 && $a_mode != "offline" && $a_mode !== "edit") {
314 $ilCtrl->setParameterByClass(strtolower(get_class($this->getPage())) . "gui", "page_id", $this->getPage()->getId());
315 $url = $ilCtrl->getLinkTargetByClass(strtolower(get_class($this->getPage())) . "gui", "processAnswer", "", true, false);
316 $code[] = "ilCOPageQuestionHandler.initCallback('" . $url . "');";
317 }
318
319 if ($this->getPage()->getPageConfig()->getDisableDefaultQuestionFeedback()) {
320 $code[] = "ilias.questions.default_feedback = false;";
321 }
322
323 $code[] = self::getJSTextInitCode($this->getPage()->getPageConfig()->getLocalizationLanguage()) . ' il.COPagePres.updateQuestionOverviews();';
324 }
325
326 $q_ids = $this->getQuestionIds();
327
328 // call renderers
329 foreach ($q_ids as $q_id) {
330 $code[] = "if (typeof renderILQuestion$q_id === 'function') {renderILQuestion$q_id();}";
331 }
332
333 // init answer status
334 $get_stored_tries = $this->getPage()->getPageConfig()->getUseStoredQuestionTries();
335 if ($get_stored_tries) {
336 if (count($q_ids) > 0) {
337 foreach ($q_ids as $q_id) {
338 $as = ilPageQuestionProcessor::getAnswerStatus($q_id, $ilUser->getId());
339 $code[] = "ilias.questions.initAnswer(" . $q_id . ", " . (int) ($as["try"] ?? 0) . ", " . ($as["passed"] ? "true" : "null") . ");";
340 }
341 }
342 }
343 return $code;
344 }
345
349 public static function getJSTextInitCode(string $a_lang): string
350 {
351 global $DIC;
352
353 $lng = $DIC->language();
354 $ilUser = $DIC->user();
355
356 if ($a_lang == "") {
357 $a_lang = $ilUser->getLanguage();
358 }
359
360 return
361 '
362 ilias.questions.txt.wrong_answers = "' . $lng->txtlng("content", "cont_wrong_answers", $a_lang) . '";
363 ilias.questions.txt.wrong_answers_single = "' . $lng->txtlng("content", "cont_wrong_answers_single", $a_lang) . '";
364 ilias.questions.txt.tries_remaining = "' . $lng->txtlng("content", "cont_tries_remaining", $a_lang) . '";
365 ilias.questions.txt.please_try_again = "' . $lng->txtlng("content", "cont_please_try_again", $a_lang) . '";
366 ilias.questions.txt.all_answers_correct = "' . $lng->txtlng("content", "cont_all_answers_correct", $a_lang) . '";
367 ilias.questions.txt.enough_answers_correct = "' . $lng->txtlng("content", "cont_enough_answers_correct", $a_lang) . '";
368 ilias.questions.txt.nr_of_tries_exceeded = "' . $lng->txtlng("content", "cont_nr_of_tries_exceeded", $a_lang) . '";
369 ilias.questions.txt.correct_answers_separator = "' . $lng->txtlng("assessment", "or", $a_lang) . '";
370 ilias.questions.txt.correct_answers_shown = "' . $lng->txtlng("content", "cont_correct_answers_shown", $a_lang) . '";
371 ilias.questions.txt.correct_answers_also = "' . $lng->txtlng("content", "cont_correct_answers_also", $a_lang) . '";
372 ilias.questions.txt.correct_answer_also = "' . $lng->txtlng("content", "cont_correct_answer_also", $a_lang) . '";
373 ilias.questions.txt.ov_all_correct = "' . $lng->txtlng("content", "cont_ov_all_correct", $a_lang) . '";
374 ilias.questions.txt.ov_some_correct = "' . $lng->txtlng("content", "cont_ov_some_correct", $a_lang) . '";
375 ilias.questions.txt.ov_wrong_answered = "' . $lng->txtlng("content", "cont_ov_wrong_answered", $a_lang) . '";
376 ilias.questions.txt.please_select = "' . $lng->txtlng("content", "cont_please_select", $a_lang) . '";
377 ilias.questions.txt.ov_preview = "' . $lng->txtlng("content", "cont_ov_preview", $a_lang) . '";
378 ilias.questions.txt.submit_answers = "' . $lng->txtlng("content", "cont_submit_answers", $a_lang) . '";
379 ilias.questions.refresh_lang();
380 ';
381 }
382
383 public function getQuestionJsOfPage(
384 bool $a_no_interaction,
385 string $a_mode
386 ): array {
387 $q_ids = $this->getQuestionIds();
388 $js = array();
389 if (count($q_ids) > 0) {
390 foreach ($q_ids as $q_id) {
391 $q_exporter = new ilQuestionExporter($a_no_interaction);
392 $image_path = "";
393 if ($a_mode == "offline") {
394 if ($this->getPage()->getParentType() == "sahs") {
395 $image_path = "./objects/";
396 }
397 if ($this->getPage()->getParentType() == "lm") {
398 $image_path = "./assessment/0/" . $q_id . "/images/";
399 }
400 }
401 $js[$q_id] = $q_exporter->exportQuestion($q_id, $image_path, $a_mode);
402 }
403 }
404 return $js;
405 }
406
407 protected function getQuestionIds(): array
408 {
409 $dom = $this->getPage()->getDomDoc();
410 $q_ids = [];
411 $nodes = $this->dom_util->path($dom, "//Question");
412 foreach ($nodes as $node) {
413 $qref = $node->getAttribute("QRef");
414 $inst_id = ilInternalLink::_extractInstOfTarget($qref);
416
417 if (!($inst_id > 0)) {
418 if ($obj_id > 0) {
419 $q_ids[] = $obj_id;
420 }
421 }
422 }
423 return $q_ids;
424 }
425
426 public static function handleCopiedContent(
427 DOMDocument $a_domdoc,
428 bool $a_self_ass = true,
429 bool $a_clone_mobs = false,
430 int $new_parent_id = 0,
431 int $obj_copy_id = 0
432 ): void {
433 global $DIC;
434
435 $dom_util = $DIC->copage()->internal()->domain()->domUtil();
436
437 // handle question elements
438 if ($a_self_ass) {
439 // copy questions
440 $path = "//Question";
441 $nodes = $dom_util->path($a_domdoc, $path);
442 foreach ($nodes as $node) {
443 $qref = $node->getAttribute("QRef");
444
445 $inst_id = ilInternalLink::_extractInstOfTarget($qref);
447
448 if (!($inst_id > 0)) {
449 if ($q_id > 0) {
450 $question = null;
451 try {
452 $question = assQuestion::instantiateQuestion($q_id);
453 } catch (Exception $e) {
454 }
455 // check due to #16557
456 if (is_object($question) && $question->isComplete()) {
457 // check if page for question exists
458 // due to a bug in early 4.2.x version this is possible
459 if (!ilPageObject::_exists("qpl", $q_id)) {
460 $question->createPageObject();
461 }
462
463 // now copy this question and change reference to
464 // new question id
465 $duplicate_id = $question->duplicate(false);
466 $node->setAttribute("QRef", "il__qst_" . $duplicate_id);
467 }
468 }
469 }
470 }
471 } else {
472 // remove question
473 $path = "//Question";
474 $nodes = $dom_util->path($a_domdoc, $path);
475 foreach ($nodes as $node) {
476 $parent = $node->parentNode;
477 $parent->parentNode->removeChild($parent);
478 }
479 }
480 }
481}
static _getQuestionGUI(string $question_type='', int $question_id=-1)
Creates a question gui representation and returns the alias to the question gui.
copyObject(int $target_parent_id, string $title='')
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 handleCopiedContent(DOMDocument $a_domdoc, bool $a_self_ass=true, bool $a_clone_mobs=false, int $new_parent_id=0, int $obj_copy_id=0)
Handle copied content.
static resetInitialState()
Reset initial state (for exports)
static getLangVars()
Get lang vars needed for editing.
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="-")
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)
Content object of ilPageObject (see ILIAS DTD).
createInitialChildNode(string $hier_id, string $pc_id, string $child, array $child_attributes=[])
setType(string $a_type)
Set Type.
Class ilPageObject Handles PageObjects of ILIAS Learning Modules (see ILIAS DTD)
static _exists(string $a_parent_type, int $a_id, string $a_lang="", bool $a_no_cache=false)
Checks whether page exists.
static getAnswerStatus( $a_q_id, int $a_user_id=0)
Scorm 2004 Question Exporter.
static questionsJS(?array $a_qids=null)
$path
Definition: ltiservices.php:30
$res
Definition: ltiservices.php:69
global $lng
Definition: privfeed.php:31
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:68