ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.ilTestPlayerAbstractGUI.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once './Modules/Test/classes/inc.AssessmentConstants.php';
5require_once './Modules/Test/classes/class.ilTestPlayerCommands.php';
6require_once './Modules/Test/classes/class.ilTestServiceGUI.php';
7require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
8require_once './Services/UIComponent/Button/classes/class.ilSubmitButton.php';
9require_once 'Modules/Test/classes/class.ilTestPlayerNavButton.php';
10
26{
27 const PRESENTATION_MODE_VIEW = 'view';
28 const PRESENTATION_MODE_EDIT = 'edit';
29
36
41
45 protected $processLocker;
46
50 protected $testSession;
51
55 protected $assSettings;
56
60 protected $testSequence = null;
61
67 public function __construct($a_object)
68 {
69 parent::ilTestServiceGUI($a_object);
70 $this->ref_id = $_GET["ref_id"];
71
72 global $rbacsystem, $ilUser, $lng;
73 require_once 'Modules/Test/classes/class.ilTestPasswordChecker.php';
74 $this->passwordChecker = new ilTestPasswordChecker($rbacsystem, $ilUser, $this->object, $lng);
75
76 $this->processLocker = null;
77 $this->testSession = null;
78 $this->assSettings = null;
79 }
80
81 protected function checkReadAccess()
82 {
83 global $rbacsystem;
84
85 if(!$rbacsystem->checkAccess("read", $this->object->getRefId()))
86 {
87 // only with read access it is possible to run the test
88 $this->ilias->raiseError($this->lng->txt("cannot_execute_test"), $this->ilias->error_obj->MESSAGE);
89 }
90 }
91
92 protected function checkTestExecutable()
93 {
94 $executable = $this->object->isExecutable($this->testSession, $this->testSession->getUserId());
95
96 if( !$executable['executable'] )
97 {
98 ilUtil::sendInfo($executable['errormessage'], true);
99 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
100 }
101 }
102
104 {
105 if( $testSession->getActiveId() )
106 {
107 return;
108 }
109
110 global $ilUser;
111
112 $testSession->setUserId($ilUser->getId());
113
114 if( $testSession->isAnonymousUser() )
115 {
116 if( !$testSession->doesAccessCodeInSessionExists() )
117 {
118 return;
119 }
120
121 $testSession->setAnonymousId($testSession->getAccessCodeFromSession());
122 }
123
124 $testSession->saveToDb();
125 }
126
127 protected function initProcessLocker($activeId)
128 {
129 global $ilDB;
130
131 require_once 'Modules/Test/classes/class.ilTestProcessLockerFactory.php';
132 $processLockerFactory = new ilTestProcessLockerFactory($this->assSettings, $ilDB);
133
134 $processLockerFactory->setActiveId($activeId);
135
136 $this->processLocker = $processLockerFactory->getLocker();
137 }
138
145 function saveTagsCmd()
146 {
147 include_once("./Services/Tagging/classes/class.ilTaggingGUI.php");
148 $tagging_gui = new ilTaggingGUI();
149 $tagging_gui->setObject($this->object->getId(), $this->object->getType());
150 $tagging_gui->saveInput();
151 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
152 }
153
158 {
159 if ($_SESSION["active_time_id"])
160 {
161 $this->object->updateWorkingTime($_SESSION["active_time_id"]);
162 }
163
164 $_SESSION["active_time_id"] = $this->object->startWorkingTime(
165 $this->testSession->getActiveId(), $this->testSession->getPass()
166 );
167 }
168
172 abstract public function saveQuestionSolution($authorized = true, $force = false);
173
174 abstract protected function canSaveResult();
175
176 public function suspendTestCmd()
177 {
178 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
179 }
180
188 public function isMaxProcessingTimeReached()
189 {
190 global $ilUser;
191 $active_id = $this->testSession->getActiveId();
192 $starting_time = $this->object->getStartingTimeOfUser($active_id);
193 if ($starting_time === FALSE)
194 {
195 return FALSE;
196 }
197 else
198 {
199 return $this->object->isMaxProcessingTimeReached($starting_time, $active_id);
200 }
201 }
202
203 protected function determineInlineScoreDisplay()
204 {
205 $show_question_inline_score = FALSE;
206 if ($this->object->getAnswerFeedbackPoints())
207 {
208 $show_question_inline_score = TRUE;
209 return $show_question_inline_score;
210 }
211 return $show_question_inline_score;
212 }
213
215 {
216 $this->tpl->setCurrentBlock('test_nav_toolbar');
217 $this->tpl->setVariable('TEST_NAV_TOOLBAR', $toolbarGUI->getHTML());
218 $this->tpl->parseCurrentBlock();
219 }
220
221 protected function populateQuestionNavigation($sequenceElement, $disabled)
222 {
223 if( !$this->isFirstQuestionInSequence($sequenceElement) )
224 {
225 $this->populatePreviousButtons($disabled);
226 }
227
228 if( !$this->isLastQuestionInSequence($sequenceElement) )
229 {
230 $this->populateNextButtons($disabled);
231 }
232 }
233
234 protected function populatePreviousButtons($disabled)
235 {
236 $this->populateUpperPreviousButtonBlock($disabled);
237 $this->populateLowerPreviousButtonBlock($disabled);
238 }
239
240 protected function populateNextButtons($disabled)
241 {
242 $this->populateUpperNextButtonBlock($disabled);
243 $this->populateLowerNextButtonBlock($disabled);
244 }
245
246 protected function populateLowerNextButtonBlock($disabled)
247 {
248 $button = $this->buildNextButtonInstance($disabled);
249 $button->setId('bottomnextbutton');
250
251 $this->tpl->setCurrentBlock( "next_bottom" );
252 $this->tpl->setVariable( "BTN_NEXT", $button->render());
253 $this->tpl->parseCurrentBlock();
254 }
255
256 protected function populateUpperNextButtonBlock($disabled)
257 {
258 $button = $this->buildNextButtonInstance($disabled);
259 $button->setId('nextbutton');
260
261 $this->tpl->setCurrentBlock( "next" );
262 $this->tpl->setVariable( "BTN_NEXT", $button->render());
263 $this->tpl->parseCurrentBlock();
264 }
265
266 protected function populateLowerPreviousButtonBlock($disabled)
267 {
268 $button = $this->buildPreviousButtonInstance($disabled);
269 $button->setId('bottomprevbutton');
270
271 $this->tpl->setCurrentBlock( "prev_bottom" );
272 $this->tpl->setVariable("BTN_PREV", $button->render());
273 $this->tpl->parseCurrentBlock();
274 }
275
276 protected function populateUpperPreviousButtonBlock($disabled)
277 {
278 $button = $this->buildPreviousButtonInstance($disabled);
279 $button->setId('prevbutton');
280
281 $this->tpl->setCurrentBlock( "prev" );
282 $this->tpl->setVariable("BTN_PREV", $button->render());
283 $this->tpl->parseCurrentBlock();
284 }
285
290 private function buildNextButtonInstance($disabled)
291 {
293 $button->setPrimary(false);
294 $button->setNextCommand(ilTestPlayerCommands::NEXT_QUESTION);
295 $button->setUrl($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::NEXT_QUESTION));
296 $button->setCaption('next_question');
297 $button->addCSSClass('ilTstNavElem');
298 //$button->setDisabled($disabled);
299 return $button;
300 }
301
306 private function buildPreviousButtonInstance($disabled)
307 {
309 $button->setNextCommand(ilTestPlayerCommands::PREVIOUS_QUESTION);
310 $button->setUrl($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::PREVIOUS_QUESTION));
311 $button->setCaption('previous_question');
312 $button->addCSSClass('ilTstNavElem');
313 //$button->setDisabled($disabled);
314 return $button;
315 }
316
317 protected function populateSpecificFeedbackBlock($question_gui)
318 {
319 $this->tpl->setCurrentBlock( "specific_feedback" );
320 $this->tpl->setVariable( "SPECIFIC_FEEDBACK",
321 $question_gui->getSpecificFeedbackOutput(
322 $this->testSession->getActiveId(),
323 $this->testSequence->getPass()
324 )
325 );
326 $this->tpl->parseCurrentBlock();
327 }
328
329 protected function populateGenericFeedbackBlock(assQuestionGUI $question_gui, $solutionCorrect)
330 {
331 $feedback = $question_gui->getGenericFeedbackOutput(
332 $this->testSession->getActiveId(),$this->testSequence->getPass()
333 );
334
335 if( strlen($feedback) )
336 {
337 $cssClass = ( $solutionCorrect ?
339 );
340
341 $this->tpl->setCurrentBlock( "answer_feedback" );
342 $this->tpl->setVariable( "ANSWER_FEEDBACK", $feedback);
343 $this->tpl->setVariable( "ILC_FB_CSS_CLASS", $cssClass);
344 $this->tpl->parseCurrentBlock();
345 }
346 }
347
348 protected function populateScoreBlock($reachedPoints, $maxPoints)
349 {
350 $scoreInformation = sprintf(
351 $this->lng->txt( "you_received_a_of_b_points" ), $reachedPoints, $maxPoints
352 );
353
354 $this->tpl->setCurrentBlock( "received_points_information" );
355 $this->tpl->setVariable("RECEIVED_POINTS_INFORMATION", $scoreInformation);
356 $this->tpl->parseCurrentBlock();
357 }
358
359 protected function populateSolutionBlock($solutionoutput)
360 {
361 $this->tpl->setCurrentBlock( "solution_output" );
362 $this->tpl->setVariable( "CORRECT_SOLUTION", $this->lng->txt( "tst_best_solution_is" ) );
363 $this->tpl->setVariable( "QUESTION_FEEDBACK", $solutionoutput );
364 $this->tpl->parseCurrentBlock();
365 }
366
367 protected function populateSyntaxStyleBlock()
368 {
369 $this->tpl->setCurrentBlock( "SyntaxStyle" );
370 $this->tpl->setVariable( "LOCATION_SYNTAX_STYLESHEET",
372 );
373 $this->tpl->parseCurrentBlock();
374 }
375
376 protected function populateContentStyleBlock()
377 {
378 include_once("./Services/Style/classes/class.ilObjStyleSheet.php");
379 $this->tpl->setCurrentBlock( "ContentStyle" );
380 $this->tpl->setVariable( "LOCATION_CONTENT_STYLESHEET",
382 );
383 $this->tpl->parseCurrentBlock();
384 }
385
391 public function setAnonymousIdCmd()
392 {
393 if( $this->testSession->isAnonymousUser() )
394 {
395 $this->testSession->setAccessCodeToSession($_POST['anonymous_id']);
396 }
397
398 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
399 }
400
407 protected function startPlayerCmd()
408 {
409 $testStartLock = $this->getLockParameter();
410 $isFirstTestStartRequest = false;
411
412 $this->processLocker->requestTestStartLockCheckLock();
413
414 if( $this->testSession->lookupTestStartLock() != $testStartLock )
415 {
416 $this->testSession->persistTestStartLock($testStartLock);
417 $isFirstTestStartRequest = true;
418 }
419
420 $this->processLocker->releaseTestStartLockCheckLock();
421
422 if( $isFirstTestStartRequest )
423 {
424 $this->handleUserSettings();
425 $this->ctrl->redirect($this, ilTestPlayerCommands::INIT_TEST);
426 }
427
428 $this->ctrl->setParameterByClass('ilObjTestGUI', 'lock', $testStartLock);
429 $this->ctrl->redirectByClass("ilobjtestgui", "redirectToInfoScreen");
430 }
431
432 public function getLockParameter()
433 {
434 if( isset($_POST['lock']) && strlen($_POST['lock']) )
435 {
436 return $_POST['lock'];
437 }
438 elseif( isset($_GET['lock']) && strlen($_GET['lock']) )
439 {
440 return $_GET['lock'];
441 }
442
443 return null;
444 }
445
449 abstract protected function resumePlayerCmd();
450
454 protected function initTestCmd()
455 {
456 if ($this->object->checkMaximumAllowedUsers() == FALSE)
457 {
459 }
460
461 if( $this->testSession->isAnonymousUser() && !$this->testSession->getActiveId() )
462 {
463 $accessCode = $this->testSession->createNewAccessCode();
464
465 $this->testSession->setAccessCodeToSession($accessCode);
466 $this->testSession->setAnonymousId($accessCode);
467 $this->testSession->saveToDb();
468
469 $this->ctrl->redirect($this, ilTestPlayerCommands::DISPLAY_ACCESS_CODE);
470 }
471
472 $this->testSession->unsetAccessCodeInSession();
473 $this->ctrl->redirect($this, ilTestPlayerCommands::START_TEST);
474 }
475
477 {
478 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_anonymous_code_presentation.html", "Modules/Test");
479 $this->tpl->setCurrentBlock("adm_content");
480 $this->tpl->setVariable("TEXT_ANONYMOUS_CODE_CREATED", $this->lng->txt("tst_access_code_created"));
481 $this->tpl->setVariable("TEXT_ANONYMOUS_CODE", $this->testSession->getAccessCodeFromSession());
482 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
483 $this->tpl->setVariable("CMD_CONFIRM", ilTestPlayerCommands::ACCESS_CODE_CONFIRMED);
484 $this->tpl->setVariable("TXT_CONFIRM", $this->lng->txt("continue_work"));
485 $this->tpl->parseCurrentBlock();
486 }
487
489 {
490 $this->ctrl->redirect($this, ilTestPlayerCommands::START_TEST);
491 }
492
496 public function handleUserSettings()
497 {
498 global $ilUser;
499
500 if ($_POST["chb_javascript"])
501 {
502 $ilUser->writePref("tst_javascript", 1);
503 }
504 else
505 {
506 $ilUser->writePref("tst_javascript", 0);
507 }
508
509 // hide previous results
510 if ($this->object->getNrOfTries() != 1)
511 {
512 if ($this->object->getUsePreviousAnswers() == 1)
513 {
514 if ($_POST["chb_use_previous_answers"])
515 {
516 $ilUser->writePref("tst_use_previous_answers", 1);
517 }
518 else
519 {
520 $ilUser->writePref("tst_use_previous_answers", 0);
521 }
522 }
523 }
524 }
525
527 {
528 $active_id = $this->testSession->getActiveId();
529 $actualpass = $this->object->_getPass($active_id);
530
531 $this->performTestPassFinishedTasks($actualpass);
532
533 $this->testSession->setLastFinishedPass($this->testSession->getPass());
534 $this->testSession->increaseTestPass();
535
536 $url = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED);
537
538 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_redirect_autosave.html", "Modules/Test");
539 $this->tpl->setVariable("TEXT_REDIRECT", $this->lng->txt("redirectAfterSave"));
540 $this->tpl->setCurrentBlock("HeadContent");
541 $this->tpl->setVariable("CONTENT_BLOCK", "<meta http-equiv=\"refresh\" content=\"5; url=" . $url . "\">");
542 $this->tpl->parseCurrentBlock();
543 }
544
545 abstract protected function getCurrentQuestionId();
546
547 function autosaveCmd()
548 {
549 $canSaveResult = $this->canSaveResult();
550 $authorizedSolution = !$canSaveResult;
551
552 $result = "";
553 if (is_array($_POST) && count($_POST) > 0)
554 {
556 {
557 $result = '-IGNORE-';
558 }
559 else
560 {
561 $res = $this->saveQuestionSolution($authorizedSolution, true);
562 if ($res)
563 {
564 $result = $this->lng->txt("autosave_success");
565 }
566 else
567 {
568 $result = $this->lng->txt("autosave_failed");
569 }
570 }
571 }
572 if (!$canSaveResult)
573 {
574 // this was the last action in the test, saving is no longer allowed
575 $result = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::REDIRECT_ON_TIME_LIMIT, "", true);
576 }
577 echo $result;
578 exit;
579 }
580
581 protected function submitIntermediateSolutionCmd()
582 {
583 $this->saveQuestionSolution(false, true);
584 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
585 }
586
590 public function toggleSideListCmd()
591 {
592 global $ilUser;
593
594 $show_side_list = $ilUser->getPref('side_list_of_questions');
595 $ilUser->writePref('side_list_of_questions', !$show_side_list);
596 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
597 }
598
600 {
601 $this->saveQuestionSolution(false);
602 $this->markQuestionCmd();
603 }
604
608 protected function markQuestionCmd()
609 {
610 $questionId = $this->testSequence->getQuestionForSequence(
612 );
613
614 $this->object->setQuestionSetSolved(1, $questionId, $this->testSession->getUserId());
615
616 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
617 }
618
620 {
621 $this->saveQuestionSolution(false);
622 $this->unmarkQuestionCmd();
623 }
624
628 protected function unmarkQuestionCmd()
629 {
630 $questionId = $this->testSequence->getQuestionForSequence(
632 );
633
634 $this->object->setQuestionSetSolved(0, $questionId, $this->testSession->getUserId());
635
636 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
637 }
638
642 protected function confirmFinishCmd()
643 {
644 $this->finishTestCmd(false);
645 }
646
650 protected function confirmFinishTestCmd()
651 {
655 global $ilUser;
656
657 require_once 'Services/Utilities/classes/class.ilConfirmationGUI.php';
658 $confirmation = new ilConfirmationGUI();
659 $confirmation->setFormAction($this->ctrl->getFormAction($this, 'confirmFinish'));
660 $confirmation->setHeaderText($this->lng->txt("tst_finish_confirmation_question"));
661 $confirmation->setConfirm($this->lng->txt("tst_finish_confirm_button"), 'confirmFinish');
662 $confirmation->setCancel($this->lng->txt("tst_finish_confirm_cancel_button"), ilTestPlayerCommands::BACK_FROM_FINISHING);
663
664 $this->populateHelperGuiContent($confirmation);
665 }
666
667 function finishTestCmd($requires_confirmation = true)
668 {
669 global $ilAuth;
670
671 unset($_SESSION["tst_next"]);
672
673 $active_id = $this->testSession->getActiveId();
674 $actualpass = $this->object->_getPass($active_id);
675
676 $allObligationsAnswered = ilObjTest::allObligationsAnswered($this->testSession->getTestId(), $active_id, $actualpass);
677
678 /*
679 * The following "endgames" are possible prior to actually finishing the test:
680 * - Obligations (Ability to finish the test.)
681 * If not all obligatory questions are answered, the user is presented a list
682 * showing the deficits.
683 * - Examview (Will to finish the test.)
684 * With the examview, the participant can review all answers given in ILIAS or a PDF prior to
685 * commencing to the finished test.
686 * - Last pass allowed (Reassuring the will to finish the test.)
687 * If passes are limited, on the last pass, an additional confirmation is to be displayed.
688 */
689
690
691 if( $this->object->areObligationsEnabled() && !$allObligationsAnswered )
692 {
693 if( $this->object->getListOfQuestions() )
694 {
695 $this->ctrl->redirect($this, ilTestPlayerCommands::QUESTION_SUMMARY_INC_OBLIGATIONS);
696 }
697 else
698 {
700 }
701
702 return;
703 }
704
705 // Examview enabled & !reviewed & requires_confirmation? test_submission_overview (review gui)
706 if ($this->object->getEnableExamview() && !isset($_GET['reviewed']) && $requires_confirmation)
707 {
708 $this->ctrl->redirectByClass('ilTestSubmissionReviewGUI', "show");
709 return;
710 }
711
712 // Last try in limited tries & !confirmed
713 if (($requires_confirmation) && ($actualpass == $this->object->getNrOfTries() - 1))
714 {
715 // show confirmation page
716 return $this->confirmFinishTestCmd();
717 }
718
719 // Last try in limited tries & confirmed?
720 if(($actualpass == $this->object->getNrOfTries() - 1) && (!$requires_confirmation))
721 {
722 $ilAuth->setIdle(ilSession::getIdleValue(), false);
723 $ilAuth->setExpire(0);
724 switch($this->object->getMailNotification())
725 {
726 case 1:
727 $this->object->sendSimpleNotification($active_id);
728 break;
729 case 2:
730 $this->object->sendAdvancedNotification($active_id);
731 break;
732 }
733 }
734
735 // Non-last try finish
736 if(!$_SESSION['tst_pass_finish'])
737 {
738 if(!$_SESSION['tst_pass_finish']) $_SESSION['tst_pass_finish'] = 1;
739 if($this->object->getMailNotificationType() == 1)
740 {
741 switch($this->object->getMailNotification())
742 {
743 case 1:
744 $this->object->sendSimpleNotification($active_id);
745 break;
746 case 2:
747 $this->object->sendAdvancedNotification($active_id);
748 break;
749 }
750 }
751 }
752
753 // no redirect request loops after test pass finished tasks has been performed
754
755 $this->performTestPassFinishedTasks($actualpass);
756
757 $this->testSession->setLastFinishedPass($this->testSession->getPass());
758 $this->testSession->increaseTestPass();
759
760 $this->ctrl->redirect($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED);
761 }
762
763 protected function performTestPassFinishedTasks($finishedPass)
764 {
765 if( !$this->testSession->isSubmitted() )
766 {
767 $this->testSession->setSubmitted(1);
768 $this->testSession->setSubmittedTimestamp(date('Y-m-d H:i:s'));
769 $this->testSession->saveToDb();
770 }
771 }
772
773 protected function afterTestPassFinishedCmd()
774 {
775 $activeId = $this->testSession->getActiveId();
776 $lastFinishedPass = $this->testSession->getLastFinishedPass();
777
778 // handle test signature
779 if ( $this->isTestSignRedirectRequired($activeId, $lastFinishedPass) )
780 {
781 $this->ctrl->redirectByClass('ilTestSignatureGUI', 'invokeSignaturePlugin');
782 }
783
784 // show final statement
785 if(!$_GET['skipfinalstatement'])
786 {
787 if ($this->object->getShowFinalStatement())
788 {
789 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_FINAL_STATMENT);
790 }
791 }
792
793 // redirect after test
794 $redirection_mode = $this->object->getRedirectionMode();
795 $redirection_url = $this->object->getRedirectionUrl();
796 if( $redirection_url && $redirection_mode && !$this->object->canViewResults() )
797 {
798 if( $redirection_mode == REDIRECT_KIOSK )
799 {
800 if( $this->object->getKioskMode() )
801 {
802 ilUtil::redirect($redirection_url);
803 }
804 }
805 else
806 {
807 ilUtil::redirect($redirection_url);
808 }
809 }
810
811 // default redirect (pass overview when enabled, otherwise infoscreen)
812 $this->redirectBackCmd();
813 }
814
815 protected function isTestSignRedirectRequired($activeId, $lastFinishedPass)
816 {
817 if( !$this->object->getSignSubmission() )
818 {
819 return false;
820 }
821
822 if( !is_null(ilSession::get("signed_{$activeId}_{$lastFinishedPass}")) )
823 {
824 return false;
825 }
826
827 global $ilPluginAdmin;
828
829 $activePlugins = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, 'Test', 'tsig');
830
831 if( !count($activePlugins) )
832 {
833 return false;
834 }
835
836 return true;
837 }
838
844 protected function archiveParticipantSubmission( $active, $pass )
845 {
846 global $ilObjDataCache;
847
848 require_once 'Modules/Test/classes/class.ilTestResultHeaderLabelBuilder.php';
849 $testResultHeaderLabelBuilder = new ilTestResultHeaderLabelBuilder($this->lng, $ilObjDataCache);
850
851 $objectivesList = null;
852
853 if( $this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired() )
854 {
855 $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($this->testSession->getActiveId(), $this->testSession->getPass());
856 $testSequence->loadFromDb();
857 $testSequence->loadQuestions();
858
859 require_once 'Modules/Course/classes/Objectives/class.ilLOTestQuestionAdapter.php';
860 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($this->testSession);
861
862 $objectivesList = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $testSequence);
863 $objectivesList->loadObjectivesTitles();
864
865 $testResultHeaderLabelBuilder->setObjectiveOrientedContainerId($this->testSession->getObjectiveOrientedContainerId());
866 $testResultHeaderLabelBuilder->setUserId($this->testSession->getUserId());
867 $testResultHeaderLabelBuilder->setTestObjId($this->object->getId());
868 $testResultHeaderLabelBuilder->setTestRefId($this->object->getRefId());
869 $testResultHeaderLabelBuilder->initObjectiveOrientedMode();
870 }
871
872 $results = $this->object->getTestResult(
873 $active, $pass, false, !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
874 );
875
876 require_once 'class.ilTestEvaluationGUI.php';
877 $testevaluationgui = new ilTestEvaluationGUI($this->object);
878 $results_output = $testevaluationgui->getPassListOfAnswers(
879 $results, $active, $pass, false, false, false, false, false, $objectivesList, $testResultHeaderLabelBuilder
880 );
881
882 require_once './Modules/Test/classes/class.ilTestArchiver.php';
883 global $ilSetting;
884 $inst_id = $ilSetting->get('inst_id', null);
885 $archiver = new ilTestArchiver($this->object->getId());
886
887 $path = ilUtil::getWebspaceDir() . '/assessment/'. $this->object->getId() . '/exam_pdf';
888 if (!is_dir($path))
889 {
891 }
892 $filename = realpath($path) . '/exam_N' . $inst_id . '-' . $this->object->getId()
893 . '-' . $active . '-' . $pass . '.pdf';
894
895 require_once 'class.ilTestPDFGenerator.php';
897 //$template->setVariable("PDF_FILE_LOCATION", $filename);
898 // Participant submission
899 $archiver->handInParticipantSubmission( $active, $pass, $filename, $results_output );
900 //$archiver->handInParticipantMisc( $active, $pass, 'signature_gedoens.sig', $filename );
901 //$archiver->handInParticipantQuestionMaterial( $active, $pass, 123, 'file_upload.pdf', $filename );
902
903 global $ilias;
904 $questions = $this->object->getQuestions();
905 foreach ($questions as $question_id)
906 {
907 $question_object = $this->object->getQuestionDataset( $question_id );
908 if ($question_object->type_tag == 'assFileUpload')
909 {
910 // Pfad: /data/default/assessment/tst_2/14/21/files/file_14_4_1370417414.png
911 // /data/ - klar
912 // /assessment/ - Konvention
913 // /tst_2/ = /tst_<test_id> (ilObjTest)
914 // /14/ = /<active_fi>/
915 // /21/ = /<question_id>/ (question_object)
916 // /files/ - Konvention
917 // file_14_4_1370417414.png = file_<active_fi>_<pass>_<some timestamp>.<ext>
918
919 $candidate_path =
920 $ilias->ini_ilias->readVariable( 'server', 'absolute_path' ) . ilTestArchiver::DIR_SEP
921 . $ilias->ini_ilias->readVariable( 'clients', 'path' ) . ilTestArchiver::DIR_SEP
922 . $ilias->client_id . ilTestArchiver::DIR_SEP
923 . 'assessment' . ilTestArchiver::DIR_SEP
924 . 'tst_' . $this->object->test_id . ilTestArchiver::DIR_SEP
925 . $active . ilTestArchiver::DIR_SEP
926 . $question_id . ilTestArchiver::DIR_SEP
927 . 'files' . ilTestArchiver::DIR_SEP;
928 $handle = opendir( $candidate_path );
929 while ($handle !== false && ($file = readdir( $handle )) !== false)
930 {
931 if ($file != null)
932 {
933 $filename_start = 'file_' . $active . '_' . $pass . '_';
934
935 if (strpos( $file, $filename_start ) === 0)
936 {
937 $archiver->handInParticipantQuestionMaterial( $active, $pass, $question_id, $file, $file );
938 }
939 }
940 }
941 }
942 }
943 $passdata = $this->object->getTestResult(
944 $active, $pass, false, !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
945 );
946 $overview = $testevaluationgui->getPassListOfAnswers(
947 $passdata, $active, $pass, true, false, false, true, false, $objectivesList, $testResultHeaderLabelBuilder
948 );
949 $filename = realpath(ilUtil::getWebspaceDir()) . '/assessment/scores-'.$this->object->getId() . '-' . $active . '-' . $pass . '.pdf';
951 $archiver->handInTestResult($active, $pass, $filename);
952 unlink($filename);
953
954 return;
955 }
956
957 public function redirectBackCmd()
958 {
959 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
960 $testPassesSelector = new ilTestPassesSelector($GLOBALS['ilDB'], $this->object);
961 $testPassesSelector->setActiveId($this->testSession->getActiveId());
962 $testPassesSelector->setLastFinishedPass($this->testSession->getLastFinishedPass());
963
964 if( count($testPassesSelector->getReportablePasses()) )
965 {
966 $this->ctrl->redirectByClass("ilTestEvaluationGUI", "outUserResultsOverview");
967 }
968
969 $this->backToInfoScreenCmd();
970 }
971
972 protected function backToInfoScreenCmd()
973 {
974 $this->ctrl->redirectByClass('ilObjTestGUI', 'redirectToInfoScreen');
975 }
976
977 /*
978 * Presents the final statement of a test
979 */
980 public function showFinalStatementCmd()
981 {
982 $template = new ilTemplate("tpl.il_as_tst_final_statement.html", TRUE, TRUE, "Modules/Test");
983 $this->ctrl->setParameter($this, "skipfinalstatement", 1);
984 $template->setVariable("FORMACTION", $this->ctrl->getFormAction($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED));
985 $template->setVariable("FINALSTATEMENT", $this->object->prepareTextareaOutput($this->object->getFinalStatement(), true));
986 $template->setVariable("BUTTON_CONTINUE", $this->lng->txt("btn_next"));
987 $this->tpl->setVariable($this->getContentBlockName(), $template->get());
988 }
989
990 public function getKioskHead()
991 {
992 global $ilUser;
993
994 $template = new ilTemplate('tpl.il_as_tst_kiosk_head.html', true, true, 'Modules/Test');
995 if ($this->object->getShowKioskModeTitle())
996 {
997 $template->setCurrentBlock("kiosk_show_title");
998 $template->setVariable("TEST_TITLE", $this->object->getTitle());
999 $template->parseCurrentBlock();
1000 }
1001 if ($this->object->getShowKioskModeParticipant())
1002 {
1003 $template->setCurrentBlock("kiosk_show_participant");
1004 $template->setVariable("PARTICIPANT_NAME_TXT", $this->lng->txt("login_as"));
1005 $template->setVariable("PARTICIPANT_NAME", $ilUser->getFullname());
1006 $template->setVariable("PARTICIPANT_LOGIN", $ilUser->getLogin());
1007 $template->setVariable("PARTICIPANT_MATRICULATION", $ilUser->getMatriculation());
1008 $template->setVariable("PARTICIPANT_EMAIL", $ilUser->getEmail());
1009 $template->parseCurrentBlock();
1010 }
1011 if ($this->object->isShowExamIdInTestPassEnabled())
1012 {
1013 $exam_id = ilObjTest::buildExamId(
1014 $this->testSession->getActiveId() , $this->testSession->getPass(), $this->object->getId()
1015 );
1016
1017 $template->setCurrentBlock("kiosk_show_exam_id");
1018 $template->setVariable("EXAM_ID_TXT", $this->lng->txt("exam_id"));
1019 $template->setVariable( "EXAM_ID", $exam_id);
1020 $template->parseCurrentBlock();
1021 }
1022 return $template->get();
1023 }
1024
1028 protected function prepareTestPage($presentationMode, $sequenceElement, $questionId)
1029 {
1030 global $ilUser, $ilNavigationHistory;
1031
1032 $ilNavigationHistory->addItem($this->testSession->getRefId(),
1033 $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::RESUME_PLAYER), 'tst'
1034 );
1035
1036 $this->initTestPageTemplate();
1038 $this->populateSyntaxStyleBlock();
1039
1040 if ($this->isMaxProcessingTimeReached())
1041 {
1042 $this->maxProcessingTimeReached();
1043 return;
1044 }
1045
1046 if ($this->object->endingTimeReached())
1047 {
1048 $this->endingTimeReached();
1049 return;
1050 }
1051
1052 if( $this->isOptionalQuestionAnsweringConfirmationRequired($sequenceElement) )
1053 {
1054 $this->ctrl->setParameter($this, "sequence", $sequenceElement);
1056 return;
1057 }
1058
1059 if ($this->object->getKioskMode())
1060 {
1061 $this->populateKioskHead();
1062 }
1063
1064 $this->tpl->setVariable("TEST_ID", $this->object->getTestId());
1065 $this->tpl->setVariable("LOGIN", $ilUser->getLogin());
1066 $this->tpl->setVariable("SEQ_ID", $sequenceElement);
1067 $this->tpl->setVariable("QUEST_ID", $questionId);
1068
1069 if ($this->object->getEnableProcessingTime())
1070 {
1071 $this->outProcessingTime($this->testSession->getActiveId());
1072 }
1073
1074 $this->tpl->setVariable("PAGETITLE", "- " . $this->object->getTitle());
1075
1076 if ($this->object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode())
1077 {
1078 $this->tpl->setCurrentBlock('exam_id_footer');
1079 $this->tpl->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
1080 $this->testSession->getActiveId(), $this->testSession->getPass(), $this->object->getId()
1081 ));
1082 $this->tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
1083 $this->tpl->parseCurrentBlock();
1084 }
1085
1086 if ($this->object->getListOfQuestions())
1087 {
1088 $this->showSideList($presentationMode, $sequenceElement);
1089 }
1090 }
1091
1092 abstract protected function isOptionalQuestionAnsweringConfirmationRequired($sequenceElement);
1093
1094 abstract protected function isShowingPostponeStatusReguired($questionId);
1095
1096 protected function showQuestionViewable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
1097 {
1098 $questionNavigationGUI = $this->buildReadOnlyStateQuestionNavigationGUI($questionGui->object->getId());
1099 $questionNavigationGUI->setQuestionWorkedThrough($isQuestionWorkedThrough);
1100 $questionGui->setNavigationGUI($questionNavigationGUI);
1101
1102 $answerFeedbackEnabled = (
1103 $instantResponse && $this->object->getSpecificAnswerFeedback()
1104 );
1105
1106 $solutionoutput = $questionGui->getSolutionOutput(
1107 $this->testSession->getActiveId(), #active_id
1108 $this->testSession->getPass(), #pass
1109 false, #graphical_output
1110 false, #result_output
1111 true, #show_question_only
1112 $answerFeedbackEnabled, #show_feedback
1113 false, #show_correct_solution
1114 false, #show_manual_scoring
1115 true #show_question_text
1116 );
1117
1118 $pageoutput = $questionGui->outQuestionPage(
1119 "",
1120 $this->isShowingPostponeStatusReguired($questionGui->object->getId()),
1121 $this->testSession->getActiveId(),
1122 $solutionoutput
1123 );
1124
1125 $this->tpl->setCurrentBlock('readonly_css_class');
1126 $this->tpl->touchBlock('readonly_css_class');
1127 $this->tpl->parseCurrentBlock();
1128
1129 $this->tpl->setVariable('QUESTION_OUTPUT', $pageoutput);
1130
1131 $this->tpl->setVariable("FORMACTION", $formAction);
1132 $this->tpl->setVariable("ENCTYPE", 'enctype="'.$questionGui->getFormEncodingType().'"');
1133 $this->tpl->setVariable("FORM_TIMESTAMP", time());
1134 }
1135
1136 protected function showQuestionEditable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
1137 {
1138 $questionNavigationGUI = $this->buildEditableStateQuestionNavigationGUI(
1139 $questionGui->object->getId(), $this->populateCharSelectorIfRequired()
1140 );
1141 if( $isQuestionWorkedThrough )
1142 {
1143 $questionNavigationGUI->setDiscardSolutionButtonEnabled(true);
1144 }
1145 else
1146 {
1147 $questionNavigationGUI->setSkipQuestionLinkTarget(
1148 $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::SKIP_QUESTION)
1149 );
1150 }
1151 $questionGui->setNavigationGUI($questionNavigationGUI);
1152
1153 $isPostponed = $this->isShowingPostponeStatusReguired($questionGui->object->getId());
1154
1155 $answerFeedbackEnabled = (
1156 $instantResponse && $this->object->getSpecificAnswerFeedback()
1157 );
1158
1159 if( isset($_GET['save_error']) && $_GET['save_error'] == 1 && isset($_SESSION['previouspost']) )
1160 {
1161 $userPostSolution = $_SESSION['previouspost'];
1162 unset($_SESSION['previouspost']);
1163 }
1164 else
1165 {
1166 $userPostSolution = false;
1167 }
1168
1169 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
1170 $solutionPassIndex = $this->determineSolutionPassIndex($questionGui);
1171 $questionGui->setPreviousSolutionPrefilled($solutionPassIndex < $this->testSession->getPass());
1172 // hey.
1173
1174 // Answer specific feedback is rendered into the display of the test question with in the concrete question types outQuestionForTest-method.
1175 // Notation of the params prior to getting rid of this crap in favor of a class
1176 $questionGui->outQuestionForTest(
1177 $formAction, #form_action
1178 $this->testSession->getActiveId(), #active_id
1179 // hey: prevPassSolutions - prepared pass index having no, current or previous solution
1180 $solutionPassIndex, #pass
1181 // hey.
1182 $isPostponed, #is_postponed
1183 $userPostSolution, #user_post_solution
1184 $answerFeedbackEnabled #answer_feedback == inline_specific_feedback
1185 );
1186 // The display of specific inline feedback and specific feedback in an own block is to honor questions, which
1187 // have the possibility to embed the specific feedback into their output while maintaining compatibility to
1188 // questions, which do not have such facilities. E.g. there can be no "specific inline feedback" for essay
1189 // questions, while the multiple-choice questions do well.
1190
1191
1192 $this->populateModals();
1193
1194 $this->populateIntermediateSolutionSaver($questionGui);
1195 }
1196
1197 // hey: prevPassSolutions - determine solution pass index
1198 protected function determineSolutionPassIndex(assQuestionGUI $questionGui)
1199 {
1200 require_once './Modules/Test/classes/class.ilObjTest.php';
1201
1202 if( ilObjTest::_getUsePreviousAnswers($this->testSession->getActiveId(), true) )
1203 {
1204 $currentSolutionAvailable = $questionGui->object->authorizedOrIntermediateSolutionExists(
1205 $this->testSession->getActiveId(), $this->testSession->getPass()
1206 );
1207
1208 if( !$currentSolutionAvailable )
1209 {
1210 $previousPass = $questionGui->object->getSolutionMaxPass(
1211 $this->testSession->getActiveId()
1212 );
1213
1214 $previousSolutionAvailable = $questionGui->object->authorizedSolutionExists(
1215 $this->testSession->getActiveId(), $previousPass
1216 );
1217
1218 if( $previousSolutionAvailable )
1219 {
1220 return $previousPass;
1221 }
1222 }
1223 }
1224
1225 return $this->testSession->getPass();
1226 }
1227 // hey.
1228
1229 abstract protected function showQuestionCmd();
1230
1231 abstract protected function editSolutionCmd();
1232
1233 abstract protected function submitSolutionCmd();
1234
1235 abstract protected function discardSolutionCmd();
1236
1237 abstract protected function skipQuestionCmd();
1238
1239 abstract protected function startTestCmd();
1248 {
1249 global $ilUser;
1250
1251 // check if user is invited to participate
1252 $user = $this->object->getInvitedUsers($ilUser->getId());
1253 if (!is_array ($user) || count($user)!=1)
1254 {
1255 ilUtil::sendInfo($this->lng->txt("user_not_invited"), true);
1256 $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1257 }
1258
1259 $user = array_pop($user);
1260 // check if client ip is set and if current remote addr is equal to stored client-ip
1261 if (strcmp($user["clientip"],"")!=0 && strcmp($user["clientip"],$_SERVER["REMOTE_ADDR"])!=0)
1262 {
1263 ilUtil::sendInfo($this->lng->txt("user_wrong_clientip"), true);
1264 $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1265 }
1266 }
1267
1268
1273 {
1274 return !$this->isNrOfTriesReached()
1275 and !$this->isMaxProcessingTimeReached()
1276 and $this->object->startingTimeReached()
1277 and !$this->object->endingTimeReached();
1278 }
1279
1284 {
1285 return $this->object->hasNrOfTriesRestriction() && $this->object->isNrOfTriesReached($this->testSession->getPass());
1286 }
1287
1294 {
1295 ilUtil::sendInfo(sprintf($this->lng->txt("detail_ending_time_reached"), ilFormat::ftimestamp2datetimeDB($this->object->getEndingTime())));
1296 $this->testSession->increasePass();
1297 $this->testSession->setLastSequence(0);
1298 $this->testSession->saveToDb();
1299
1300 $this->redirectBackCmd();
1301 }
1302
1311 {
1312 $this->suspendTestCmd();
1313 }
1314
1321 {
1322 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_submit_answers_confirm.html", "Modules/Test");
1323 $this->tpl->setCurrentBlock("adm_content");
1324 if ($this->object->isTestFinished($this->testSession->getActiveId()))
1325 {
1326 $this->tpl->setCurrentBlock("not_submit_allowed");
1327 $this->tpl->setVariable("TEXT_ALREADY_SUBMITTED", $this->lng->txt("tst_already_submitted"));
1328 $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_show_answer_sheet"));
1329 } else
1330 {
1331 $this->tpl->setCurrentBlock("submit_allowed");
1332 $this->tpl->setVariable("TEXT_CONFIRM_SUBMIT_RESULTS", $this->lng->txt("tst_confirm_submit_answers"));
1333 $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_submit_results"));
1334 }
1335 $this->tpl->setVariable("BTN_BACK", $this->lng->txt("back"));
1336 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this, "finalSubmission"));
1337 $this->tpl->parseCurrentBlock();
1338 }
1339
1340 function outProcessingTime($active_id)
1341 {
1342 global $ilUser;
1343
1344 $starting_time = $this->object->getStartingTimeOfUser($active_id);
1345 $processing_time = $this->object->getProcessingTimeInSeconds($active_id);
1346 $processing_time_minutes = floor($processing_time / 60);
1347 $processing_time_seconds = $processing_time - $processing_time_minutes * 60;
1348 $str_processing_time = "";
1349 if ($processing_time_minutes > 0)
1350 {
1351 $str_processing_time = $processing_time_minutes . " " . ($processing_time_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1352 }
1353 if ($processing_time_seconds > 0)
1354 {
1355 if (strlen($str_processing_time) > 0) $str_processing_time .= " " . $this->lng->txt("and") . " ";
1356 $str_processing_time .= $processing_time_seconds . " " . ($processing_time_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1357 }
1358 $time_left = $starting_time + $processing_time - mktime();
1359 $time_left_minutes = floor($time_left / 60);
1360 $time_left_seconds = $time_left - $time_left_minutes * 60;
1361 $str_time_left = "";
1362 if ($time_left_minutes > 0)
1363 {
1364 $str_time_left = $time_left_minutes . " " . ($time_left_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1365 }
1366 if ($time_left < 300)
1367 {
1368 if ($time_left_seconds > 0)
1369 {
1370 if (strlen($str_time_left) > 0) $str_time_left .= " " . $this->lng->txt("and") . " ";
1371 $str_time_left .= $time_left_seconds . " " . ($time_left_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1372 }
1373 }
1374 $date = getdate($starting_time);
1375 $formattedStartingTime = ilDatePresentation::formatDate(new ilDateTime($date,IL_CAL_FKT_GETDATE));
1376 /*
1377 $formattedStartingTime = ilFormat::formatDate(
1378 $date["year"]."-".
1379 sprintf("%02d", $date["mon"])."-".
1380 sprintf("%02d", $date["mday"])." ".
1381 sprintf("%02d", $date["hours"]).":".
1382 sprintf("%02d", $date["minutes"]).":".
1383 sprintf("%02d", $date["seconds"])
1384 );
1385 */
1386 $datenow = getdate();
1387 $this->tpl->setCurrentBlock("enableprocessingtime");
1388 $this->tpl->setVariable("USER_WORKING_TIME",
1389 sprintf(
1390 $this->lng->txt("tst_time_already_spent"),
1391 $formattedStartingTime,
1392 $str_processing_time
1393 )
1394 );
1395 $this->tpl->setVariable("USER_REMAINING_TIME", sprintf($this->lng->txt("tst_time_already_spent_left"), $str_time_left));
1396 $this->tpl->parseCurrentBlock();
1397 $template = new ilTemplate("tpl.workingtime.js.html", TRUE, TRUE, 'Modules/Test');
1398 $template->setVariable("STRING_MINUTE", $this->lng->txt("minute"));
1399 $template->setVariable("STRING_MINUTES", $this->lng->txt("minutes"));
1400 $template->setVariable("STRING_SECOND", $this->lng->txt("second"));
1401 $template->setVariable("STRING_SECONDS", $this->lng->txt("seconds"));
1402 $template->setVariable("STRING_TIMELEFT", $this->lng->txt("tst_time_already_spent_left"));
1403 $template->setVariable("AND", strtolower($this->lng->txt("and")));
1404 $template->setVariable("YEAR", $date["year"]);
1405 $template->setVariable("MONTH", $date["mon"]-1);
1406 $template->setVariable("DAY", $date["mday"]);
1407 $template->setVariable("HOUR", $date["hours"]);
1408 $template->setVariable("MINUTE", $date["minutes"]);
1409 $template->setVariable("SECOND", $date["seconds"]);
1410 if ($this->object->isEndingTimeEnabled() && preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->object->getEndingTime(), $matches))
1411 {
1412 $template->setVariable("ENDYEAR", $matches[1]);
1413 $template->setVariable("ENDMONTH", $matches[2]-1);
1414 $template->setVariable("ENDDAY", $matches[3]);
1415 $template->setVariable("ENDHOUR", $matches[4]);
1416 $template->setVariable("ENDMINUTE", $matches[5]);
1417 $template->setVariable("ENDSECOND", $matches[6]);
1418 }
1419 $template->setVariable("YEARNOW", $datenow["year"]);
1420 $template->setVariable("MONTHNOW", $datenow["mon"]-1);
1421 $template->setVariable("DAYNOW", $datenow["mday"]);
1422 $template->setVariable("HOURNOW", $datenow["hours"]);
1423 $template->setVariable("MINUTENOW", $datenow["minutes"]);
1424 $template->setVariable("SECONDNOW", $datenow["seconds"]);
1425 $template->setVariable("PTIME_M", $processing_time_minutes);
1426 $template->setVariable("PTIME_S", $processing_time_seconds);
1427
1428 $this->tpl->setCurrentBlock("HeadContent");
1429 $this->tpl->setVariable("CONTENT_BLOCK", $template->get());
1430 $this->tpl->parseCurrentBlock();
1431 }
1432
1433 protected function showSideList($presentationMode, $currentSequenceElement)
1434 {
1435 global $ilUser;
1436
1437 $sideListActive = $ilUser->getPref('side_list_of_questions');
1438
1439 if($sideListActive)
1440 {
1441 $this->tpl->addCss(
1442 ilUtil::getStyleSheetLocation("output", "ta_split.css", "Modules/Test"), "screen"
1443 );
1444
1445 $questionSummaryData = $this->service->getQuestionSummaryData($this->testSequence, false);
1446
1447 require_once 'Modules/Test/classes/class.ilTestQuestionSideListGUI.php';
1448 $questionSideListGUI = new ilTestQuestionSideListGUI($this->ctrl, $this->lng);
1449 $questionSideListGUI->setTargetGUI($this);
1450 $questionSideListGUI->setQuestionSummaryData($questionSummaryData);
1451 $questionSideListGUI->setCurrentSequenceElement($currentSequenceElement);
1452 $questionSideListGUI->setCurrentPresentationMode($presentationMode);
1453 $questionSideListGUI->setDisabled($presentationMode == self::PRESENTATION_MODE_EDIT);
1454 $this->tpl->setVariable('LIST_OF_QUESTIONS', $questionSideListGUI->getHTML());
1455 }
1456 }
1457
1458 abstract protected function isQuestionSummaryFinishTestButtonRequired();
1459
1463 public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = false, $obligationsNotAnswered = false, $obligationsFilter = false)
1464 {
1465 if( $fullpage )
1466 {
1467 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_question_summary.html", "Modules/Test");
1468 }
1469
1470 if( $obligationsNotAnswered )
1471 {
1472 ilUtil::sendFailure($this->lng->txt('not_all_obligations_answered'));
1473 }
1474
1475 if( $this->object->getKioskMode() && $fullpage )
1476 {
1477 $head = $this->getKioskHead();
1478 if( strlen($head) )
1479 {
1480 $this->tpl->setCurrentBlock("kiosk_options");
1481 $this->tpl->setVariable("KIOSK_HEAD", $head);
1482 $this->tpl->parseCurrentBlock();
1483 }
1484 }
1485
1486
1487 $active_id = $this->testSession->getActiveId();
1488 $questionSummaryData = $this->service->getQuestionSummaryData($this->testSequence, $obligationsFilter);
1489
1490 $this->ctrl->setParameter($this, "sequence", $_GET["sequence"]);
1491
1492 if( $fullpage )
1493 {
1494 include_once "./Modules/Test/classes/tables/class.ilListOfQuestionsTableGUI.php";
1495 $table_gui = new ilListOfQuestionsTableGUI($this, 'backFromSummary');
1496
1497 $table_gui->setShowPointsEnabled( !$this->object->getTitleOutput() );
1498 $table_gui->setShowMarkerEnabled( $this->object->getShowMarker() );
1499 $table_gui->setObligationsNotAnswered( $obligationsNotAnswered );
1500 $table_gui->setShowObligationsEnabled( $this->object->areObligationsEnabled() );
1501 $table_gui->setObligationsFilterEnabled( $obligationsFilter );
1502 $table_gui->setFinishTestButtonEnabled($this->isQuestionSummaryFinishTestButtonRequired());
1503
1504 $table_gui->init();
1505
1506 $table_gui->setData($questionSummaryData);
1507
1508 $this->tpl->setVariable('TABLE_LIST_OF_QUESTIONS', $table_gui->getHTML());
1509
1510 if( $this->object->getEnableProcessingTime() )
1511 {
1512 $this->outProcessingTime($active_id);
1513 }
1514 }
1515 }
1516
1518 {
1519 return $this->outQuestionSummaryCmd(true, true, true, false);
1520 }
1521
1523 {
1524 return $this->outQuestionSummaryCmd(true, true, true, true);
1525 }
1526
1528 {
1529 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_max_allowed_users_reached.html", "Modules/Test");
1530 $this->tpl->setCurrentBlock("adm_content");
1531 $this->tpl->setVariable("MAX_ALLOWED_USERS_MESSAGE", sprintf($this->lng->txt("tst_max_allowed_users_message"), $this->object->getAllowedUsersTimeGap()));
1532 $this->tpl->setVariable("MAX_ALLOWED_USERS_HEADING", sprintf($this->lng->txt("tst_max_allowed_users_heading"), $this->object->getAllowedUsersTimeGap()));
1533 $this->tpl->setVariable("CMD_BACK_TO_INFOSCREEN", ilTestPlayerCommands::BACK_TO_INFO_SCREEN);
1534 $this->tpl->setVariable("TXT_BACK_TO_INFOSCREEN", $this->lng->txt("tst_results_back_introduction"));
1535 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1536 $this->tpl->parseCurrentBlock();
1537 }
1538
1540 {
1541 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
1542 }
1543
1550 {
1551 $this->tpl->addBlockFile("ADM_CONTENT", "adm_content", "tpl.il_as_tst_correct_solution.html", "Modules/Test");
1552
1553 include_once("./Services/Style/classes/class.ilObjStyleSheet.php");
1554 $this->tpl->setCurrentBlock("ContentStyle");
1555 $this->tpl->setVariable("LOCATION_CONTENT_STYLESHEET", ilObjStyleSheet::getContentStylePath(0));
1556 $this->tpl->parseCurrentBlock();
1557
1558 $this->tpl->setCurrentBlock("SyntaxStyle");
1559 $this->tpl->setVariable("LOCATION_SYNTAX_STYLESHEET", ilObjStyleSheet::getSyntaxStylePath());
1560 $this->tpl->parseCurrentBlock();
1561
1562 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1563 if ($this->object->getShowSolutionAnswersOnly())
1564 {
1565 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1566 }
1567
1568 $this->tpl->setCurrentBlock("adm_content");
1569 $solution = $this->getCorrectSolutionOutput($_GET["evaluation"], $_GET["active_id"], $_GET["pass"]);
1570 $this->tpl->setVariable("OUTPUT_SOLUTION", $solution);
1571 $this->tpl->setVariable("TEXT_BACK", $this->lng->txt("back"));
1572 $this->ctrl->saveParameter($this, "pass");
1573 $this->ctrl->saveParameter($this, "active_id");
1574 $this->tpl->setVariable("URL_BACK", $this->ctrl->getLinkTarget($this, "outUserResultsOverview"));
1575 $this->tpl->parseCurrentBlock();
1576 }
1577
1587 function showListOfAnswers($active_id, $pass = NULL, $top_data = "", $bottom_data = "")
1588 {
1589 global $ilUser;
1590
1591 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_finish_list_of_answers.html", "Modules/Test");
1592
1593 $result_array =& $this->object->getTestResult(
1594 $active_id, $pass, false, !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
1595 );
1596
1597 $counter = 1;
1598 // output of questions with solutions
1599 foreach ($result_array as $question_data)
1600 {
1601 $question = $question_data["qid"];
1602 if (is_numeric($question))
1603 {
1604 $this->tpl->setCurrentBlock("printview_question");
1605 $question_gui = $this->object->createQuestionGUI("", $question);
1606 $template = new ilTemplate("tpl.il_as_qpl_question_printview.html", TRUE, TRUE, "Modules/TestQuestionPool");
1607 $template->setVariable("COUNTER_QUESTION", $counter.". ");
1608 $template->setVariable("QUESTION_TITLE", $question_gui->object->getTitle());
1609
1610 $show_question_only = ($this->object->getShowSolutionAnswersOnly()) ? TRUE : FALSE;
1611 $result_output = $question_gui->getSolutionOutput($active_id, $pass, FALSE, FALSE, $show_question_only, $this->object->getShowSolutionFeedback());
1612 $template->setVariable("SOLUTION_OUTPUT", $result_output);
1613 $this->tpl->setVariable("QUESTION_OUTPUT", $template->get());
1614 $this->tpl->parseCurrentBlock();
1615 $counter ++;
1616 }
1617 }
1618
1619 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1620 if ($this->object->getShowSolutionAnswersOnly())
1621 {
1622 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1623 }
1624 if (strlen($top_data))
1625 {
1626 $this->tpl->setCurrentBlock("top_data");
1627 $this->tpl->setVariable("TOP_DATA", $top_data);
1628 $this->tpl->parseCurrentBlock();
1629 }
1630
1631 if (strlen($bottom_data))
1632 {
1633 $this->tpl->setCurrentBlock("bottom_data");
1634 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1635 $this->tpl->setVariable("BOTTOM_DATA", $bottom_data);
1636 $this->tpl->parseCurrentBlock();
1637 }
1638
1639 $this->tpl->setCurrentBlock("adm_content");
1640 $this->tpl->setVariable("TXT_ANSWER_SHEET", $this->lng->txt("tst_list_of_answers"));
1641 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($this->testSession, $active_id, TRUE);
1642 $signature = $this->getResultsSignature();
1643 $this->tpl->setVariable("USER_DETAILS", $user_data);
1644 $this->tpl->setVariable("SIGNATURE", $signature);
1645 $this->tpl->setVariable("TITLE", $this->object->getTitle());
1646 $this->tpl->setVariable("TXT_TEST_PROLOG", $this->lng->txt("tst_your_answers"));
1647 $invited_user =& $this->object->getInvitedUsers($ilUser->getId());
1648 $pagetitle = $this->object->getTitle() . " - " . $this->lng->txt("clientip") .
1649 ": " . $invited_user[$ilUser->getId()]["clientip"] . " - " .
1650 $this->lng->txt("matriculation") . ": " .
1651 $invited_user[$ilUser->getId()]["matriculation"];
1652 $this->tpl->setVariable("PAGETITLE", $pagetitle);
1653 $this->tpl->parseCurrentBlock();
1654 }
1655
1661 public function getContentBlockName()
1662 {
1663 if ($this->object->getKioskMode())
1664 {
1665 $this->tpl->setBodyClass("kiosk");
1666 $this->tpl->setAddFooter(FALSE);
1667 return "CONTENT";
1668 }
1669 else
1670 {
1671 return "ADM_CONTENT";
1672 }
1673 }
1674
1676 {
1677 $this->ctrl->redirectByClass(
1678 array('ilRepositoryGUI', 'ilObjTestGUI', 'ilTestEvaluationGUI'), "outUserResultsOverview"
1679 );
1680 }
1681
1685 protected function showRequestedHintListCmd()
1686 {
1687 $this->saveQuestionSolution(false);
1688
1689 $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_EDIT);
1690
1691 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1692 $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_SHOW_LIST);
1693 }
1694
1698 protected function confirmHintRequestCmd()
1699 {
1700 $this->saveQuestionSolution(false);
1701
1702 $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_EDIT);
1703
1704 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1705 $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_CONFIRM_REQUEST);
1706 }
1707
1708 abstract protected function isFirstQuestionInSequence($sequenceElement);
1709
1710 abstract protected function isLastQuestionInSequence($sequenceElement);
1711
1712
1713 abstract protected function handleQuestionActionCmd();
1714
1715 abstract protected function showInstantResponseCmd();
1716
1717 abstract protected function nextQuestionCmd();
1718
1719 abstract protected function previousQuestionCmd();
1720
1721 protected function prepareSummaryPage()
1722 {
1723 $this->tpl->addBlockFile(
1724 $this->getContentBlockName(), 'adm_content', 'tpl.il_as_tst_question_summary.html', 'Modules/Test'
1725 );
1726
1727 if ($this->object->getKioskMode())
1728 {
1729 $this->populateKioskHead();
1730 }
1731 }
1732
1733 protected function initTestPageTemplate()
1734 {
1735 $this->tpl->addBlockFile(
1736 $this->getContentBlockName(), 'adm_content', 'tpl.il_as_tst_output.html', 'Modules/Test'
1737 );
1738 }
1739
1740 protected function populateKioskHead()
1741 {
1742 ilUtil::sendInfo(); // ???
1743
1744 $head = $this->getKioskHead();
1745
1746 if (strlen($head))
1747 {
1748 $this->tpl->setCurrentBlock("kiosk_options");
1749 $this->tpl->setVariable("KIOSK_HEAD", $head);
1750 $this->tpl->parseCurrentBlock();
1751 }
1752 }
1753
1755 {
1756 if( $this->ctrl->getNextClass() == 'iltestpasswordprotectiongui' )
1757 {
1758 return;
1759 }
1760
1761 if( !$this->passwordChecker->isPasswordProtectionPageRedirectRequired() )
1762 {
1763 return;
1764 }
1765
1766 $this->ctrl->setParameter($this, 'lock', $this->getLockParameter());
1767
1768 $nextCommand = $this->ctrl->getCmdClass().'::'.$this->ctrl->getCmd();
1769 $this->ctrl->setParameterByClass('ilTestPasswordProtectionGUI', 'nextCommand', $nextCommand);
1770 $this->ctrl->redirectByClass('ilTestPasswordProtectionGUI', 'showPasswordForm');
1771 }
1772
1773 protected function isParticipantsAnswerFixed($questionId)
1774 {
1775 if( !$this->object->isInstantFeedbackAnswerFixationEnabled() )
1776 {
1777 return false;
1778 }
1779
1780 if( !$this->testSequence->isQuestionChecked($questionId) )
1781 {
1782 return false;
1783 }
1784
1785 return true;
1786 }
1787
1792 {
1793 return $this->lng->txt("save_introduction");
1794 }
1795
1796 protected function initAssessmentSettings()
1797 {
1798 $this->assSettings = new ilSetting('assessment');
1799 }
1800
1805 {
1806 $questionList = $this->buildTestPassQuestionList();
1807 $questionList->load();
1808
1809 $testResults = $this->object->getTestResult($testSession->getActiveId(), $testSession->getPass(), true);
1810
1811 require_once 'Modules/Test/classes/class.ilTestSkillEvaluation.php';
1812 $skillEvaluation = new ilTestSkillEvaluation($this->db, $this->object->getTestId(), $this->object->getRefId());
1813
1814 $skillEvaluation->setUserId($testSession->getUserId());
1815 $skillEvaluation->setActiveId($testSession->getActiveId());
1816 $skillEvaluation->setPass($testSession->getPass());
1817
1818 $skillEvaluation->setNumRequiredBookingsForSkillTriggering($this->assSettings->get(
1820 ));
1821
1822
1823 $skillEvaluation->init($questionList);
1824 $skillEvaluation->evaluate($testResults);
1825
1826 $skillEvaluation->handleSkillTriggering();
1827 }
1828
1829 abstract protected function buildTestPassQuestionList();
1830
1832 {
1833 require_once 'Modules/Test/classes/confirmations/class.ilTestAnswerOptionalQuestionsConfirmationGUI.php';
1834 $confirmation = new ilTestAnswerOptionalQuestionsConfirmationGUI($this->lng);
1835
1836 $confirmation->setFormAction($this->ctrl->getFormAction($this));
1837 $confirmation->setCancelCmd('cancelAnswerOptionalQuestions');
1838 $confirmation->setConfirmCmd('confirmAnswerOptionalQuestions');
1839
1840 $confirmation->build($this->object->isFixedTest());
1841
1842 $this->populateHelperGuiContent($confirmation);
1843 }
1844
1846 {
1847 $this->testSequence->setAnsweringOptionalQuestionsConfirmed(true);
1848 $this->testSequence->saveToDb();
1849
1850 $this->ctrl->setParameter($this, 'activecommand', 'gotoquestion');
1851 $this->ctrl->redirect($this, 'redirectQuestion');
1852 }
1853
1855 {
1856 if( $this->object->getListOfQuestions() )
1857 {
1858 $this->ctrl->setParameter($this, 'activecommand', 'summary');
1859 }
1860 else
1861 {
1862 $this->ctrl->setParameter($this, 'activecommand', 'previous');
1863 }
1864
1865 $this->ctrl->redirect($this, 'redirectQuestion');
1866 }
1867
1871 protected function populateHelperGuiContent($helperGui)
1872 {
1873 if($this->object->getKioskMode())
1874 {
1875 $this->tpl->addBlockfile($this->getContentBlockName(), 'content', "tpl.il_as_tst_kiosk_mode_content.html", "Modules/Test");
1876 $this->tpl->setContent($this->ctrl->getHTML($helperGui));
1877 }
1878 else
1879 {
1880 $this->tpl->setVariable($this->getContentBlockName(), $this->ctrl->getHTML($helperGui));
1881 }
1882 }
1883
1888 {
1889 global $ilSetting;
1890
1891 if ($ilSetting->get('char_selector_availability') > 0)
1892 {
1893 require_once 'Services/UIComponent/CharSelector/classes/class.ilCharSelectorGUI.php';
1894 $char_selector = ilCharSelectorGUI::_getCurrentGUI($this->object);
1895 if ($char_selector->getConfig()->getAvailability() == ilCharSelectorConfig::ENABLED)
1896 {
1897 $char_selector->addToPage();
1898 $this->tpl->setCurrentBlock('char_selector');
1899 $this->tpl->setVariable("CHAR_SELECTOR_TEMPLATE", $char_selector->getSelectorHtml());
1900 $this->tpl->parseCurrentBlock();
1901
1902 return true;
1903 }
1904 }
1905
1906 return false;
1907 }
1908
1909 protected function getTestNavigationToolbarGUI()
1910 {
1911 global $ilUser;
1912
1913 require_once 'Modules/Test/classes/class.ilTestNavigationToolbarGUI.php';
1914 $navigationToolbarGUI = new ilTestNavigationToolbarGUI($this->ctrl, $this->lng, $this);
1915
1916 $navigationToolbarGUI->setSuspendTestButtonEnabled($this->object->getShowCancel());
1917 $navigationToolbarGUI->setQuestionTreeButtonEnabled($this->object->getListOfQuestions());
1918 $navigationToolbarGUI->setQuestionTreeVisible($ilUser->getPref('side_list_of_questions'));
1919 $navigationToolbarGUI->setQuestionListButtonEnabled($this->object->getListOfQuestions());
1920 $navigationToolbarGUI->setFinishTestCommand($this->getFinishTestCommand());
1921
1922 return $navigationToolbarGUI;
1923 }
1924
1925 protected function buildReadOnlyStateQuestionNavigationGUI($questionId)
1926 {
1927 require_once 'Modules/Test/classes/class.ilTestQuestionNavigationGUI.php';
1928 $navigationGUI = new ilTestQuestionNavigationGUI($this->lng);
1929
1930 if( !$this->isParticipantsAnswerFixed($questionId) )
1931 {
1932 $navigationGUI->setEditSolutionCommand(ilTestPlayerCommands::EDIT_SOLUTION);
1933 }
1934
1935 if($this->object->getShowMarker())
1936 {
1937 include_once "./Modules/Test/classes/class.ilObjTest.php";
1938 $solved_array = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId(), $questionId);
1939 $solved = 0;
1940
1941 if(count($solved_array) > 0)
1942 {
1943 $solved = array_pop($solved_array);
1944 $solved = $solved["solved"];
1945 }
1946
1947 if($solved == 1)
1948 {
1949 $navigationGUI->setQuestionMarkCommand(ilTestPlayerCommands::UNMARK_QUESTION);
1950 $navigationGUI->setQuestionMarked(true);
1951 }
1952 else
1953 {
1954 $navigationGUI->setQuestionMarkCommand(ilTestPlayerCommands::MARK_QUESTION);
1955 $navigationGUI->setQuestionMarked(false);
1956 }
1957 }
1958
1959 return $navigationGUI;
1960 }
1961
1962 protected function buildEditableStateQuestionNavigationGUI($questionId, $charSelectorAvailable)
1963 {
1964 require_once 'Modules/Test/classes/class.ilTestQuestionNavigationGUI.php';
1965 $navigationGUI = new ilTestQuestionNavigationGUI($this->lng);
1966
1967 if( $this->object->isForceInstantFeedbackEnabled() )
1968 {
1969 $navigationGUI->setSubmitSolutionCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
1970 }
1971 else
1972 {
1973 $navigationGUI->setSubmitSolutionCommand(ilTestPlayerCommands::SUBMIT_SOLUTION_AND_NEXT);
1974 }
1975
1976
1977 // feedback
1978 switch( 1 )
1979 {
1980 case $this->object->getSpecificAnswerFeedback():
1981 case $this->object->getGenericAnswerFeedback():
1982 case $this->object->getAnswerFeedbackPoints():
1983 case $this->object->getInstantFeedbackSolution():
1984
1985 $navigationGUI->setAnswerFreezingEnabled($this->object->isInstantFeedbackAnswerFixationEnabled());
1986
1987 if( $this->object->isForceInstantFeedbackEnabled() )
1988 {
1989 $navigationGUI->setForceInstantResponseEnabled(true);
1990 $navigationGUI->setInstantFeedbackCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
1991 }
1992 else
1993 {
1994 $navigationGUI->setInstantFeedbackCommand(ilTestPlayerCommands::SHOW_INSTANT_RESPONSE);
1995 }
1996 }
1997
1998 // hints
1999 if( $this->object->isOfferingQuestionHintsEnabled() )
2000 {
2001 $activeId = $this->testSession->getActiveId();
2002 $pass = $this->testSession->getPass();
2003
2004 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
2005 $questionHintTracking = new ilAssQuestionHintTracking($questionId, $activeId, $pass);
2006
2007 if( $questionHintTracking->requestsPossible() )
2008 {
2009 $navigationGUI->setRequestHintCommand(ilTestPlayerCommands::CONFIRM_HINT_REQUEST);
2010 }
2011
2012 if( $questionHintTracking->requestsExist() )
2013 {
2014 $navigationGUI->setShowHintsCommand(ilTestPlayerCommands::SHOW_REQUESTED_HINTS_LIST);
2015 }
2016 }
2017
2018 $navigationGUI->setCharSelectorEnabled($charSelectorAvailable);
2019
2020 if($this->object->getShowMarker())
2021 {
2022 include_once "./Modules/Test/classes/class.ilObjTest.php";
2023 $solved_array = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId(), $questionId);
2024 $solved = 0;
2025
2026 if(count($solved_array) > 0)
2027 {
2028 $solved = array_pop($solved_array);
2029 $solved = $solved["solved"];
2030 }
2031
2032 if($solved == 1)
2033 {
2034 $navigationGUI->setQuestionMarkCommand(ilTestPlayerCommands::UNMARK_QUESTION_SAVE);
2035 $navigationGUI->setQuestionMarked(true);
2036 }
2037 else
2038 {
2039 $navigationGUI->setQuestionMarkCommand(ilTestPlayerCommands::MARK_QUESTION_SAVE);
2040 $navigationGUI->setQuestionMarked(false);
2041 }
2042 }
2043
2044 return $navigationGUI;
2045 }
2046
2050 protected function getFinishTestCommand()
2051 {
2052 if( !$this->object->getListOfQuestionsEnd() )
2053 {
2054 return 'finishTest';
2055 }
2056
2057 if( $this->object->areObligationsEnabled() )
2058 {
2059 $allObligationsAnswered = ilObjTest::allObligationsAnswered(
2060 $this->testSession->getTestId(), $this->testSession->getActiveId(), $this->testSession->getPass()
2061 );
2062
2063 if( !$allObligationsAnswered )
2064 {
2065 return 'outQuestionSummaryWithObligationsInfo';
2066 }
2067 }
2068
2069 return 'outQuestionSummary';
2070 }
2071
2075 protected function populateIntermediateSolutionSaver(assQuestionGUI $questionGui)
2076 {
2077 $this->tpl->addJavaScript(ilUtil::getJSLocation("autosave.js", "Modules/Test"));
2078
2079 $this->tpl->setVariable("AUTOSAVE_URL", $this->ctrl->getFormAction(
2080 $this, ilTestPlayerCommands::AUTO_SAVE, "", true
2081 ));
2082
2083 if( $questionGui->isAutosaveable() && $this->object->getAutosave() )
2084 {
2085 $formAction = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AUTO_SAVE, '', false, false);
2086
2087 $this->tpl->touchBlock('autosave');
2088 $this->tpl->setVariable("AUTOSAVEFORMACTION", $formAction);
2089 $this->tpl->setVariable("AUTOSAVEINTERVAL", $this->object->getAutosaveIval());
2090 }
2091 }
2092
2096 protected function populateInstantResponseBlocks(assQuestionGUI $questionGui, $authorizedSolution)
2097 {
2098 // This controls if the solution should be shown.
2099 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
2100 if($this->object->getInstantFeedbackSolution())
2101 {
2102 $show_question_inline_score = $this->determineInlineScoreDisplay();
2103
2104 // Notation of the params prior to getting rid of this crap in favor of a class
2105 $solutionoutput = $questionGui->getSolutionOutput($this->testSession->getActiveId(), #active_id
2106 $this->testSession->getPass(), #pass
2107 FALSE, #graphical_output
2108 $show_question_inline_score, #result_output
2109 FALSE, #show_question_only
2110 FALSE, #show_feedback
2111 TRUE, #show_correct_solution
2112 FALSE, #show_manual_scoring
2113 FALSE #show_question_text
2114 );
2115 $this->populateSolutionBlock($solutionoutput);
2116 }
2117
2118 $reachedPoints = $questionGui->object->getAdjustedReachedPoints(
2119 $this->testSession->getActiveId(), NULL, $authorizedSolution
2120 );
2121
2122 $maxPoints = $questionGui->object->getMaximumPoints();
2123
2124 $solutionCorrect = ($reachedPoints == $maxPoints);
2125
2126 // This controls if the score should be shown.
2127 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Results (Only Points)"
2128 if($this->object->getAnswerFeedbackPoints())
2129 {
2130 $this->populateScoreBlock($reachedPoints, $maxPoints);
2131 }
2132
2133 // This controls if the generic feedback should be shown.
2134 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
2135 if($this->object->getGenericAnswerFeedback())
2136 {
2137 $this->populateGenericFeedbackBlock($questionGui, $solutionCorrect);
2138 }
2139
2140 // This controls if the specific feedback should be shown.
2141 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Answer-Specific Feedback"
2142 if($this->object->getSpecificAnswerFeedback())
2143 {
2144 $this->populateSpecificFeedbackBlock($questionGui);
2145 }
2146 }
2147
2148 protected function getCurrentSequenceElement()
2149 {
2150 if( $this->getSequenceElementParameter() )
2151 {
2152 return $this->getSequenceElementParameter();
2153 }
2154
2155 return $this->testSession->getLastSequence();
2156 }
2157
2158 protected function getSequenceElementParameter()
2159 {
2160 if( isset($_GET['sequence']) )
2161 {
2162 return $_GET['sequence'];
2163 }
2164
2165 return null;
2166 }
2167
2168 protected function getPresentationModeParameter()
2169 {
2170 if( isset($_GET['pmode']) )
2171 {
2172 return $_GET['pmode'];
2173 }
2174
2175 return null;
2176 }
2177
2178 protected function getInstantResponseParameter()
2179 {
2180 if( isset($_GET['instresp']) )
2181 {
2182 return $_GET['instresp'];
2183 }
2184
2185 return null;
2186 }
2187
2188 protected function getNextCommandParameter()
2189 {
2190 if( isset($_POST['nextcmd']) && strlen($_POST['nextcmd']) )
2191 {
2192 return $_POST['nextcmd'];
2193 }
2194
2195 return null;
2196 }
2197
2198 protected function getNextSequenceParameter()
2199 {
2200 if( isset($_POST['nextseq']) && is_numeric($_POST['nextseq']) )
2201 {
2202 return (int)$_POST['nextseq'];
2203 }
2204
2205 return null;
2206 }
2207
2211 private $cachedQuestionGuis = array();
2212
2218 protected function getQuestionGuiInstance($questionId, $fromCache = true)
2219 {
2220 if( !$fromCache || !isset($this->cachedQuestionGuis[$questionId]) )
2221 {
2222 $questionGui = $this->object->createQuestionGUI("", $questionId);
2223 $questionGui->setTargetGui($this);
2224 $questionGui->setPresentationContext(assQuestionGUI::PRESENTATION_CONTEXT_TEST);
2225 $questionGui->object->setObligationsToBeConsidered($this->object->areObligationsEnabled());
2226 $questionGui->object->setOutputType(OUTPUT_JAVASCRIPT);
2227 $questionGui->object->setShuffler($this->buildQuestionAnswerShuffler($questionId));
2228
2229 $this->cachedQuestionGuis[$questionId] = $questionGui;
2230 }
2231
2232 return $this->cachedQuestionGuis[$questionId];
2233 }
2234
2238 private $cachedQuestionObjects = array();
2239
2244 protected function getQuestionInstance($questionId, $fromCache = true)
2245 {
2246 global $ilDB, $ilUser;
2247
2248 if( !$fromCache || !isset($this->cachedQuestionObjects[$questionId]) )
2249 {
2250 $questionOBJ = assQuestion::_instantiateQuestion($questionId);
2251
2252 $assSettings = new ilSetting('assessment');
2253 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
2254 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
2255 $processLockerFactory->setQuestionId($questionOBJ->getId());
2256 $processLockerFactory->setUserId($ilUser->getId());
2257 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
2258 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
2259 $questionOBJ->setProcessLocker($processLockerFactory->getLocker());
2260
2261 $questionOBJ->setObligationsToBeConsidered($this->object->areObligationsEnabled());
2262 $questionOBJ->setOutputType(OUTPUT_JAVASCRIPT);
2263
2264 $this->cachedQuestionObjects[$questionId] = $questionOBJ;
2265 }
2266
2267 return $this->cachedQuestionObjects[$questionId];
2268 }
2269
2274 protected function buildQuestionAnswerShuffler($questionId)
2275 {
2276 require_once 'Services/Randomization/classes/class.ilArrayElementShuffler.php';
2277 $shuffler = new ilArrayElementShuffler();
2278
2279 $shuffler->setSeed(
2280 $questionId.$this->testSession->getActiveId().$this->testSession->getPass()
2281 );
2282
2283 return $shuffler;
2284 }
2285
2291 protected function handleTearsAndAngerQuestionIsNull($questionId, $sequenceElement)
2292 {
2293 global $ilLog;
2294
2295 $ilLog->write("INV SEQ:"
2296 ."active={$this->testSession->getActiveId()} "
2297 ."qId=$questionId seq=$sequenceElement "
2298 . serialize($this->testSequence)
2299 );
2300
2301 $ilLog->logStack('INV SEQ');
2302
2303 $this->ctrl->setParameter($this, 'sequence', $this->testSequence->getFirstSequence());
2304 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
2305 }
2306
2310 protected function populateMessageContent($contentHTML)
2311 {
2312 if($this->object->getKioskMode())
2313 {
2314 $this->tpl->addBlockfile($this->getContentBlockName(), 'content', "tpl.il_as_tst_kiosk_mode_content.html", "Modules/Test");
2315 $this->tpl->setContent($contentHTML);
2316 }
2317 else
2318 {
2319 $this->tpl->setVariable($this->getContentBlockName(), $contentHTML);
2320 }
2321 }
2322
2323 protected function populateModals()
2324 {
2325 require_once 'Services/UIComponent/Button/classes/class.ilSubmitButton.php';
2326 require_once 'Services/UIComponent/Button/classes/class.ilLinkButton.php';
2327 require_once 'Services/UIComponent/Modal/classes/class.ilModalGUI.php';
2328
2331
2332 if( $this->object->getKioskMode() )
2333 {
2334 $this->tpl->addJavaScript('Services/UICore/lib/bootstrap-3.2.0/dist/js/bootstrap.min.js', true);
2335 }
2336 }
2337
2338 protected function populateDiscardSolutionModal()
2339 {
2340 $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2341
2342 $tpl->setVariable('CONFIRMATION_TEXT', $this->lng->txt('discard_answer_confirmation'));
2343
2344 $button = ilSubmitButton::getInstance();
2345 $button->setCommand(ilTestPlayerCommands::DISCARD_SOLUTION);
2346 $button->setCaption('yes');
2347 $tpl->setCurrentBlock('buttons');
2348 $tpl->setVariable('BUTTON', $button->render());
2349 $tpl->parseCurrentBlock();
2350
2351 $button = ilLinkButton::getInstance();
2352 $button->setId('tst_cancel_discard_button');
2353 $button->setCaption('no');
2354 $button->setPrimary(true);
2355 $tpl->setCurrentBlock('buttons');
2356 $tpl->setVariable('BUTTON', $button->render());
2357 $tpl->parseCurrentBlock();
2358
2359 $modal = ilModalGUI::getInstance();
2360 $modal->setId('tst_discard_solution_modal');
2361 $modal->setHeading($this->lng->txt('discard_answer'));
2362 $modal->setBody($tpl->get());
2363
2364 $this->tpl->setCurrentBlock('discard_solution_modal');
2365 $this->tpl->setVariable('DISCARD_SOLUTION_MODAL', $modal->getHTML());
2366 $this->tpl->parseCurrentBlock();
2367
2368 $this->tpl->addJavaScript('Modules/Test/js/ilTestPlayerDiscardSolutionModal.js', true);
2369 }
2370
2371 protected function populateNavWhileEditModal()
2372 {
2373 require_once 'Services/Form/classes/class.ilFormPropertyGUI.php';
2374 require_once 'Services/Form/classes/class.ilHiddenInputGUI.php';
2375
2376 $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2377
2378 $tpl->setVariable('CONFIRMATION_TEXT', $this->lng->txt('tst_nav_while_edit_modal_text'));
2379
2380 $button = ilSubmitButton::getInstance();
2381 $button->setCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2382 $button->setCaption('tst_nav_while_edit_modal_save_btn');
2383 $button->setPrimary(true);
2384 $tpl->setCurrentBlock('buttons');
2385 $tpl->setVariable('BUTTON', $button->render());
2386 $tpl->parseCurrentBlock();
2387
2388 foreach(array('nextcmd', 'nextseq') as $hiddenPostVar)
2389 {
2390 $nextCmdInp = new ilHiddenInputGUI($hiddenPostVar);
2391 $nextCmdInp->setValue('');
2392 $tpl->setCurrentBlock('hidden_inputs');
2393 $tpl->setVariable('HIDDEN_INPUT', $nextCmdInp->getToolbarHTML());
2394 $tpl->parseCurrentBlock();
2395 }
2396
2397 $button = ilLinkButton::getInstance();
2398 $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_VIEW);
2399 $button->setId('nextCmdLink');
2400 $button->setUrl('#');
2401 $this->ctrl->setParameter($this, 'pmode', $this->getPresentationModeParameter());
2402 $button->setCaption('tst_nav_while_edit_modal_nosave_btn');
2403 $tpl->setCurrentBlock('buttons');
2404 $tpl->setVariable('BUTTON', $button->render());
2405 $tpl->parseCurrentBlock();
2406
2407 $button = ilLinkButton::getInstance();
2408 $button->setId('tst_cancel_nav_while_edit_button');
2409 $button->setCaption('tst_nav_while_edit_modal_cancel_btn');
2410 $tpl->setCurrentBlock('buttons');
2411 $tpl->setVariable('BUTTON', $button->render());
2412 $tpl->parseCurrentBlock();
2413
2414 $modal = ilModalGUI::getInstance();
2415 $modal->setId('tst_nav_while_edit_modal');
2416 $modal->setHeading($this->lng->txt('tst_nav_while_edit_modal_header'));
2417 $modal->setBody($tpl->get());
2418
2419 $this->tpl->setCurrentBlock('nav_while_edit_modal');
2420 $this->tpl->setVariable('NAV_WHILE_EDIT_MODAL', $modal->getHTML());
2421 $this->tpl->parseCurrentBlock();
2422
2423 $this->tpl->addJavaScript('Modules/Test/js/ilTestPlayerNavWhileEditModal.js', true);
2424 }
2425
2426 protected function getQuestionsDefaultPresentationMode($isQuestionWorkedThrough)
2427 {
2428 if( $isQuestionWorkedThrough )
2429 {
2431 }
2432
2434 }
2435}
$result
print $file
$filename
Definition: buildRTE.php:89
$_GET["client_id"]
$_SESSION["AccountId"]
const IL_COMP_MODULE
const IL_CAL_FKT_GETDATE
Basic GUI class for assessment questions.
setNavigationGUI($navigationGUI)
getSolutionOutput( $active_id, $pass=NULL, $graphicalOutput=FALSE, $result_output=FALSE, $show_question_only=TRUE, $show_feedback=FALSE, $show_correct_solution=FALSE, $show_manual_scoring=FALSE, $show_question_text=TRUE)
outQuestionForTest( $formaction, $active_id, $pass, $is_question_postponed=FALSE, $user_post_solutions=FALSE, $show_specific_inline_feedback=FALSE)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="")
output question page
setPreviousSolutionPrefilled($previousSolutionPrefilled)
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
static _instantiateQuestion($question_id)
static _getCurrentGUI(ilObjTest $a_test_obj=null)
Get the GUI that is used for the currently available selector (other GUI instances may exist for conf...
Confirmation screen class.
static formatDate(ilDateTime $date)
Format a date @access public.
@classDescription Date and time handling
ftimestamp2datetimeDB($aTimestamp)
Timestamp to database datetime.
This class represents a hidden form property in a property form.
static getInstance(ilTestSession $a_test_session)
static getInstance()
Factory.
static getInstance()
Get instance.
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
getContentStylePath($a_style_id)
get content style path
getSyntaxStylePath()
get syntax style path
_getUsePreviousAnswers($active_id, $user_active_user_setting=false)
Returns if the previous results should be hidden for a learner.
_getSolvedQuestions($active_id, $question_fi=null)
get solved questions
static allObligationsAnswered($test_id, $active_id, $pass)
checks wether all questions marked as obligatory were answered within the test pass with given testId...
static buildExamId($active_id, $pass, $test_obj_id=null)
lookupExamId($active_id, $pass)
static getIdleValue($fixedMode=false)
Returns the idle time in seconds.
static get($a_var)
Get a value.
ILIAS Setting Class.
static getInstance()
Factory.
Class ilTaggingGUI.
special template class to simplify handling of ITX/PEAR
Class ilTestArchiver.
Output class for assessment test evaluation.
static generatePDF($pdf_output, $output_mode, $filename=null)
Output class for assessment test execution.
handleSkillTriggering(ilTestSession $testSession)
isShowingPostponeStatusReguired($questionId)
saveTagsCmd()
Save tags for tagging gui.
showListOfAnswers($active_id, $pass=NULL, $top_data="", $bottom_data="")
Creates an output of the list of answers for a test participant during the test (only the actual pass...
confirmHintRequestCmd()
Go to hint request confirmation.
__construct($a_object)
ilTestOutputGUI constructor
confirmFinishCmd()
The final submission of a test was confirmed.
buildEditableStateQuestionNavigationGUI($questionId, $charSelectorAvailable)
populateQuestionNavigation($sequenceElement, $disabled)
startPlayerCmd()
Start a test for the first time.
populateIntermediateSolutionSaver(assQuestionGUI $questionGui)
prepareTestPage($presentationMode, $sequenceElement, $questionId)
isOptionalQuestionAnsweringConfirmationRequired($sequenceElement)
handleTearsAndAngerQuestionIsNull($questionId, $sequenceElement)
getQuestionInstance($questionId, $fromCache=true)
saveQuestionSolution($authorized=true, $force=false)
saves the user input of a question
isFirstQuestionInSequence($sequenceElement)
populateGenericFeedbackBlock(assQuestionGUI $question_gui, $solutionCorrect)
unmarkQuestionCmd()
Set a question unsolved.
showSideList($presentationMode, $currentSequenceElement)
initTestCmd()
Start a test for the first time after a redirect.
endingTimeReached()
handle endingTimeReached
maxProcessingTimeReached()
Outputs a message when the maximum processing time is reached.
showQuestionEditable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
getQuestionGuiInstance($questionId, $fromCache=true)
resumePlayerCmd()
Resume a test at the last position.
confirmSubmitAnswers()
confirm submit results if confirm then results are submitted and the screen will be redirected to the...
ensureExistingTestSession(ilTestSession $testSession)
populateScoreBlock($reachedPoints, $maxPoints)
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)
getQuestionsDefaultPresentationMode($isQuestionWorkedThrough)
outCorrectSolution()
Creates an output of the solution of an answer compared to the correct solution.
finishTestCmd($requires_confirmation=true)
markQuestionCmd()
Set a question solved.
populateTestNavigationToolbar(ilTestNavigationToolbarGUI $toolbarGUI)
isTestSignRedirectRequired($activeId, $lastFinishedPass)
determineSolutionPassIndex(assQuestionGUI $questionGui)
showRequestedHintListCmd()
Go to requested hint list.
isMaxProcessingTimeReached()
Checks wheather the maximum processing time is reached or not.
setAnonymousIdCmd()
Sets a session variable with the test access code for an anonymous test user.
isLastQuestionInSequence($sequenceElement)
checkOnlineTestAccess()
check access restrictions like client ip, partipating user etc.
isTestAccessible()
test accessible returns true if the user can perform the test
showQuestionViewable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
getContentBlockName()
Returns the name of the current content block (depends on the kiosk mode setting)
outQuestionSummaryCmd($fullpage=true, $contextFinishTest=false, $obligationsNotAnswered=false, $obligationsFilter=false)
Output of a summary of all test questions for test participants.
Service GUI class for tests.
getCorrectSolutionOutput($question_id, $active_id, $pass, ilTestQuestionRelatedObjectivesList $objectivesList=null)
Returns an output of the solution to an answer compared to the correct solution.
getResultsSignature()
Returns HTML code for a signature field.
getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, $overwrite_anonymity=FALSE)
Returns the user data for a test results output.
buildQuestionRelatedObjectivesList(ilLOTestQuestionAdapter $objectivesAdapter, ilTestQuestionSequence $testSequence)
Test session handler.
static getJSLocation($a_js_name, $a_js_location="", $add_version=FALSE)
get full javascript file name (path inclusive) of current user
static getWebspaceDir($mode="filesystem")
get webspace directory
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
static redirect($a_script)
http redirect to other script
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
$_POST['username']
Definition: cron.php:12
$GLOBALS['PHPCAS_CLIENT']
This global variable is used by the interface class phpCAS.
Definition: CAS.php:276
const OUTPUT_JAVASCRIPT
const REDIRECT_KIOSK
exit
Definition: login.php:54
redirection script todo: (a better solution should control the processing via a xml file)
global $ilSetting
Definition: privfeed.php:40
$results
$url
Definition: shib_logout.php:72
$path
Definition: index.php:22
global $ilDB
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
global $ilUser
Definition: imgupload.php:15