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