ILIAS  release_8 Revision v8.24
class.ilTestOutputGUI.php
Go to the documentation of this file.
1<?php
2
34{
39
43 public function executeCommand()
44 {
45 global $DIC;
46 $ilDB = $DIC['ilDB'];
47 $component_repository = $DIC['component.repository'];
48 $lng = $DIC['lng'];
49 $refinery = $DIC['refinery'];
50 $ilTabs = $DIC['ilTabs'];
51
52 $this->checkReadAccess();
53
54 $ilTabs->clearTargets();
55
56 $cmd = $this->ctrl->getCmd();
57 $next_class = $this->ctrl->getNextClass($this);
58
59 $this->ctrl->saveParameter($this, "sequence");
60 $this->ctrl->saveParameter($this, "pmode");
61 $this->ctrl->saveParameter($this, "active_id");
62
64
65 $testSessionFactory = new ilTestSessionFactory($this->object);
66 $this->testSession = $testSessionFactory->getSession($this->testrequest->raw('active_id'));
67
68 $this->ensureExistingTestSession($this->testSession);
69 $this->checkTestSessionUser($this->testSession);
70
71 $this->initProcessLocker($this->testSession->getActiveId());
72
73 $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $refinery, $component_repository, $this->object);
74 $this->testSequence = $testSequenceFactory->getSequenceByTestSession($this->testSession);
75 $this->testSequence->loadFromDb();
76 $this->testSequence->loadQuestions();
77
78 $DIC->globalScreen()->tool()->context()->current()->addAdditionalData(
80 $this->object->getKioskMode()
81 );
82 $title = $this->object->getTitle();
83 if (($sequence_index = $this->getSequenceElementParameter()) !== null) {
84 $title .= ' - ' . $this->lng->txt('question') . $sequence_index;
85 }
86 $DIC->globalScreen()->tool()->context()->current()->addAdditionalData(
88 $title
89 );
90 $instance_name = $DIC['ilSetting']->get('short_inst_name');
91 if (trim($instance_name) === '') {
92 $instance_name = 'ILIAS';
93 }
94 $DIC->globalScreen()->tool()->context()->current()->addAdditionalData(
96 $instance_name
97 );
98
99 $this->questionRelatedObjectivesList = new ilTestQuestionRelatedObjectivesList();
100
103
105
106 $cmd = $this->getCommand($cmd);
107
108 switch ($next_class) {
109 case 'ilassquestionpagegui':
110 $this->checkTestExecutable();
111
112 $questionId = $this->testSequence->getQuestionForSequence($this->getCurrentSequenceElement());
113
114 $page_gui = new ilAssQuestionPageGUI($questionId);
115 $ret = $this->ctrl->forwardCommand($page_gui);
116 break;
117
118 case 'iltestsubmissionreviewgui':
119 $this->checkTestExecutable();
120
121 $gui = new ilTestSubmissionReviewGUI($this, $this->object, $this->testSession);
122 $gui->setObjectiveOrientedContainer($this->getObjectiveOrientedContainer());
123 $ret = $this->ctrl->forwardCommand($gui);
124 break;
125
126 case 'ilassquestionhintrequestgui':
127 $this->checkTestExecutable();
128
129 $questionGUI = $this->object->createQuestionGUI(
130 "",
131 $this->testSequence->getQuestionForSequence($this->getCurrentSequenceElement())
132 );
133
134 $questionHintTracking = new ilAssQuestionHintTracking(
135 $questionGUI->object->getId(),
136 $this->testSession->getActiveId(),
137 $this->testSession->getPass()
138 );
139
140 $gui = new ilAssQuestionHintRequestGUI($this, ilTestPlayerCommands::SHOW_QUESTION, $questionGUI, $questionHintTracking);
141
142 // fau: testNav - save the 'answer changed' status for viewing hint requests
144 // fau.
145 $ret = $this->ctrl->forwardCommand($gui);
146
147 break;
148
149 case 'iltestsignaturegui':
150 $this->checkTestExecutable();
151
152 $gui = new ilTestSignatureGUI($this);
153 $ret = $this->ctrl->forwardCommand($gui);
154 break;
155
156 case 'iltestpasswordprotectiongui':
157 $this->checkTestExecutable();
158
159 $gui = new ilTestPasswordProtectionGUI($this->ctrl, $this->tpl, $this->lng, $this, $this->passwordChecker);
160 $ret = $this->ctrl->forwardCommand($gui);
161 break;
162
163 default:
165 $this->checkTestExecutable();
166 }
167
168 if (strtolower($cmd) === 'showquestion') {
169 $testPassesSelector = new ilTestPassesSelector($this->db, $this->object);
170 $testPassesSelector->setActiveId($this->testSession->getActiveId());
171 $testPassesSelector->setLastFinishedPass($this->testSession->getLastFinishedPass());
172
173 if (!$testPassesSelector->openPassExists()) {
174 $this->tpl->setOnScreenMessage('info', $this->lng->txt('tst_pass_finished'), true);
175 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
176 }
177 }
178
179 $cmd .= 'Cmd';
180 $ret = $this->$cmd();
181 break;
182 }
183 return $ret;
184 }
185
186 protected function startTestCmd()
187 {
188 global $DIC;
189 $ilUser = $DIC['ilUser'];
190
191 ilSession::set('tst_pass_finish', 0);
192
193 // ensure existing test session
194 $this->testSession->setUserId($ilUser->getId());
195 $access_code = ilSession::get('tst_access_code');
196 if ($access_code != null && isset($access_code[$this->object->getTestId()])) {
197 $this->testSession->setAnonymousId((int) $access_code[$this->object->getTestId()]);
198 }
199 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
200 $this->testSession->setObjectiveOrientedContainerId($this->getObjectiveOrientedContainer()->getObjId());
201 }
202 $this->testSession->saveToDb();
203
204 $active_id = $this->testSession->getActiveId();
205 $this->ctrl->setParameter($this, "active_id", $active_id);
206
207 $shuffle = $this->object->getShuffleQuestions();
208 if ($this->object->isRandomTest()) {
210
211 $this->object->loadQuestions();
212 $shuffle = false; // shuffle is already done during the creation of the random questions
213 }
214
215 assQuestion::_updateTestPassResults(
216 $active_id,
217 $this->testSession->getPass(),
218 $this->object->areObligationsEnabled(),
219 null,
220 $this->object->getId()
221 );
222
223 // ensure existing test sequence
224 if (!$this->testSequence->hasSequence()) {
225 $this->testSequence->createNewSequence($this->object->getQuestionCount(), $shuffle);
226 $this->testSequence->saveToDb();
227 }
228
229 $this->testSequence->loadFromDb();
230 $this->testSequence->loadQuestions();
231
232 if ($this->testSession->isObjectiveOriented()) {
233 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($this->testSession);
234
235 $objectivesAdapter->notifyTestStart($this->testSession, $this->object->getId());
236 $objectivesAdapter->prepareTestPass($this->testSession, $this->testSequence);
237
238 $objectivesAdapter->buildQuestionRelatedObjectiveList(
239 $this->testSequence,
240 $this->questionRelatedObjectivesList
241 );
242
243 if ($this->testSequence->hasOptionalQuestions()) {
245
246 $this->testSequence->reorderOptionalQuestionsToSequenceEnd();
247 $this->testSequence->saveToDb();
248 }
249 }
250
251 $active_time_id = $this->object->startWorkingTime(
252 $this->testSession->getActiveId(),
253 $this->testSession->getPass()
254 );
255 ilSession::set("active_time_id", $active_time_id);
256
258
259 $sequenceElement = $this->testSequence->getFirstSequence();
260
261 $this->ctrl->setParameter($this, 'sequence', $sequenceElement);
262 $this->ctrl->setParameter($this, 'pmode', '');
263
264 if ($this->object->getListOfQuestionsStart()) {
265 $this->ctrl->redirect($this, ilTestPlayerCommands::QUESTION_SUMMARY);
266 }
267
268 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
269 }
270
272 {
273 global $DIC;
274 $ilUser = $DIC['ilUser'];
275
276 ilLPStatusWrapper::_updateStatus($this->object->getId(), $ilUser->getId());
277 }
278
279 private function isValidSequenceElement($sequenceElement): bool
280 {
281 if ($sequenceElement === false) {
282 return false;
283 }
284
285 if ($sequenceElement < 1) {
286 return false;
287 }
288
289 if (!$this->testSequence->getPositionOfSequence($sequenceElement)) {
290 return false;
291 }
292
293 return true;
294 }
295
296 protected function showQuestionCmd()
297 {
298 ilSession::set('tst_pass_finish', 0);
299
301 "active_time_id",
302 $this->object->startWorkingTime(
303 $this->testSession->getActiveId(),
304 $this->testSession->getPass()
305 )
306 );
307
308 global $DIC;
309 $help = $DIC->help();
310 $help->setScreenIdComponent("tst");
311 $help->setScreenId("assessment");
312 $help->setSubScreenId("question");
313
314 $sequenceElement = $this->getCurrentSequenceElement();
315
316 if (!$this->isValidSequenceElement($sequenceElement)) {
317 $sequenceElement = $this->testSequence->getFirstSequence();
318 }
319
320 $this->testSession->setLastSequence($sequenceElement);
321 $this->testSession->saveToDb();
322
323
324 $questionId = $this->testSequence->getQuestionForSequence($sequenceElement);
325
326 if (!(int) $questionId && $this->testSession->isObjectiveOriented()) {
328 }
329
330 if (!$this->testSequence->isQuestionPresented($questionId)) {
331 $this->testSequence->setQuestionPresented($questionId);
332 $this->testSequence->saveToDb();
333 }
334
335 $isQuestionWorkedThrough = assQuestion::_isWorkedThrough(
336 $this->testSession->getActiveId(),
337 $questionId,
338 $this->testSession->getPass()
339 );
340
341 // fau: testNav - always use edit mode, except for fixed answer
342 if ($this->isParticipantsAnswerFixed($questionId)) {
344 $instantResponse = true;
345 } else {
347 // #37025 don't show instant response if a request for it should fix the answer and answer is not yet fixed
348 if ($this->object->isInstantFeedbackAnswerFixationEnabled()) {
349 $instantResponse = false;
350 } else {
351 $instantResponse = $this->getInstantResponseParameter();
352 }
353 }
354 // fau.
355
356 $questionGui = $this->getQuestionGuiInstance($questionId);
357
358 if (!($questionGui instanceof assQuestionGUI)) {
359 $this->handleTearsAndAngerQuestionIsNull($questionId, $sequenceElement);
360 }
361
362 $questionGui->setSequenceNumber($this->testSequence->getPositionOfSequence($sequenceElement));
363 $questionGui->setQuestionCount($this->testSequence->getUserQuestionCount());
364
365 $headerBlockBuilder = new ilTestQuestionHeaderBlockBuilder($this->lng);
366 $headerBlockBuilder->setHeaderMode($this->object->getTitleOutput());
367 $headerBlockBuilder->setQuestionTitle($questionGui->object->getTitleForHTMLOutput());
368 $headerBlockBuilder->setQuestionPoints($questionGui->object->getPoints());
369 $headerBlockBuilder->setQuestionPosition($this->testSequence->getPositionOfSequence($sequenceElement));
370 $headerBlockBuilder->setQuestionCount($this->testSequence->getUserQuestionCount());
371 $headerBlockBuilder->setQuestionPostponed($this->testSequence->isPostponedQuestion($questionId));
372 $headerBlockBuilder->setQuestionObligatory(
373 $this->object->areObligationsEnabled() && ilObjTest::isQuestionObligatory($questionGui->object->getId())
374 );
375 if ($this->testSession->isObjectiveOriented()) {
376 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($this->testSession);
377 $objectivesAdapter->buildQuestionRelatedObjectiveList($this->testSequence, $this->questionRelatedObjectivesList);
378 $this->questionRelatedObjectivesList->loadObjectivesTitles();
379
380 $objectivesString = $this->questionRelatedObjectivesList->getQuestionRelatedObjectiveTitles($questionId);
381 $headerBlockBuilder->setQuestionRelatedObjectives($objectivesString);
382 }
383 $questionGui->setQuestionHeaderBlockBuilder($headerBlockBuilder);
384
385 $this->prepareTestPage($presentationMode, $sequenceElement, $questionId);
386
387 $navigationToolbarGUI = $this->getTestNavigationToolbarGUI();
388 $navigationToolbarGUI->setFinishTestButtonEnabled(true);
389
390 $isNextPrimary = $this->handlePrimaryButton($navigationToolbarGUI, $questionId);
391
392 $this->ctrl->setParameter($this, 'sequence', $sequenceElement);
393 $this->ctrl->setParameter($this, 'pmode', $presentationMode);
394 $formAction = $this->ctrl->getFormAction($this, ilTestPlayerCommands::SUBMIT_INTERMEDIATE_SOLUTION);
395
396 switch ($presentationMode) {
398
399 // fau: testNav - enable navigation toolbar in edit mode
400 $navigationToolbarGUI->setDisabledStateEnabled(false);
401 // fau.
402 $this->showQuestionEditable($questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse);
403
404 break;
405
407
408 if ($this->testSequence->isQuestionOptional($questionGui->object->getId())) {
410 }
411
412 $this->showQuestionViewable($questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse);
413
414 break;
415
416 default:
417 throw new ilTestException('no presentation mode given');
418 }
419
420 $navigationToolbarGUI->build();
421 $this->populateTestNavigationToolbar($navigationToolbarGUI);
422
423 // fau: testNav - enable the question navigation in edit mode
424 $this->populateQuestionNavigation($sequenceElement, false, $isNextPrimary);
425 // fau.
426
427 if ($instantResponse) {
428 // fau: testNav - always use authorized solution for instant feedback
430 $questionGui,
431 true
432 );
433 // fau.
434 }
435
436 // fau: testNav - add feedback modal
440 }
441 // fau.
442 }
443
444 protected function editSolutionCmd()
445 {
446 $this->ctrl->setParameter($this, 'pmode', ilTestPlayerAbstractGUI::PRESENTATION_MODE_EDIT);
447 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
448 }
449
450 protected function submitSolutionAndNextCmd()
451 {
452 if ($this->object->isForceInstantFeedbackEnabled()) {
453 $this->submitSolutionCmd();
454 return;
455 }
456
457 if ($this->saveQuestionSolution(true, false)) {
458 $questionId = $this->testSequence->getQuestionForSequence(
460 );
461
463
464 $nextSequenceElement = $this->testSequence->getNextSequence($this->getCurrentSequenceElement());
465
466 if (!$this->isValidSequenceElement($nextSequenceElement)) {
467 $nextSequenceElement = $this->testSequence->getFirstSequence();
468 }
469
470 $this->testSession->setLastSequence($nextSequenceElement);
471 $this->testSession->saveToDb();
472
473 $this->ctrl->setParameter($this, 'sequence', $nextSequenceElement);
474 $this->ctrl->setParameter($this, 'pmode', '');
475 }
476
477 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
478 }
479
480 protected function submitSolutionCmd()
481 {
482 if ($this->saveQuestionSolution(true, false)) {
483 $questionId = $this->testSequence->getQuestionForSequence(
485 );
486
488
489 if ($this->object->isForceInstantFeedbackEnabled()) {
490 $this->ctrl->setParameter($this, 'instresp', 1);
491
492 $this->testSequence->setQuestionChecked($questionId);
493 $this->testSequence->saveToDb();
494 }
495
496 if ($this->getNextCommandParameter()) {
497 if ($this->getNextSequenceParameter()) {
498 $this->ctrl->setParameter($this, 'sequence', $this->getNextSequenceParameter());
499 $this->ctrl->setParameter($this, 'pmode', '');
500 }
501
502 $this->ctrl->redirect($this, $this->getNextCommandParameter());
503 }
504
505 $this->ctrl->setParameter($this, 'pmode', ilTestPlayerAbstractGUI::PRESENTATION_MODE_VIEW);
506 } else {
507 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
508 }
509
510 // fau: testNav - remember to prevent the navigation confirmation
512 // fau.
513
514 // fau: testNav - handle navigation after saving
515 if ($this->getNavigationUrlParameter()) {
517 } else {
518 $this->ctrl->saveParameter($this, 'sequence');
519 }
520 // fau.
521 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
522 }
523
524 protected function discardSolutionCmd()
525 {
526 $currentSequenceElement = $this->getCurrentSequenceElement();
527
528 $currentQuestionOBJ = $this->getQuestionInstance(
529 $this->testSequence->getQuestionForSequence($currentSequenceElement)
530 );
531
532 $currentQuestionOBJ->resetUsersAnswer(
533 $this->testSession->getActiveId(),
534 $this->testSession->getPass()
535 );
536
537 $this->ctrl->saveParameter($this, 'sequence');
538
539 $this->ctrl->setParameter($this, 'pmode', ilTestPlayerAbstractGUI::PRESENTATION_MODE_VIEW);
540
541 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
542 }
543
544 protected function skipQuestionCmd()
545 {
546 $curSequenceElement = $this->getCurrentSequenceElement();
547 $nextSequenceElement = $this->testSequence->getNextSequence($curSequenceElement);
548
549 if (!$this->isValidSequenceElement($nextSequenceElement)) {
550 $nextSequenceElement = $this->testSequence->getFirstSequence();
551 }
552
553 if ($this->object->isPostponingEnabled()) {
554 $this->testSequence->postponeSequence($curSequenceElement);
555 $this->testSequence->saveToDb();
556 }
557
558 $this->ctrl->setParameter($this, 'sequence', $nextSequenceElement);
559 $this->ctrl->setParameter($this, 'pmode', '');
560
561 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
562 }
563
564 protected function handleQuestionPostponing($sequenceElement)
565 {
566 $questionId = $this->testSequence->getQuestionForSequence($sequenceElement);
567
568 $isQuestionWorkedThrough = assQuestion::_isWorkedThrough(
569 $this->testSession->getActiveId(),
570 $questionId,
571 $this->testSession->getPass()
572 );
573
574 if (!$isQuestionWorkedThrough) {
575 $this->testSequence->postponeQuestion($questionId);
576 $this->testSequence->saveToDb();
577 }
578 }
579
580 protected function handleCheckTestPassValid(): void
581 {
582 $testObj = new ilObjTest($this->ref_id, true);
583
584 $participants = $testObj->getActiveParticipantList();
585 $participant = $participants->getParticipantByActiveId($this->testrequest->getActiveId());
586 if (!$participant || !$participant->hasUnfinishedPasses()) {
587 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("tst_current_run_no_longer_valid"), true);
588 $this->backToInfoScreenCmd();
589 }
590 }
591
592 protected function nextQuestionCmd()
593 {
595 $lastSequenceElement = $this->getCurrentSequenceElement();
596 $nextSequenceElement = $this->testSequence->getNextSequence($lastSequenceElement);
597
598 if ($this->object->isPostponingEnabled()) {
599 $this->handleQuestionPostponing($lastSequenceElement);
600 }
601
602 if (!$this->isValidSequenceElement($nextSequenceElement)) {
603 $nextSequenceElement = $this->testSequence->getFirstSequence();
604 }
605
606 $this->ctrl->setParameter($this, 'sequence', $nextSequenceElement);
607 $this->ctrl->setParameter($this, 'pmode', '');
608
609 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
610 }
611
612 protected function previousQuestionCmd()
613 {
615
616 $sequenceElement = $this->testSequence->getPreviousSequence(
618 );
619
620 if (!$this->isValidSequenceElement($sequenceElement)) {
621 $sequenceElement = $this->testSequence->getLastSequence();
622 }
623
624 $this->ctrl->setParameter($this, 'sequence', $sequenceElement);
625 $this->ctrl->setParameter($this, 'pmode', '');
626
627 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
628 }
629
630 protected function isFirstQuestionInSequence($sequenceElement): bool
631 {
632 return $sequenceElement == $this->testSequence->getFirstSequence();
633 }
634
635 protected function isLastQuestionInSequence($sequenceElement): bool
636 {
637 return $sequenceElement == $this->testSequence->getLastSequence();
638 }
639
645 protected function canSaveResult(): bool
646 {
647 return !$this->object->endingTimeReached() && !$this->isMaxProcessingTimeReached() && !$this->isNrOfTriesReached();
648 }
649
653 protected function getCurrentQuestionId(): int
654 {
655 return $this->testSequence->getQuestionForSequence($this->testrequest->raw("sequence"));
656 }
657
661 public function saveQuestionSolution($authorized = true, $force = false): bool
662 {
663 $this->updateWorkingTime();
664 $this->saveResult = false;
665 if (!$force) {
666 $formtimestamp = $_POST["formtimestamp"] ?? '';
667 if (strlen($formtimestamp) == 0) {
668 $formtimestamp = $this->testrequest->raw("formtimestamp");
669 }
670 if (ilSession::get('formtimestamp') == null || $formtimestamp != ilSession::get("formtimestamp")) {
671 ilSession::set("formtimestamp", $formtimestamp);
672 } else {
673 return false;
674 }
675 }
676
677 /*
678 #21097 - exceed maximum passes
679 this is a battle of conditions; e.g. ilTestPlayerAbstractGUI::autosaveOnTimeLimitCmd forces saving of results.
680 However, if an admin has finished the pass in the meantime, a new pass should not be created.
681 */
682 if ($force && $this->isNrOfTriesReached()) {
683 $force = false;
684 }
685
686 // save question solution
687 if ($this->canSaveResult() || $force) {
688 // but only if the ending time is not reached
689 $q_id = $this->testSequence->getQuestionForSequence($this->testrequest->raw("sequence"));
690
691 if ($this->isParticipantsAnswerFixed($q_id)) {
692 // should only be reached by firebugging the disabled form in ui
693 throw new ilTestException('not allowed request');
694 }
695
696 if (is_numeric($q_id) && (int) $q_id) {
697 $questionOBJ = $this->getQuestionInstance($q_id);
698
699 $active_id = (int) $this->testSession->getActiveId();
700 $pass = ilObjTest::_getPass($active_id);
701 $this->saveResult = $questionOBJ->persistWorkingState(
702 $active_id,
703 $pass,
704 $this->object->areObligationsEnabled(),
705 $authorized
706 );
707
708 if ($authorized && $this->testSession->isObjectiveOriented()) {
709 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($this->testSession);
710 $objectivesAdapter->updateQuestionResult($this->testSession, $questionOBJ);
711 }
712
713 if ($authorized && $this->object->isSkillServiceToBeConsidered()) {
714 $this->handleSkillTriggering($this->testSession);
715 }
716 }
717 }
718
719 if ($this->saveResult == false || (!$questionOBJ->validateSolutionSubmit() && $questionOBJ->savePartial())) {
720 $this->ctrl->setParameter($this, "save_error", "1");
721 ilSession::set("previouspost", $_POST);
722 }
723
724 return $this->saveResult;
725 }
726
727 protected function showInstantResponseCmd()
728 {
729 $questionId = $this->testSequence->getQuestionForSequence(
731 );
732
733 if (!$this->isParticipantsAnswerFixed($questionId)) {
734 if ($this->saveQuestionSolution(true)) {
736 $this->setAnswerChangedParameter(false);
737 } else {
738 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
739 }
740 $this->testSequence->setQuestionChecked($questionId);
741 $this->testSequence->saveToDb();
742 } elseif ($this->object->isForceInstantFeedbackEnabled()) {
743 $this->testSequence->setQuestionChecked($questionId);
744 $this->testSequence->saveToDb();
745 }
746
747 $this->ctrl->setParameter($this, 'instresp', 1);
748
749 // fau: testNav - handle navigation after feedback
750 if ($this->getNavigationUrlParameter()) {
753 }
754 // fau.
755 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
756 }
757
758 protected function handleQuestionActionCmd()
759 {
760 $questionId = $this->testSequence->getQuestionForSequence(
762 );
763
764 if (!$this->isParticipantsAnswerFixed($questionId)) {
765 $this->updateWorkingTime();
766 $this->saveQuestionSolution(false);
767 // fau: testNav - add changed status of the question
768 $this->setAnswerChangedParameter(true);
769 // fau.
770 }
771
772 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
773 }
774
776 {
777 if ($this->testSession->getActiveId() > 0) {
778 if ($this->testSequence->hasRandomQuestionsForPass($this->testSession->getActiveId(), $this->testSession->getPass()) > 0) {
779 // Something went wrong. Maybe the user pressed the start button twice
780 // Questions already exist so there is no need to create new questions
781
782 global $DIC;
783 $ilLog = $DIC['ilLog'];
784 $ilUser = $DIC['ilUser'];
785
786 $ilLog->write(
787 __METHOD__ . ' Random Questions allready exists for user ' .
788 $ilUser->getId() . ' in test ' . $this->object->getTestId()
789 );
790
791 return true;
792 }
793 } else {
794 // This may not happen! If it happens, raise a fatal error...
795
796 global $DIC;
797 $ilLog = $DIC['ilLog'];
798 $ilUser = $DIC['ilUser'];
799
800 $ilLog->write(__METHOD__ . ' ' . sprintf(
801 $this->lng->txt("error_random_question_generation"),
802 $ilUser->getId(),
803 $this->object->getTestId()
804 ));
805
806 return true;
807 };
808
809 return false;
810 }
811
813 {
814 global $DIC;
815 $tree = $DIC['tree'];
816 $ilDB = $DIC['ilDB'];
817 $component_repository = $DIC['component.repository'];
818
819 $questionSetConfig = new ilTestRandomQuestionSetConfig($tree, $ilDB, $component_repository, $this->object);
820 $questionSetConfig->loadFromDb();
821
822 $sourcePoolDefinitionFactory = new ilTestRandomQuestionSetSourcePoolDefinitionFactory($ilDB, $this->object);
823
824 $sourcePoolDefinitionList = new ilTestRandomQuestionSetSourcePoolDefinitionList($ilDB, $this->object, $sourcePoolDefinitionFactory);
825 $sourcePoolDefinitionList->loadDefinitions();
826
827 $this->processLocker->executeRandomPassBuildOperation(function () use ($ilDB, $component_repository, $questionSetConfig, $sourcePoolDefinitionList) {
829 $stagingPoolQuestionList = new ilTestRandomQuestionSetStagingPoolQuestionList($ilDB, $component_repository);
830
831 $questionSetBuilder = ilTestRandomQuestionSetBuilder::getInstance($ilDB, $this->object, $questionSetConfig, $sourcePoolDefinitionList, $stagingPoolQuestionList);
832
833 $questionSetBuilder->performBuild($this->testSession);
834 }
835 }, $sourcePoolDefinitionList->hasTaxonomyFilters());
836 }
837
841 protected function resumePlayerCmd()
842 {
843 $this->handleUserSettings();
844
845 $active_id = $this->testSession->getActiveId();
846 $this->ctrl->setParameter($this, "active_id", $active_id);
847
848 $active_time_id = $this->object->startWorkingTime($active_id, $this->testSession->getPass());
849 ilSession::set("active_time_id", $active_time_id);
850 ilSession::set('tst_pass_finish', 0);
851
852 if ($this->object->isRandomTest()) {
853 if (!$this->testSequence->hasRandomQuestionsForPass($active_id, $this->testSession->getPass())) {
854 // create a new set of random questions
856 }
857 }
858
859 $shuffle = $this->object->getShuffleQuestions();
860 if ($this->object->isRandomTest()) {
861 $shuffle = false;
862 }
863
864 assQuestion::_updateTestPassResults(
865 $active_id,
866 $this->testSession->getPass(),
867 $this->object->areObligationsEnabled(),
868 null,
869 $this->object->getId()
870 );
871
872 // ensure existing test sequence
873 if (!$this->testSequence->hasSequence()) {
874 $this->testSequence->createNewSequence($this->object->getQuestionCount(), $shuffle);
875 $this->testSequence->saveToDb();
876 }
877
878 if ($this->object->getListOfQuestionsStart()) {
879 $this->ctrl->redirect($this, ilTestPlayerCommands::QUESTION_SUMMARY);
880 }
881
882 $this->ctrl->setParameter($this, 'sequence', $this->testSession->getLastSequence());
883 $this->ctrl->setParameter($this, 'pmode', '');
884 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
885 }
886
887 protected function isShowingPostponeStatusReguired($questionId): bool
888 {
889 return $this->testSequence->isPostponedQuestion($questionId);
890 }
891
893 {
894 global $DIC;
895 $ilDB = $DIC['ilDB'];
896 $ilUser = $DIC['ilUser'];
897
898 $assSettings = new ilSetting('assessment');
899
900 $isAssessmentLogEnabled = ilObjAssessmentFolder::_enabledAssessmentLogging();
901
902 $userSolutionAdopter = new ilAssQuestionUserSolutionAdopter($ilDB, $assSettings, $isAssessmentLogEnabled);
903
904 $userSolutionAdopter->setUserId($ilUser->getId());
905 $userSolutionAdopter->setActiveId($this->testSession->getActiveId());
906 $userSolutionAdopter->setTargetPass($this->testSequence->getPass());
907 $userSolutionAdopter->setQuestionIds($this->testSequence->getOptionalQuestions());
908
909 $userSolutionAdopter->perform();
910 }
911
912 abstract protected function populateQuestionOptionalMessage();
913
914 protected function isOptionalQuestionAnsweringConfirmationRequired($sequenceKey): bool
915 {
916 if ($this->testSequence->isAnsweringOptionalQuestionsConfirmed()) {
917 return false;
918 }
919
920 $questionId = $this->testSequence->getQuestionForSequence($sequenceKey);
921
922 if (!$this->testSequence->isQuestionOptional($questionId)) {
923 return false;
924 }
925
926 return true;
927 }
928
930 {
931 return true;
932 }
933
935 {
936 $this->tpl->setOnScreenMessage('failure', sprintf($this->lng->txt('tst_objective_oriented_test_pass_without_questions'), $this->object->getTitle()), true);
937
938 $this->backToInfoScreenCmd();
939 }
940
946 protected function handlePrimaryButton(ilTestNavigationToolbarGUI $navigationToolbarGUI, $currentQuestionId): bool
947 {
948 $isNextPrimary = true;
949
950 if ($this->object->isForceInstantFeedbackEnabled()) {
951 $isNextPrimary = false;
952 }
953
954 $questionsMissingResult = assQuestion::getQuestionsMissingResultRecord(
955 $this->testSession->getActiveId(),
956 $this->testSession->getPass(),
957 $this->testSequence->getOrderedSequenceQuestions()
958 );
959
960 if (!count($questionsMissingResult)) {
961 $navigationToolbarGUI->setFinishTestButtonPrimary(true);
962 $isNextPrimary = false;
963 } elseif (count($questionsMissingResult) == 1) {
964 $lastOpenQuestion = current($questionsMissingResult);
965
966 if ($currentQuestionId == $lastOpenQuestion) {
967 $navigationToolbarGUI->setFinishTestButtonPrimary(true);
968 $isNextPrimary = false;
969 }
970 }
971
972 return $isNextPrimary;
973 }
974}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _isWorkedThrough(int $active_id, int $question_id, int $pass)
Returns true if the question was worked through in the given pass Worked through means that the user ...
static getQuestionsMissingResultRecord(int $activeId, int $pass, array $questionIds)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstance(ilTestSession $a_test_session)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
static get(string $a_var)
static set(string $a_var, $a_val)
Set a value.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setFinishTestButtonPrimary($finishTestButtonPrimary)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
isLastQuestionInSequence($sequenceElement)
handleQuestionPostponing($sequenceElement)
isOptionalQuestionAnsweringConfirmationRequired($sequenceKey)
canSaveResult()
Returns TRUE if the answers of the current user could be saved.
handlePrimaryButton(ilTestNavigationToolbarGUI $navigationToolbarGUI, $currentQuestionId)
resumePlayerCmd()
Resume a test at the last position.
populateQuestionOptionalMessage()
isShowingPostponeStatusReguired($questionId)
executeCommand()
Execute Command.
isValidSequenceElement($sequenceElement)
isFirstQuestionInSequence($sequenceElement)
saveQuestionSolution($authorized=true, $force=false)
saves the user input of a question
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
handleSkillTriggering(ilTestSession $testSession)
checkTestSessionUser(ilTestSession $testSession)
removeIntermediateSolution()
remove an auto-saved solution of the current question
setAnswerChangedParameter($changed=true)
Set the 'answer changed' url parameter for generated links.
prepareTestPage($presentationMode, $sequenceElement, $questionId)
handleTearsAndAngerQuestionIsNull($questionId, $sequenceElement)
getQuestionInstance($questionId, $fromCache=true)
getQuestionGuiInstance($question_id, $fromCache=true)
populateInstantResponseModal(assQuestionGUI $questionGui, $navUrl)
showQuestionEditable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
ensureExistingTestSession(ilTestSession $testSession)
updateWorkingTime()
updates working time and stores state saveresult to see if question has to be stored or not
handleUserSettings()
Handles some form parameters on starting and resuming a test.
populateInstantResponseBlocks(assQuestionGUI $questionGui, $authorizedSolution)
populateTestNavigationToolbar(ilTestNavigationToolbarGUI $toolbarGUI)
getAnswerChangedParameter()
Get the 'answer changed' status from the current request It may be set by ilTestPlayerNavigationContr...
isMaxProcessingTimeReached()
Checks wheather the maximum processing time is reached or not.
saveNavigationPreventConfirmation()
Save the save the switch to prevent the navigation confirmation.
registerForcedFeedbackNavUrl($forcedFeedbackNavUrl)
populateQuestionNavigation($sequenceElement, $disabled, $primaryNext)
showQuestionViewable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
static getInstance(ilDBInterface $db, ilObjTest $testOBJ, ilTestRandomQuestionSetConfig $questionSetConfig, ilTestRandomQuestionSetSourcePoolDefinitionList $sourcePoolDefinitionList, ilTestRandomQuestionSetStagingPoolQuestionList $stagingPoolQuestionList)
getCommand($cmd)
Retrieves the ilCtrl command.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static redirect(string $a_script)
static initConnectionWithAnimation()
Init YUI connection and animation module used in Modules/Test (Jan 2022)
static initjQuery(ilGlobalTemplateInterface $a_tpl=null)
inits and adds the jQuery JS-File to the global or a passed template
global $DIC
Definition: feed.php:28
$ilUser
Definition: imgupload.php:34