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