ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilObjTestGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
30 use ILIAS\Style\Content\Service as ContentStyle;
31 
32 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
33 
76 {
77  private static $infoScreenChildClasses = [
78  'ilpublicuserprofilegui', 'ilobjportfoliogui'
79  ];
80 
85  private \ILIAS\Filesystem\Util\Archive\LegacyArchives $archives;
92  protected ilDBInterface $db;
94  protected ContentStyle $content_style;
97  protected HTTPServices $http;
98  protected ilHelpGUI $help;
103 
104  protected bool $create_question_mode;
105 
106  protected const INSERT_MODE_BEFORE = 0;
107  protected const INSERT_MODE_AFTER = 1;
108 
114  public function __construct($refId = null)
115  {
117  global $DIC;
118  $this->navigation_history = $DIC['ilNavigationHistory'];
119  $this->component_repository = $DIC['component.repository'];
120  $this->component_factory = $DIC['component.factory'];
121  $this->ui_factory = $DIC['ui.factory'];
122  $this->ui_renderer = $DIC['ui.renderer'];
123  $this->http = $DIC['http'];
124  $this->error = $DIC['ilErr'];
125  $this->db = $DIC['ilDB'];
126  $this->logging_services = $DIC->logger();
127  $this->help = $DIC['ilHelp'];
128  $this->global_screen = $DIC['global_screen'];
129  $this->obj_data_cache = $DIC['ilObjDataCache'];
130  $this->skills_service = $DIC->skills();
131  $this->questioninfo = $DIC->testQuestionPool()->questionInfo();
132  $this->type = 'tst';
133  $this->testrequest = $DIC->test()->internal()->request();
134  $this->archives = $DIC->legacyArchives();
135  $this->content_style = $DIC->contentStyle();
136 
137  $ref_id = 0;
138  if ($this->testrequest->hasRefId() && is_numeric($this->testrequest->getRefId())) {
139  $ref_id = $this->testrequest->getRefId();
140  }
141  parent::__construct("", $ref_id, true, false);
142 
143  $this->ctrl->saveParameter($this, ['ref_id', 'test_ref_id', 'calling_test', 'test_express_mode', 'q_id']);
144 
145  $this->lng->loadLanguageModule('assessment');
146 
147  if ($this->object instanceof ilObjTest) {
153  if (!$this->object->isFixedTest() && !$this->object->isRandomTest()) {
154  $this->tpl->setOnScreenMessage('failure', sprintf(
155  'You tried to access a Dynamic Test. This is not possible anymore with ILIAS 9. '
156  . 'Please tell your administrator to run the corresponding migration to remove this Test completely.',
157  $this->object->getTitle()
158  ), true);
159  $this->ctrl->setParameterByClass('ilrepositorygui', 'ref_id', ROOT_FOLDER_ID);
160  $this->ctrl->redirectByClass('ilrepositorygui');
161  }
162 
163  $this->test_question_set_config_factory = new ilTestQuestionSetConfigFactory(
164  $this->tree,
165  $this->db,
166  $this->lng,
167  $this->logging_services->root(),
171  );
172 
173  $this->test_player_factory = new ilTestPlayerFactory($this->object);
174  $this->test_session_factory = new ilTestSessionFactory($this->object, $this->db, $this->user);
175  $this->setTestAccess(new ilTestAccess($this->ref_id, $this->object->getTestId()));
176  } else {
177  $this->setCreationMode(true); // I think?
178  }
179  $this->objective_oriented_container = new ilTestObjectiveOrientedContainer();
180 
181  if ($this->object instanceof ilObjTest) {
182  $tabs_manager = new ilTestTabsManager(
183  $this->tabs_gui,
184  $this->lng,
185  $this->ctrl,
186  $this->request_wrapper,
187  $this->refinery,
188  $this->access,
189  $this->test_access,
190  $this->objective_oriented_container
191  );
192  $tabs_manager->setTestOBJ($this->object);
193  $tabs_manager->setTestSession($this->test_session_factory->getSession());
194  $tabs_manager->setTestQuestionSetConfig($this->test_question_set_config_factory->getQuestionSetConfig());
195  $this->setTabsManager($tabs_manager);
196  }
197  }
198 
202  public function executeCommand(): void
203  {
204  $cmd = $this->ctrl->getCmd('testScreen');
205 
206  $cmds_disabled_due_to_offline_status = [
207  'resumePlayer', 'resumePlayer', 'outUserResultsOverview', 'outUserListOfAnswerPasses'
208  ];
209 
210  if (!$this->getCreationMode() && $this->object->getOfflineStatus() && in_array($cmd, $cmds_disabled_due_to_offline_status)) {
211  $cmd = 'infoScreen';
212  }
213 
214  $next_class = $this->ctrl->getNextClass($this);
215 
216  // add entry to navigation history
217  if (!$this->getCreationMode() &&
218  $this->access->checkAccess('read', '', $this->testrequest->getRefId())
219  ) {
220  $this->navigation_history->addItem(
221  $this->testrequest->getRefId(),
222  ilLink::_getLink($this->testrequest->getRefId(), "tst"),
223  'tst',
224  );
225  }
226 
227  // elba hack for storing question id for inserting new question after
228  if ($this->testrequest->raw('prev_qid')) {
229  global $___prev_question_id;
230  $___prev_question_id = $this->testrequest->raw('prev_qid');
231  $this->ctrl->setParameter($this, 'prev_qid', $this->testrequest->raw('prev_qid'));
232  }
233 
234  if (
235  !$this->getCreationMode()
236  && isset($this->test_question_set_config_factory)
237  && $this->test_question_set_config_factory->getQuestionSetConfig()->areDepenciesBroken()
238  && !$this->test_question_set_config_factory->getQuestionSetConfig()->isValidRequestOnBrokenQuestionSetDepencies($next_class, $cmd)
239  ) {
240  $this->ctrl->redirectByClass('ilObjTestGUI', 'infoScreen');
241  }
242 
244 
245  switch ($next_class) {
246  case 'illtiproviderobjectsettinggui':
247  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
248  $this->redirectAfterMissingRead();
249  }
250  $this->prepareOutput();
251  $this->addHeaderAction();
252  $this->tabs_manager->getSettingsSubTabs();
253  $this->tabs_gui->activateTab('settings');
254  $this->tabs_gui->activateSubTab('lti_provider');
255  $lti_gui = new ilLTIProviderObjectSettingGUI($this->object->getRefId());
256  $lti_gui->setCustomRolesForSelection($this->rbac_review->getLocalRoles($this->object->getRefId()));
257  $lti_gui->offerLTIRolesForSelection(false);
258  $this->ctrl->forwardCommand($lti_gui);
259  break;
260 
261 
262  case 'iltestexportgui':
263  if (!$this->access->checkAccess('write', '', $this->ref_id)) {
264  $this->redirectAfterMissingWrite();
265  }
266 
267  $this->prepareOutput();
268  $this->addHeaderAction();
269  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_EXPORT);
270 
271  $selected_files = [];
272  if ($this->testrequest->isset('file') && $this->testrequest->raw('file')) {
273  $selected_files = $this->testrequest->raw('file');
274  }
275 
276  if (is_string($selected_files)) {
277  $selected_files = [$selected_files];
278  }
279 
280  $export_gui = new ilTestExportGUI(
281  $this,
282  $this->db,
283  $this->logging_services->root(),
286  $this->component_factory->getActivePluginsInSlot('texp'),
287  new ilTestHTMLGenerator(),
288  $selected_files,
290  );
291  $this->ctrl->forwardCommand($export_gui);
292  break;
293 
294  case "ilinfoscreengui":
295  if (!$this->access->checkAccess("read", "", $this->testrequest->getRefId()) && !$this->access->checkAccess("visible", "", $this->testrequest->getRefId())) {
296  $this->redirectAfterMissingRead();
297  }
298  $this->prepareOutput();
299  $this->addHeaderAction();
300  $this->infoScreen(); // forwards command
301  break;
302 
303  case "iltestscreengui":
304  if (!$this->access->checkAccess('read', '', $this->testrequest->getRefId()) && !$this->access->checkAccess('visible', '', $this->testrequest->getRefId())) {
305  $this->redirectAfterMissingRead();
306  }
307  $this->prepareOutput();
308  $this->addHeaderAction();
309  $this->ctrl->forwardCommand($this->getTestScreenGUIInstance());
310  break;
311 
312  case 'ilobjectmetadatagui':
313  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
314  $this->redirectAfterMissingWrite();
315  }
316 
317  $this->prepareOutput();
318  $this->addHeaderAction();
319  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_META_DATA);
320  $md_gui = new ilObjectMetaDataGUI($this->object);
321  $this->ctrl->forwardCommand($md_gui);
322  break;
323 
324  case 'iltestdashboardgui':
325  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
326  $this->redirectAfterMissingRead();
327  }
328  $this->prepareOutput();
329  $this->addHeaderAction();
330 
331  $gui = new ilTestDashboardGUI(
332  $this->getTestObject(),
333  $this->user,
334  $this->access,
335  $this->tpl,
336  $this->ui_factory,
337  $this->ui_renderer,
338  $this->lng,
339  $this->db,
340  $this->ctrl,
341  $this->tabs_gui,
342  $this->toolbar,
343  $this->test_question_set_config_factory->getQuestionSetConfig(),
345  );
346 
347  $gui->setTestAccess($this->getTestAccess());
348  $gui->setTestTabs($this->getTabsManager());
349  $gui->setObjectiveParent($this->getObjectiveOrientedContainer());
350 
351  $this->ctrl->forwardCommand($gui);
352  break;
353 
354  case 'iltestresultsgui':
355  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
356  $this->redirectAfterMissingRead();
357  }
358  $this->prepareOutput();
359  $this->addHeaderAction();
360 
361  $gui = new ilTestResultsGUI(
362  $this->getTestObject(),
363  $this->test_question_set_config_factory->getQuestionSetConfig(),
364  $this->ctrl,
366  $this->db,
368  $this->user,
369  $this->lng,
374  $this->tpl,
381  );
382 
383  $gui->setTestAccess($this->getTestAccess());
384  $gui->setTestSession($this->test_session_factory->getSession());
385  $gui->setTestTabs($this->getTabsManager());
386  $gui->setObjectiveParent($this->getObjectiveOrientedContainer());
387 
388  $this->ctrl->forwardCommand($gui);
389  break;
390 
391  case "iltestplayerfixedquestionsetgui":
392  if ($cmd !== 'autosave'
393  && !$this->access->checkAccess("read", "", $this->testrequest->getRefId())) {
394  $this->redirectAfterMissingRead();
395  }
396  $this->trackTestObjectReadEvent();
397  if (!$this->object->getKioskMode()) {
398  $this->prepareOutput();
399  }
400  $gui = new ilTestPlayerFixedQuestionSetGUI($this->getTestObject());
401  $gui->setObjectiveOrientedContainer($this->getObjectiveOrientedContainer());
402  $this->ctrl->forwardCommand($gui);
403  break;
404 
405  case "iltestplayerrandomquestionsetgui":
406  if ($cmd !== 'autosave'
407  && !$this->access->checkAccess("read", "", $this->testrequest->getRefId())) {
408  $this->redirectAfterMissingRead();
409  }
410  $this->trackTestObjectReadEvent();
411  if (!$this->object->getKioskMode()) {
412  $this->prepareOutput();
413  }
414  $gui = new ilTestPlayerRandomQuestionSetGUI($this->getTestObject());
415  $gui->setObjectiveOrientedContainer($this->getObjectiveOrientedContainer());
416  $this->ctrl->forwardCommand($gui);
417  break;
418 
419  case "iltestevaluationgui":
420  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
421  $this->redirectAfterMissingRead();
422  }
423  $this->forwardToEvaluationGUI();
424  break;
425 
426  case "iltestevalobjectiveorientedgui":
427  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
428  $this->redirectAfterMissingRead();
429  }
430  // @PHP8-CR I believe this is an indicator for an incomplete feature. I wish to leave it in place
431  // "as is"for further analysis.
432  $this->forwardToEvalObjectiveOrientedGUI();
433  break;
434 
435  case "iltestservicegui":
436  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
437  $this->redirectAfterMissingRead();
438  }
439  $this->prepareOutput();
440  $this->addHeaderAction();
441  $serviceGUI = new ilTestServiceGUI($this->object);
442  $this->ctrl->forwardCommand($serviceGUI);
443  break;
444 
445  case 'ilpermissiongui':
446  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
447  $this->redirectAfterMissingRead();
448  }
449  $this->prepareOutput();
450  $this->addHeaderAction();
451  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_PERMISSIONS);
452  $perm_gui = new ilPermissionGUI($this);
453  $ret = $this->ctrl->forwardCommand($perm_gui);
454  break;
455 
456  case "illearningprogressgui":
457  if (!$this->access->checkAccess("read", "", $this->testrequest->getRefId())) {
458  $this->redirectAfterMissingRead();
459  }
460 
461  $this->prepareOutput();
462  $this->addHeaderAction();
463 
464  $test_object = $this->getTestObject();
465  if ($test_object === null) {
467  break;
468  }
469 
470  $test_session = $this->test_session_factory->getSessionByUserId($this->user->getId());
471  if (!$this->checkPermissionBool('write')
472  && !$test_object->canShowTestResults($test_session)) {
473  $this->tpl->setOnScreenMessage(
474  'info',
475  $this->lng->txt('tst_res_tab_msg_no_lp_access'),
476  );
477  break;
478  }
479 
480  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_LEARNING_PROGRESS);
482  $this->ctrl->forwardCommand($new_gui);
483 
484  break;
485 
486  case "ilcertificategui":
487  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
488  $this->redirectAfterMissingRead();
489  }
490  $this->prepareOutput();
491  $this->addHeaderAction();
492 
493  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_SETTINGS);
494 
495  $guiFactory = new ilCertificateGUIFactory();
496  $output_gui = $guiFactory->create($this->object);
497 
498  $this->ctrl->forwardCommand($output_gui);
499  break;
500 
501  case "iltestscoringgui":
502  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
503  $this->redirectAfterMissingRead();
504  }
505  $this->prepareOutput();
506  $this->addHeaderAction();
507  $output_gui = new ilTestScoringGUI($this->object);
508  $output_gui->setTestAccess($this->getTestAccess());
509  $this->ctrl->forwardCommand($output_gui);
510  break;
511 
512  case 'ilmarkschemagui':
513  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
514  $this->redirectAfterMissingRead();
515  }
516  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
517  $this->tpl->setOnScreenMessage('info', $this->lng->txt('cannot_edit_test'), true);
518  $this->ctrl->redirect($this, 'infoScreen');
519  }
520  $this->prepareOutput();
521  $this->addHeaderAction();
522  $mark_schema_gui = new ilMarkSchemaGUI($this->getTestObject());
523  $this->ctrl->forwardCommand($mark_schema_gui);
524  break;
525 
526  case 'iltestscoringbyquestionsgui':
527  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
528  $this->redirectAfterMissingRead();
529  }
530  $this->prepareOutput();
531  $this->addHeaderAction();
532  $output_gui = new ilTestScoringByQuestionsGUI($this->getTestObject());
533  $output_gui->setTestAccess($this->getTestAccess());
534  $this->ctrl->forwardCommand($output_gui);
535  break;
536 
537  case 'ilobjtestsettingsmaingui':
538  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
539  $this->redirectAfterMissingRead();
540  }
541 
542  $this->addHeaderAction();
543  $gui = new ilObjTestSettingsMainGUI(
544  $this->ctrl,
545  $this->access,
546  $this->lng,
547  $this->tree,
548  $this->db,
549  $this->component_repository,
550  $this->user,
551  $this,
552  $this->questioninfo
553  );
554  $this->ctrl->forwardCommand($gui);
555  break;
556 
557  case 'ilobjtestsettingsscoringresultsgui':
558  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
559  $this->redirectAfterMissingRead();
560  }
561  $this->prepareOutput();
562  $this->addHeaderAction();
564  $this->ctrl,
565  $this->access,
566  $this->lng,
567  $this->tree,
568  $this->db,
569  $this->component_repository,
570  $this,
571  $this->tpl,
572  $this->tabs_gui,
573  $this->getTestObject()->getScoreSettingsRepository(),
574  $this->getTestObject()->getTestId(),
575  $this->ui_factory,
576  $this->ui_renderer,
577  $this->refinery,
578  $this->request,
579  $this->user
580  );
581 
582  $this->ctrl->forwardCommand($gui);
583  break;
584 
585  case 'iltestrandomquestionsetconfiggui':
586  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
587  $this->redirectAfterMissingRead();
588  }
589  $this->prepareOutput();
590  $this->addHeaderAction();
591  $test_process_locker_factory = (new ilTestProcessLockerFactory(
592  new ilSetting('assessment'),
593  $this->db
594  ))->withContextId($this->object->getId());
596  $this->getTestObject(),
597  $this->ctrl,
598  $this->user,
599  $this->access,
600  $this->ui_factory,
601  $this->ui_renderer,
602  $this->tabs_gui,
603  $this->lng,
604  $this->logging_services->root(),
605  $this->tpl,
606  $this->db,
607  $this->tree,
611  $test_process_locker_factory,
614  );
615  $this->ctrl->forwardCommand($gui);
616  break;
617 
618  case 'iltestquestionbrowsertablegui':
619  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
620  $this->redirectAfterMissingRead();
621  }
622  $this->prepareOutput();
623  $this->addHeaderAction();
625  $this->tabs_gui,
626  $this->tree,
627  $this->db,
628  $this->logging_services->root(),
630  $this->getTestObject(),
632  $this->http,
638  );
639  $gui->setWriteAccess($this->access->checkAccess("write", "", $this->ref_id));
640  $gui->init();
641  $this->ctrl->forwardCommand($gui);
642  break;
643 
644  case 'iltestskilladministrationgui':
645  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
646  $this->redirectAfterMissingRead();
647  }
648  $this->prepareOutput();
649  $this->addHeaderAction();
650  $gui = new ilTestSkillAdministrationGUI(
651  $this->ctrl,
652  $this->access,
653  $this->tabs_gui,
654  $this->tpl,
655  $this->lng,
656  $this->refinery,
657  $this->db,
658  $this->logging_services->root(),
659  $this->tree,
661  $this->getTestObject(),
664  );
665  $this->ctrl->forwardCommand($gui);
666  break;
667 
668  case 'ilobjectcopygui':
669  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
670  $this->redirectAfterMissingRead();
671  }
672  $this->prepareOutput();
673  $this->addHeaderAction();
674  $cp = new ilObjectCopyGUI($this);
675  $cp->setType('tst');
676  $this->ctrl->forwardCommand($cp);
677  break;
678 
679  case 'ilpageeditorgui':
680  case 'iltestexpresspageobjectgui':
681  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
682  $this->redirectAfterMissingRead();
683  }
684  $this->getTabsManager()->getQuestionsSubTabs();
686  $incompleteQuestionPurger = new ilAssIncompleteQuestionPurger($this->db);
687  $incompleteQuestionPurger->setOwnerId($this->user->getId());
688  $incompleteQuestionPurger->purge();
689 
690  try {
691  $qid = $this->fetchAuthoringQuestionIdParameter();
692  } catch (ilTestException $e) {
693  $qid = 0;
694  }
695 
696  $this->prepareOutput();
697  if (!in_array($cmd, ['addQuestion', 'browseForQuestions'])) {
698  $this->buildPageViewToolbar($qid);
699  }
700 
701  if (!$qid || in_array($cmd, ['insertQuestions', 'browseForQuestions'])) {
702  $pageObject = new ilTestExpressPageObjectGUI(0, 0, $this->object);
703  $ret = $this->ctrl->forwardCommand($pageObject);
704  $this->tpl->setContent($ret);
705  break;
706  }
707  $this->tpl->setCurrentBlock("ContentStyle");
708  $this->tpl->setVariable(
709  "LOCATION_CONTENT_STYLESHEET",
711  );
712  $this->tpl->parseCurrentBlock();
713 
714  // syntax style
715  $this->tpl->setCurrentBlock("SyntaxStyle");
716  $this->tpl->setVariable(
717  "LOCATION_SYNTAX_STYLESHEET",
719  );
720  $this->tpl->parseCurrentBlock();
721 
722  $q_gui = assQuestionGUI::_getQuestionGUI("", $qid);
723  if (!($q_gui instanceof assQuestionGUI)) {
724  $this->ctrl->setParameterByClass('iltestexpresspageobjectgui', 'q_id', '');
725  $this->ctrl->redirectByClass('iltestexpresspageobjectgui', $this->ctrl->getCmd());
726  }
727 
728  $q_gui->setRenderPurpose(assQuestionGUI::RENDER_PURPOSE_PREVIEW);
729 
730  $q_gui->outAdditionalOutput();
731  $q_gui->object->setObjId($this->object->getId());
732 
733  $q_gui->setTargetGuiClass(null);
734  $q_gui->setQuestionActionCmd('');
735 
736  $question = $q_gui->object;
737  $this->ctrl->saveParameter($this, "q_id");
738 
739  #$this->lng->loadLanguageModule("content");
740  $this->ctrl->setReturnByClass("ilTestExpressPageObjectGUI", "view");
741  $this->ctrl->setReturn($this, "questions");
742 
743  $page_gui = new ilTestExpressPageObjectGUI($qid, 0, $this->object);
744  $page_gui->setEditPreview(true);
745  $page_gui->setEnabledTabs(false);
746  if (strlen($this->ctrl->getCmd()) == 0) {
747  $this->ctrl->setCmdClass(get_class($page_gui));
748  $this->ctrl->setCmd("preview");
749  }
750 
751  $page_gui->setQuestionHTML([$q_gui->object->getId() => $q_gui->getPreview(true)]);
752  $page_gui->setTemplateTargetVar("ADM_CONTENT");
753 
754  $page_gui->setOutputMode($this->object->evalTotalPersons() == 0 ? "edit" : 'preview');
755 
756  $page_gui->setHeader($question->getTitleForHTMLOutput());
757  $page_gui->setFileDownloadLink($this->ctrl->getLinkTarget($this, "downloadFile"));
758  $page_gui->setFullscreenLink($this->ctrl->getLinkTarget($this, "fullscreen"));
759  $page_gui->setSourcecodeDownloadScript($this->ctrl->getLinkTarget($this));
760  $page_gui->setPresentationTitle($question->getTitleForHTMLOutput() . ' [' . $this->lng->txt('question_id_short') . ': ' . $question->getId() . ']');
761  $ret = $this->ctrl->forwardCommand($page_gui);
762  if ($ret != "") {
763  $this->tpl->setContent($ret);
764  }
765  $this->tabs_gui->activateTab('assQuestions');
766 
767  break;
768 
769  case 'ilassquestionpreviewgui':
770  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
771  $this->redirectAfterMissingWrite();
772  }
773  $this->prepareOutput();
774 
775  $this->ctrl->saveParameter($this, "q_id");
776 
777  $gui = new ilAssQuestionPreviewGUI(
778  $this->ctrl,
779  $this->rbac_system,
780  $this->tabs_gui,
781  $this->tpl,
782  $this->lng,
783  $this->db,
784  $this->user,
785  $this->refinery->random(),
787  $this->http,
789  );
790 
791  $gui->initQuestion($this->fetchAuthoringQuestionIdParameter(), $this->object->getId());
792  $gui->initPreviewSettings($this->object->getRefId());
793  $gui->initPreviewSession($this->user->getId(), $this->testrequest->getQuestionId());
794  $gui->initHintTracking();
795  $gui->initStyleSheets();
796 
797  $this->ctrl->forwardCommand($gui);
798 
799  break;
800 
801  case 'ilassquestionpagegui':
802  if ($cmd == 'finishEditing') {
803  $this->ctrl->redirectByClass('ilassquestionpreviewgui', ilAssQuestionPreviewGUI::CMD_SHOW);
804  break;
805  }
806  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
807  $this->redirectAfterMissingRead();
808  }
809  if ($cmd === 'edit' && !$this->access->checkAccess('write', '', $this->testrequest->getRefId())) {
810  $this->redirectAfterMissingWrite();
811  }
812  $this->prepareOutput();
813  $forwarder = new ilAssQuestionPageCommandForwarder();
814  $forwarder->setTestObj($this->getTestObject());
815  $forwarder->forward();
816  break;
817 
818  case 'ilassspecfeedbackpagegui':
819  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
820  $this->redirectAfterMissingRead();
821  }
822  $pg_gui = new ilAssSpecFeedbackPageGUI((int) $this->testrequest->raw("feedback_id"));
823  $this->ctrl->forwardCommand($pg_gui);
824  break;
825 
826  case 'ilassgenfeedbackpagegui':
827  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
828  $this->redirectAfterMissingRead();
829  }
830  $pg_gui = new ilAssGenFeedbackPageGUI($this->testrequest->int("feedback_id"));
831  $this->ctrl->forwardCommand($pg_gui);
832  break;
833 
834  case 'illocalunitconfigurationgui':
835  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
836  $this->redirectAfterMissingRead();
837  }
838  $this->prepareSubGuiOutput();
839 
840  // set return target
841  $this->ctrl->setReturn($this, "questions");
843  $questionGUI->object->setObjId($this->object->getId());
844  $questionGUI->setQuestionTabs();
845  $gui = new ilLocalUnitConfigurationGUI(
846  new ilUnitConfigurationRepository($this->testrequest->getQuestionId())
847  );
848  $this->ctrl->forwardCommand($gui);
849  break;
850 
851  case "ilcommonactiondispatchergui":
852  if (!$this->access->checkAccess("read", "", $this->testrequest->getRefId()) && !$this->access->checkAccess("visible", "", $this->testrequest->getRefId())) {
853  $this->redirectAfterMissingRead();
854  }
855  $this->prepareOutput();
857  $this->ctrl->forwardCommand($gui);
858  break;
859 
860  case 'ilassquestionhintsgui':
861  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
862  $this->redirectAfterMissingWrite();
863  }
864  $this->prepareSubGuiOutput();
865 
866  // set return target
867  $this->ctrl->setReturn($this, "questions");
869  $questionGUI->object->setObjId($this->object->getId());
870  $questionGUI->setQuestionTabs();
871 
872  if ($this->object->evalTotalPersons() !== 0) {
873  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("question_is_part_of_running_test"), true);
874  $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
875  }
876  $gui = new ilAssQuestionHintsGUI($questionGUI);
877 
878  $gui->setEditingEnabled(
879  $this->access->checkAccess('write', '', $this->object->getRefId())
880  );
881 
882  $this->ctrl->forwardCommand($gui);
883 
884  break;
885 
886  case 'ilassquestionfeedbackeditinggui':
887  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
888  $this->redirectAfterMissingWrite();
889  }
890  $this->prepareSubGuiOutput();
891 
892  // set return target
893  $this->ctrl->setReturn($this, "questions");
895  $questionGUI->object->setObjId($this->object->getId());
896  $questionGUI->setQuestionTabs();
897 
898  if ($this->object->evalTotalPersons() !== 0) {
899  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("question_is_part_of_running_test"), true);
900  $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
901  }
902  $gui = new ilAssQuestionFeedbackEditingGUI($questionGUI, $this->ctrl, $this->access, $this->tpl, $this->tabs_gui, $this->lng);
903  $this->ctrl->forwardCommand($gui);
904 
905  break;
906 
907  case 'iltestcorrectionsgui':
908  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
909  $this->redirectAfterMissingRead();
910  }
911  $this->prepareOutput();
912  $gui = new ilTestCorrectionsGUI(
913  $this->db,
914  $this->ctrl,
915  $this->access,
916  $this->lng,
917  $this->tabs_gui,
918  $this->help,
919  $this->ui_factory,
920  $this->ui_renderer,
921  $this->tpl,
922  $this->refinery,
923  $this->request,
924  $this->testrequest,
925  $this->getTestObject(),
926  $this->questioninfo
927  );
928  $this->ctrl->forwardCommand($gui);
929  break;
930 
931  case 'iltestpagegui':
932  if ((!$this->access->checkAccess("write", "", $this->testrequest->getRefId()))) {
933  $this->redirectAfterMissingWrite();
934  }
935  if ($cmd === 'downloadFile') {
936  $page_id = $this->object->getIntroductionPageId();
937  if ($this->testrequest->strVal('page_type') === 'concludingremarkspage') {
938  $page_id = $this->object->getConcludingRemarksPageId();
939  }
940  $this->ctrl->forwardCommand(new ilTestPageGUI('tst', $page_id));
941  }
942  $this->showEditTestPageGUI($cmd);
943  break;
944 
945  case '':
946  case 'ilobjtestgui':
947  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()) && !$this->access->checkAccess("visible", "", $this->testrequest->getRefId()))) {
948  $this->redirectAfterMissingRead();
949  }
950  $this->prepareOutput();
951  $this->addHeaderAction();
952  if ((strcmp($cmd, "properties") == 0) && ($this->testrequest->raw("browse"))) {
953  $this->questionsObject();
954  return;
955  }
956  if ((strcmp($cmd, "properties") == 0) && ($this->testrequest->raw("up") || $this->testrequest->raw("down"))) {
957  $this->questionsObject();
958  return;
959  }
960  $ret = $cmd === 'testScreen' ? $this->ctrl->forwardCommand($this->getTestScreenGUIInstance()) : $this->{$cmd . "Object"}();
961  break;
962  default:
963  if ((!$this->access->checkAccess("read", "", $this->testrequest->getRefId()))) {
964  $this->redirectAfterMissingRead();
965  }
966  if (in_array($cmd, ['editQuestion', 'save', 'suggestedsolution'])
967  && !$this->access->checkAccess('write', '', $this->object->getRefId())) {
968  $this->redirectAfterMissingWrite();
969  }
970  // elba hack for storing question id for inserting new question after
971  if ($this->testrequest->raw('prev_qid')) {
972  global $___prev_question_id;
973  $___prev_question_id = $this->testrequest->raw('prev_qid');
974  $this->ctrl->setParameterByClass('ilassquestionpagegui', 'prev_qid', $this->testrequest->raw('prev_qid'));
975  $this->ctrl->setParameterByClass($this->testrequest->raw('sel_question_types') . 'gui', 'prev_qid', $this->testrequest->raw('prev_qid'));
976  }
977  $this->create_question_mode = true;
978  $this->prepareOutput();
979 
980  $this->ctrl->setReturn($this, "questions");
981 
982  try {
983  $qid = $this->fetchAuthoringQuestionIdParameter();
984 
985  $questionGui = assQuestionGUI::_getQuestionGUI(
986  ilUtil::stripSlashes($this->testrequest->raw('sel_question_types') ?? ''),
987  $qid
988  );
989 
990  $questionGui->setEditContext(assQuestionGUI::EDIT_CONTEXT_AUTHORING);
991  $questionGui->object->setObjId($this->object->getId());
992 
993  if (in_array($cmd, ['editQuestion', 'save', 'suggestedsolution'])
994  && $this->object->evalTotalPersons() !== 0) {
995  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("question_is_part_of_running_test"), true);
996  $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
997  }
998 
999  $questionGuiClass = get_class($questionGui);
1000  $this->ctrl->setParameterByClass($questionGuiClass, 'prev_qid', $this->testrequest->raw('prev_qid'));
1001  $this->ctrl->setParameterByClass($questionGuiClass, 'test_ref_id', $this->testrequest->getRefId());
1002  $this->ctrl->setParameterByClass($questionGuiClass, 'q_id', $qid);
1003 
1004  if ($this->testrequest->isset('test_express_mode')) {
1005  $this->ctrl->setParameterByClass($questionGuiClass, 'test_express_mode', 1);
1006  }
1007 
1008  $questionGui->setQuestionTabs();
1009 
1010  $this->ctrl->forwardCommand($questionGui);
1011  } catch (ilTestException $e) {
1012  if ($this->testrequest->isset('test_express_mode')) {
1013  $this->ctrl->redirect($this, 'showPage');
1014  } else {
1015  $this->ctrl->redirect($this, 'questions');
1016  }
1017  }
1018  break;
1019  }
1020  if (!in_array(strtolower($this->testrequest->raw('baseClass')), ['iladministrationgui', 'ilrepositorygui'])
1021  && $this->getCreationMode() !== true) {
1022  $this->tpl->printToStdout();
1023  }
1024  }
1025 
1026  protected function redirectAfterMissingWrite()
1027  {
1028  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_permission"), true);
1029  $target_class = get_class($this->object) . "GUI";
1030  $this->ctrl->setParameterByClass($target_class, 'ref_id', $this->ref_id);
1031  $this->ctrl->redirectByClass($target_class);
1032  }
1033 
1034  protected function redirectAfterMissingRead(): void
1035  {
1036  $this->tpl->setOnScreenMessage('failure', sprintf(
1037  $this->lng->txt("msg_no_perm_read_item"),
1038  $this->object->getTitle()
1039  ), true);
1040  $this->ctrl->setParameterByClass('ilrepositorygui', 'ref_id', ROOT_FOLDER_ID);
1041  $this->ctrl->redirectByClass('ilrepositorygui');
1042  }
1043 
1044  protected function trackTestObjectReadEvent()
1045  {
1047  $this->object->getType(),
1048  $this->object->getRefId(),
1049  $this->object->getId(),
1050  $this->user->getId()
1051  );
1052  }
1053 
1058  protected function exportObject()
1059  {
1060  $this->ctrl->redirectByClass('ilTestExportGUI');
1061  }
1062 
1068  {
1069  $qid = $this->testrequest->int('q_id');
1070 
1071  if ($this->object->checkQuestionParent($qid)) {
1072  return $qid;
1073  }
1074 
1075  throw new ilTestException('question id does not relate to parent object!');
1076  }
1077 
1078  private function questionsTabGatewayObject()
1079  {
1080  if ($this->object->isRandomTest()) {
1081  $this->ctrl->redirectByClass('ilTestRandomQuestionSetConfigGUI');
1082  }
1083 
1084  $this->ctrl->redirectByClass('ilObjTestGUI', 'questions');
1085  }
1086 
1087  private function userResultsGatewayObject()
1088  {
1089  $this->ctrl->setCmdClass('ilTestEvaluationGUI');
1090  $this->ctrl->setCmd('outUserResultsOverview');
1091  $this->tabs_gui->clearTargets();
1092 
1093  $this->forwardToEvaluationGUI();
1094  }
1095 
1096  private function testResultsGatewayObject(): void
1097  {
1098  $this->ctrl->redirectByClass(
1099  [
1100  ilRepositoryGUI::class,
1101  __CLASS__,
1102  ilTestResultsGUI::class,
1103  ilParticipantsTestResultsGUI::class
1104  ],
1105  'showParticipants'
1106  );
1107  }
1108 
1109  private function showEditTestPageGUI(string $cmd): void
1110  {
1111  $this->prepareOutput();
1112  $this->tabs_manager->getSettingsSubTabs();
1113 
1114  if ($this->request_wrapper->has('page_type')
1115  && $this->request_wrapper->retrieve(
1116  'page_type',
1117  $this->refinery->kindlyTo()->string()
1118  ) === 'introductionpage'
1119  ) {
1120  $page_type = 'IntroductionPage';
1121  $this->tabs_manager->activateSubTab(ilTestTabsManager::SETTINGS_SUBTAB_ID_EDIT_INTRODUCTION_PAGE);
1122  $page_id = $this->object->getIntroductionPageId();
1123  } else {
1124  $page_type = 'ConcludingRemarksPage';
1125  $this->tabs_manager->activateSubTab(ilTestTabsManager::SETTINGS_SUBTAB_ID_EDIT_CONCLUSION_PAGE);
1126  $page_id = $this->object->getConcludingRemarksPageId();
1127  }
1128  $this->ctrl->saveParameterByClass(ilTestPageGUI::class, 'page_type');
1129 
1130  $gui = new ilTestPageGUI('tst', $page_id);
1131  $this->content_style->gui()->addCss($this->tpl, $this->testrequest->getRefId());
1132  $this->tpl->setContent($this->ctrl->forwardCommand($gui));
1133 
1134  $this->tabs_manager->activateTab(ilTestTabsManager::TAB_ID_SETTINGS);
1135  }
1136 
1137  public function getTestAccess(): ilTestAccess
1138  {
1139  return $this->test_access;
1140  }
1141 
1142  public function setTestAccess(ilTestAccess $test_access)
1143  {
1144  $this->test_access = $test_access;
1145  }
1146 
1148  {
1149  return $this->tabs_manager;
1150  }
1151 
1152  public function setTabsManager(ilTestTabsManager $tabs_manager): void
1153  {
1154  $this->tabs_manager = $tabs_manager;
1155  }
1156 
1157  private function forwardToEvaluationGUI()
1158  {
1159  $this->prepareOutput();
1160  $this->addHeaderAction();
1161  $gui = new ilTestEvaluationGUI($this->getTestObject());
1162  $gui->setObjectiveOrientedContainer($this->getObjectiveOrientedContainer());
1163  $gui->setTestAccess($this->getTestAccess());
1164 
1165  $this->ctrl->forwardCommand($gui);
1166  }
1167 
1169  {
1170  $this->ctrl->redirectByClass('ilObjTestSettingsMainGUI', ilObjTestSettingsMainGUI::CMD_SHOW_FORM);
1171  }
1172 
1173  private function prepareSubGuiOutput()
1174  {
1175  $this->tpl->loadStandardTemplate();
1176 
1177  // set locator
1178  $this->setLocator();
1179 
1180  // set title and description and title icon
1181  $this->setTitleAndDescription();
1182  }
1183 
1184  public function runObject()
1185  {
1186  $this->ctrl->redirect($this, "infoScreen");
1187  }
1188 
1189  public function outEvaluationObject()
1190  {
1191  $this->ctrl->redirectByClass("iltestevaluationgui", "outEvaluation");
1192  }
1193 
1197  protected function importFileObject(int $parent_id = null): void
1198  {
1199  if (!$this->checkPermissionBool("create", "", $_REQUEST["new_type"])) {
1200  $this->redirectAfterMissingWrite();
1201  }
1202 
1203  $form = $this->initImportForm($this->testrequest->raw("new_type"));
1204  if ($form->checkInput()) {
1205  $this->ctrl->setParameter($this, "new_type", $this->type);
1206  $this->uploadTst();
1207  return;
1208  }
1209 
1210  // display form to correct errors
1211  $form->setValuesByPost();
1212  $this->tpl->setContent($form->getHTML());
1213  }
1214 
1215  public function addDidacticTemplateOptions(array &$options): void
1216  {
1217  $tst = new ilObjTest();
1218  $defaults = $tst->getAvailableDefaults();
1219  if (count($defaults)) {
1220  foreach ($defaults as $row) {
1221  $options["tstdef_" . $row["test_defaults_id"]] = [$row["name"],
1222  $this->lng->txt("tst_default_settings")];
1223  }
1224  }
1225  }
1226 
1231  public function afterSave(ilObject $new_object): void
1232  {
1233  $new_object->saveToDb();
1234 
1235  $test_def_id = $this->getDidacticTemplateVar("tstdef");
1236  if ($test_def_id !== 0) {
1237  $test_defaults = $new_object->getTestDefaults($test_def_id);
1238  $new_object->applyDefaults($test_defaults);
1239  }
1240 
1241  $template_id = $this->getDidacticTemplateVar("tsttpl");
1242  if ($template_id) {
1243  $new_object->setTemplate($template_id);
1244  }
1245 
1246  $new_object->saveToDb();
1247 
1248  // always send a message
1249  $this->tpl->setOnScreenMessage('success', $this->lng->txt("object_added"), true);
1250  $this->ctrl->setParameter($this, 'ref_id', $new_object->getRefId());
1251  $this->ctrl->redirectByClass('ilObjTestSettingsMainGUI');
1252  }
1253 
1254  public function backToRepositoryObject()
1255  {
1256  $path = $this->tree->getPathFull($this->object->getRefID());
1257  ilUtil::redirect($this->getReturnLocation("cancel", "./ilias.php?baseClass=ilRepositoryGUI&cmd=frameset&ref_id=" . $path[count($path) - 2]["child"]));
1258  }
1259 
1263  public function uploadTst()
1264  {
1265  if ($_FILES["xmldoc"]["error"] > UPLOAD_ERR_OK) {
1266  $this->lng->loadLanguageModule('file');
1267  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('general_upload_error_occured'));
1268  $this->ctrl->redirect($this, 'create');
1269  return false;
1270  }
1271 
1272  $file = pathinfo($_FILES["xmldoc"]["name"]);
1273  $subdir = basename($file["basename"], "." . $file["extension"]);
1274 
1275  if (strpos($subdir, 'tst') === false) {
1276  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('import_file_not_valid'), true);
1277  $this->ctrl->redirect($this, 'create');
1278  return false;
1279  }
1280 
1281  $basedir = ilObjTest::_createImportDirectory();
1282  $full_path = $basedir . "/" . $_FILES["xmldoc"]["name"];
1283  try {
1284  ilFileUtils::moveUploadedFile($_FILES["xmldoc"]["tmp_name"], $_FILES["xmldoc"]["name"], $full_path);
1285  } catch (Error $e) {
1286  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('import_file_not_valid'), true);
1287  $this->ctrl->redirect($this, 'create');
1288  return false;
1289  }
1290 
1291  $this->archives->unzip($full_path);
1292 
1294  $xml_file = ilObjTest::_getImportDirectory() . '/' . $subdir . '/' . $subdir . ".xml";
1295  $qti_file = ilObjTest::_getImportDirectory() . '/' . $subdir . '/' . preg_replace("/test|tst/", "qti", $subdir) . ".xml";
1296  $results_file = ilObjTest::_getImportDirectory() . '/' . $subdir . '/' . preg_replace("/test|tst/", "results", $subdir) . ".xml";
1297 
1298  if (!is_file($qti_file)) {
1299  ilFileUtils::delDir($basedir);
1300  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("tst_import_non_ilias_zip"), true);
1301  $this->ctrl->redirect($this, 'create');
1302  return false;
1303  }
1304  $qtiParser = new ilQTIParser($qti_file, ilQTIParser::IL_MO_VERIFY_QTI, 0, "");
1305  $qtiParser->startParsing();
1306  $founditems = $qtiParser->getFoundItems();
1307 
1308  $complete = 0;
1309  $incomplete = 0;
1310  foreach ($founditems as $item) {
1311  if (strlen($item["type"])) {
1312  $complete++;
1313  } else {
1314  $incomplete++;
1315  }
1316  }
1317 
1318  if (count($founditems) && $complete == 0) {
1319  ilFileUtils::delDir($basedir);
1320 
1321  $this->tpl->setOnScreenMessage('info', $this->lng->txt("qpl_import_non_ilias_files"));
1322  $this->createObject();
1323  return;
1324  }
1325 
1326  ilSession::set("tst_import_results_file", $results_file);
1327  ilSession::set("tst_import_xml_file", $xml_file);
1328  ilSession::set("tst_import_qti_file", $qti_file);
1329  ilSession::set("tst_import_subdir", $subdir);
1330 
1331  if ($qtiParser->getQuestionSetType() != ilObjTest::QUESTION_SET_TYPE_FIXED
1332  || file_exists($results_file)) {
1333  $this->importVerifiedFileObject();
1334  return;
1335  }
1336 
1337  $importVerificationTpl = new ilTemplate('tpl.tst_import_verification.html', true, true, 'Modules/Test');
1338 
1339  // on import creation screen the pool was chosen (-1 for no pool)
1340  // BUT when no pool is available the input on creation screen is missing, so the field value -1 for no pool is not submitted.
1341  $QplOrTstID = isset($_POST["qpl"]) && (int) $_POST["qpl"] != 0 ? $_POST["qpl"] : -1;
1342 
1343  $importVerificationTpl->setVariable("TEXT_TYPE", $this->lng->txt("question_type"));
1344  $importVerificationTpl->setVariable("TEXT_TITLE", $this->lng->txt("question_title"));
1345  $importVerificationTpl->setVariable("FOUND_QUESTIONS_INTRODUCTION", $this->lng->txt("tst_import_verify_found_questions"));
1346  $importVerificationTpl->setVariable("VERIFICATION_HEADING", $this->lng->txt("import_tst"));
1347  $importVerificationTpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1348  $importVerificationTpl->setVariable("ARROW", ilUtil::getImagePath("nav/arrow_downright.svg"));
1349  $importVerificationTpl->setVariable("QUESTIONPOOL_ID", $QplOrTstID);
1350  $importVerificationTpl->setVariable("VALUE_IMPORT", $this->lng->txt("import"));
1351  $importVerificationTpl->setVariable("VALUE_CANCEL", $this->lng->txt("cancel"));
1352 
1353  $row_class = ["tblrow1", "tblrow2"];
1354  $counter = 0;
1355  foreach ($founditems as $item) {
1356  $importVerificationTpl->setCurrentBlock("verification_row");
1357  $importVerificationTpl->setVariable("ROW_CLASS", $row_class[$counter++ % 2]);
1358  $importVerificationTpl->setVariable("QUESTION_TITLE", $item["title"]);
1359  $importVerificationTpl->setVariable("QUESTION_IDENT", $item["ident"]);
1360 
1361  switch ($item["type"]) {
1364  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assMultipleChoice"));
1365  break;
1368  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assSingleChoice"));
1369  break;
1372  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assKprimChoice"));
1373  break;
1376  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assLongMenu"));
1377  break;
1379  case ilQTIItem::QT_NUMERIC:
1380  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assNumeric"));
1381  break;
1383  case ilQTIItem::QT_FORMULA:
1384  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assFormulaQuestion"));
1385  break;
1388  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assTextSubset"));
1389  break;
1390  case CLOZE_TEST_IDENTIFIER:
1391  case ilQTIItem::QT_CLOZE:
1392  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assClozeTest"));
1393  break;
1394  case ERROR_TEXT_IDENTIFIER:
1396  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assErrorText"));
1397  break;
1400  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assImagemapQuestion"));
1401  break;
1404  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assMatchingQuestion"));
1405  break;
1408  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assOrderingQuestion"));
1409  break;
1412  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assOrderingHorizontal"));
1413  break;
1415  case ilQTIItem::QT_TEXT:
1416  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assTextQuestion"));
1417  break;
1420  $importVerificationTpl->setVariable("QUESTION_TYPE", $this->lng->txt("assFileUpload"));
1421  break;
1422  }
1423  $importVerificationTpl->parseCurrentBlock();
1424  }
1425 
1426  $this->tpl->setContent($importVerificationTpl->get());
1427  }
1428 
1429  public function getTestObject(): ?ilObjTest
1430  {
1432  $test = $this->object;
1433  return $test;
1434  }
1435 
1439  public function importVerifiedFileObject()
1440  {
1441  if (!$this->checkPermissionBool('create', '', $this->testrequest->strVal('new_type'))) {
1442  $this->redirectAfterMissingWrite();
1443  }
1444 
1445  // create new questionpool object
1446  $newObj = new ilObjTest(0, true);
1447  // set type of questionpool object
1448  $newObj->setType($this->testrequest->raw("new_type"));
1449  // set title of questionpool object to "dummy"
1450  $newObj->setTitle("dummy");
1451  // set description of questionpool object
1452  $newObj->setDescription("test import");
1453  // create the questionpool class in the ILIAS database (object_data table)
1454  $newObj->create(true);
1455  // create a reference for the questionpool object in the ILIAS database (object_reference table)
1456  $newObj->createReference();
1457  // put the questionpool object in the administration tree
1458  $newObj->putInTree($this->testrequest->getRefId());
1459  // get default permissions and set the permissions for the questionpool object
1460  $newObj->setPermissions($this->testrequest->getRefId());
1461  // empty mark schema
1462  $newObj->resetMarkSchema();
1463 
1464  // Handle selection of "no questionpool" as qpl_id = -1 -> use test object id instead.
1465  // possible hint: chek if empty strings in $_POST["qpl_id"] relates to a bug or not
1466  if (!isset($_POST["qpl"]) || "-1" === (string) $_POST["qpl"]) {
1467  $questionParentObjId = $newObj->getId();
1468  } else {
1469  $questionParentObjId = $_POST["qpl"];
1470  }
1471 
1472  $imp = new ilImport($this->testrequest->getRefId());
1473  $map = $imp->getMapping();
1474  $map->addMapping('Modules/Test', 'tst', 'new_id', (string) $newObj->getId());
1475 
1476  $fileName = ilSession::get('tst_import_subdir') . '.zip';
1477  $fullPath = ilSession::get('tst_import_dir') . '/' . $fileName;
1478 
1479  if (is_file(ilSession::get("tst_import_dir") . '/' . ilSession::get("tst_import_subdir") . "/manifest.xml")) {
1480  $newObj->saveToDb();
1481 
1482  ilSession::set('tst_import_idents', $_POST['ident'] ?? '');
1483  ilSession::set('tst_import_qst_parent', $questionParentObjId);
1484 
1485  $imp->importObject($newObj, $fullPath, $fileName, 'tst', 'Modules/Test', true);
1486  } else {
1487  $test_importer = new ilTestImporter();
1488  $test_importer->setImport($imp);
1489  $test_importer->setInstallId(IL_INST_ID);
1490  $test_importer->setImportDirectory(ilSession::get('tst_import_dir') . '/' . ilSession::get('tst_import_subdir'));
1491  $test_importer->init();
1492 
1493  $test_importer->importXmlRepresentation(
1494  '',
1495  '',
1496  '',
1497  $map,
1498  );
1499  }
1500 
1501 
1502  // delete import directory
1504  //Note, has been in ilTestImporter, however resetting this there, lead to problem in delDir.
1505  // See: https://github.com/ILIAS-eLearning/ILIAS/pull/5097
1507 
1508  $this->tpl->setOnScreenMessage('success', $this->lng->txt("object_imported"), true);
1509  ilUtil::redirect("ilias.php?ref_id=" . $newObj->getRefId() . "&baseClass=ilObjTestGUI");
1510  }
1511 
1518  public function uploadObject($redirect = true)
1519  {
1520  if (!$this->checkPermissionBool('create', '', $this->testrequest->strVal('new_type'))) {
1521  $this->redirectAfterMissingWrite();
1522  }
1523  $this->uploadTst();
1524  }
1525 
1529  public function downloadFileObject()
1530  {
1531  $file = explode("_", $this->testrequest->raw("file_id"));
1532  $fileObj = new ilObjFile((int) $file[count($file) - 1], false);
1533  $fileObj->sendFile();
1534  exit;
1535  }
1536 
1540  public function fullscreenObject()
1541  {
1542  $page_gui = new ilAssQuestionPageGUI($this->testrequest->raw("pg_id"));
1543  $page_gui->showMediaFullscreen();
1544  }
1545 
1549  public function download_paragraphObject()
1550  {
1551  $pg_obj = new ilAssQuestionPage($this->testrequest->raw("pg_id"));
1552  $pg_obj->sendParagraph($this->testrequest->raw("par_id"), $this->testrequest->raw("downloadtitle"));
1553  exit;
1554  }
1555 
1556  /*
1557  * Removing to get rid of a warning, leaving commented out for further analysis.
1558  public function filterObject()
1559  {
1560  $this->questionBrowser();
1561  }
1562  */
1563 
1564  /*
1565  * Removing to get rid of a warning, leaving commented out for further analysis.
1566  *
1567  public function resetFilterObject()
1568  {
1569  $this->questionBrowser();
1570  }
1571  */
1579  public function backObject()
1580  {
1581  $this->ctrl->redirect($this, "questions");
1582  }
1583 
1592  public function createQuestionPool($name = "dummy", $description = ""): int
1593  {
1594  $parent_ref = $this->tree->getParentId($this->object->getRefId());
1595  $qpl = new ilObjQuestionPool();
1596  $qpl->setType("qpl");
1597  $qpl->setTitle($name);
1598  $qpl->setDescription($description);
1599  $qpl->create();
1600  $qpl->createReference();
1601  $qpl->putInTree($parent_ref);
1602  $qpl->setPermissions($parent_ref);
1603  $qpl->getObjectProperties()->storePropertyIsOnline($qpl->getObjectProperties()->getPropertyIsOnline()->withOnline()); // must be online to be available
1604  $qpl->saveToDb();
1605  return $qpl->getRefId();
1606  }
1607 
1608  /*
1609  * Removing to get rid of a warning, leaving commented out for further analysis.
1610  public function browseForQuestionsObject()
1611  {
1612  $this->questionBrowser();
1613  }
1614  */
1615 
1619  public function executeCreateQuestionObject(): void
1620  {
1621  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1622  $this->redirectAfterMissingWrite();
1623  }
1624  $qpl_ref_id = $this->testrequest->raw("sel_qpl");
1625 
1626  try {
1627  $qpl_mode = $this->testrequest->int('usage');
1628  } catch (ConstraintViolationException $e) {
1629  $qpl_mode = 1;
1630  }
1631 
1632  if ($this->testrequest->isset('qtype')) {
1633  $sel_question_types = ilObjQuestionPool::getQuestionTypeByTypeId($this->testrequest->raw("qtype"));
1634  } elseif ($this->testrequest->isset('sel_question_types')) {
1635  $sel_question_types = $this->testrequest->raw("sel_question_types");
1636  }
1637 
1638  if (($qpl_mode === 2 && $this->testrequest->raw("txt_qpl") === '')
1639  || $qpl_mode === 3 && $qpl_ref_id === '') {
1640  $this->tpl->setOnScreenMessage('info', $this->lng->txt("questionpool_not_entered"));
1641  $this->createQuestionObject();
1642  return;
1643  }
1644 
1645  ilSession::set("test_id", $this->object->getRefId());
1646  if ($qpl_mode === 2) {
1647  // create a new question pool and return the reference id
1648  $qpl_ref_id = $this->createQuestionPool($this->testrequest->raw("txt_qpl"));
1649  } elseif ($qpl_mode === 1) {
1650  $qpl_ref_id = $this->testrequest->getRefId();
1651  }
1652  $baselink = "ilias.php?baseClass=ilObjQuestionPoolGUI&ref_id=" . $qpl_ref_id . "&cmd=createQuestionForTest&test_ref_id=" . $this->testrequest->getRefId() . "&calling_test=" . $this->testrequest->getRefId() . "&sel_question_types=" . $sel_question_types;
1653 
1654  if ($this->testrequest->isset('prev_qid')) {
1655  $baselink .= '&prev_qid=' . $this->testrequest->raw('prev_qid');
1656  } elseif ($this->testrequest->isset('position')) {
1657  $baselink .= '&prev_qid=' . $this->testrequest->raw('position');
1658  }
1659 
1660  if ($this->testrequest->raw('test_express_mode')) {
1661  $baselink .= '&test_express_mode=1';
1662  }
1663 
1664  if ($this->testrequest->isset('add_quest_cont_edit_mode')) {
1666  $baselink,
1667  "add_quest_cont_edit_mode={$this->testrequest->raw('add_quest_cont_edit_mode')}",
1668  false
1669  );
1670  }
1671 
1672  ilUtil::redirect($baselink);
1673  }
1674 
1682  public function cancelCreateQuestionObject()
1683  {
1684  $this->ctrl->redirect($this, "questions");
1685  }
1686 
1694  public function createQuestionObject()
1695  {
1696  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1697  $this->redirectAfterMissingWrite();
1698  }
1699 
1700  $this->getTabsManager()->getQuestionsSubTabs();
1702  $questionpools = $this->object->getAvailableQuestionpools(false, false, false, true, false, "write");
1703 
1704  $form = new ilPropertyFormGUI();
1705  $form->setFormAction($this->ctrl->getFormAction($this, "executeCreateQuestion"));
1706  $form->setTitle($this->lng->txt("ass_create_question"));
1707 
1708  if ($this->testrequest->isset('qtype')) {
1709  $sel_question_types = ilObjQuestionPool::getQuestionTypeByTypeId($this->testrequest->raw("qtype"));
1710  } elseif ($this->testrequest->isset('sel_question_types')) {
1711  $sel_question_types = $this->testrequest->raw("sel_question_types");
1712  }
1713 
1714 
1715  $hidden = new ilHiddenInputGUI('sel_question_types');
1716  $hidden->setValue($sel_question_types);
1717  $form->addItem($hidden);
1718 
1719  // content editing mode
1721  $ri = new ilRadioGroupInputGUI($this->lng->txt("tst_add_quest_cont_edit_mode"), "add_quest_cont_edit_mode");
1722 
1723  $option_ipe = new ilRadioOption(
1724  $this->lng->txt('tst_add_quest_cont_edit_mode_IPE'),
1726  );
1727  $option_ipe->setInfo($this->lng->txt('tst_add_quest_cont_edit_mode_IPE_info'));
1728  $ri->addOption($option_ipe);
1729 
1730  $option_rte = new ilRadioOption(
1731  $this->lng->txt('tst_add_quest_cont_edit_mode_RTE'),
1733  );
1734  $option_rte->setInfo($this->lng->txt('tst_add_quest_cont_edit_mode_RTE_info'));
1735  $ri->addOption($option_rte);
1736 
1738 
1739  $form->addItem($ri, true);
1740  } else {
1741  $hi = new ilHiddenInputGUI("question_content_editing_type");
1743  $form->addItem($hi, true);
1744  }
1745 
1746  // use pool
1747  $usage = new ilRadioGroupInputGUI($this->lng->txt("assessment_pool_selection"), "usage");
1748  $usage->setRequired(true);
1749  $no_pool = new ilRadioOption($this->lng->txt("assessment_no_pool"), '1');
1750  $usage->addOption($no_pool);
1751  $existing_pool = new ilRadioOption($this->lng->txt("assessment_existing_pool"), '3');
1752  $usage->addOption($existing_pool);
1753  $new_pool = new ilRadioOption($this->lng->txt("assessment_new_pool"), '2');
1754  $usage->addOption($new_pool);
1755  $form->addItem($usage);
1756 
1757  $usage->setValue('1');
1758 
1759  $questionpools = ilObjQuestionPool::_getAvailableQuestionpools(false, false, true, false, false, "write");
1760  $pools_data = [];
1761  foreach ($questionpools as $key => $p) {
1762  $pools_data[$key] = $p['title'];
1763  }
1764  $pools = new ilSelectInputGUI($this->lng->txt("select_questionpool"), "sel_qpl");
1765  $pools->setOptions($pools_data);
1766  $existing_pool->addSubItem($pools);
1767 
1768 
1769  $this->lng->loadLanguageModule('rbac');
1770  $name = new ilTextInputGUI($this->lng->txt("rbac_create_qpl"), "txt_qpl");
1771  $name->setSize(50);
1772  $name->setMaxLength(50);
1773  $new_pool->addSubItem($name);
1774 
1775  $form->addCommandButton("executeCreateQuestion", $this->lng->txt("submit"));
1776  $form->addCommandButton("cancelCreateQuestion", $this->lng->txt("cancel"));
1777 
1778  $this->tpl->setVariable('ADM_CONTENT', $form->getHTML());
1779  }
1780 
1785  {
1786  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1787  $this->redirectAfterMissingWrite();
1788  }
1789 
1790  $removeQuestionIds = (array) $_POST["q_id"];
1791 
1792  $questions = $this->object->getQuestionTitlesAndIndexes();
1793 
1794  $this->object->removeQuestions($removeQuestionIds);
1795 
1796  $this->object->saveCompleteStatus($this->test_question_set_config_factory->getQuestionSetConfig());
1797 
1798  $this->tpl->setOnScreenMessage('success', $this->lng->txt("tst_questions_removed"));
1799 
1800  if ($this->testrequest->raw('test_express_mode')) {
1801  $prev = null;
1802  $return_to = null;
1803  $deleted_tmp = $removeQuestionIds;
1804  $first = array_shift($deleted_tmp);
1805  foreach ($questions as $key => $value) {
1806  if (!in_array($key, $removeQuestionIds)) {
1807  $prev = $key;
1808  if (!$first) {
1809  $return_to = $prev;
1810  break;
1811  } else {
1812  continue;
1813  }
1814  } elseif ($key == $first) {
1815  if ($prev) {
1816  $return_to = $prev;
1817  break;
1818  }
1819  $first = array_shift($deleted_tmp);
1820  }
1821  }
1822 
1823  if (
1824  count($questions) == count($removeQuestionIds) ||
1825  !$return_to
1826  ) {
1827  $this->ctrl->setParameter($this, 'q_id', '');
1828  $this->ctrl->redirect($this, 'showPage');
1829  }
1830 
1831  $this->ctrl->setParameter($this, 'q_id', $return_to);
1832  $this->ctrl->redirect($this, "showPage");
1833  } else {
1834  $this->ctrl->setParameter($this, 'q_id', '');
1835  $this->ctrl->redirect($this, 'questions');
1836  }
1837  }
1838 
1847  {
1848  if ($this->testrequest->raw('test_express_mode')) {
1849  $this->ctrl->setParameter($this, 'q_id', $this->testrequest->raw('q_id'));
1850  $this->ctrl->redirect($this, "showPage");
1851  } else {
1852  $this->ctrl->redirect($this, "questions");
1853  }
1854  }
1855 
1863  public function removeQuestionsForm($checked_questions)
1864  {
1865  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1866  $this->redirectAfterMissingWrite();
1867  }
1868 
1869  $total = $this->object->evalTotalPersons();
1870  if ($total) {
1871  // the test was executed previously
1872  $question = sprintf($this->lng->txt("tst_remove_questions_and_results"), $total);
1873  } else {
1874  if (count($checked_questions) == 1) {
1875  $question = $this->lng->txt("tst_remove_question");
1876  } else {
1877  $question = $this->lng->txt("tst_remove_questions");
1878  }
1879  }
1880 
1881  $cgui = new ilConfirmationGUI();
1882  $cgui->setHeaderText($question);
1883 
1884  $this->ctrl->saveParameter($this, 'test_express_mode');
1885  $this->ctrl->saveParameter($this, 'q_id');
1886 
1887  $cgui->setFormAction($this->ctrl->getFormAction($this));
1888  $cgui->setCancel($this->lng->txt("cancel"), "cancelRemoveQuestions");
1889  $cgui->setConfirm($this->lng->txt("confirm"), "confirmRemoveQuestions");
1890  $removablequestions = $this->object->getTestQuestions();
1891  if (count($removablequestions)) {
1892  foreach ($removablequestions as $data) {
1893  if (in_array($data["question_id"], $checked_questions)) {
1894  $txt = $data["title"] . " (" . $this->questioninfo->getQuestionTypeName($data["question_id"]) . ")";
1895  $txt .= ' [' . $this->lng->txt('question_id_short') . ': ' . $data['question_id'] . ']';
1896 
1897  if ($data["description"]) {
1898  $txt .= "<div class=\"small\">" . $data["description"] . "</div>";
1899  }
1900 
1901  $cgui->addItem("q_id[]", (string) $data["question_id"], $txt);
1902  }
1903  }
1904  }
1905 
1906  $this->tpl->setContent($cgui->getHTML());
1907  }
1908 
1912  public function removeQuestionsObject()
1913  {
1914  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1915  $this->redirectAfterMissingWrite();
1916  }
1917 
1918  $this->getTabsManager()->getQuestionsSubTabs();
1920 
1921  $checked_questions = $this->testrequest->raw('q_id');
1922 
1923  if (!is_array($checked_questions) && $checked_questions) {
1924  $checked_questions = [$checked_questions];
1925  }
1926 
1927  if (!is_array($checked_questions)) {
1928  $checked_questions = [];
1929  }
1930 
1931  if (count($checked_questions) > 0) {
1932  $this->removeQuestionsForm($checked_questions);
1933  } elseif (0 === count($checked_questions)) {
1934  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("tst_no_question_selected_for_removal"), true);
1935  $this->ctrl->redirect($this, "questions");
1936  }
1937  }
1938 
1942  public function moveQuestionsObject(): void
1943  {
1944  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1945  $this->redirectAfterMissingWrite();
1946  }
1947 
1948  $selected_questions = $this->testrequest->getQuestionIds();
1949  $selected_question = $this->testrequest->getQuestionId();
1950  if ($selected_questions === [] && $selected_question !== 0) {
1951  $selected_questions = [$selected_question];
1952  }
1953 
1954  if ($selected_questions === []) {
1955  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('no_selection_for_move'), true);
1956  $this->ctrl->redirect($this, 'questions');
1957  return;
1958  }
1959 
1960  ilSession::set('tst_qst_move_' . $this->object->getTestId(), $selected_questions);
1961  $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_selected_for_move"), true);
1962  $this->ctrl->redirect($this, 'questions');
1963  }
1964 
1969  {
1970  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1971  $this->redirectAfterMissingWrite();
1972  }
1973 
1974  $this->insertQuestionsBeforeOrAfter(self::INSERT_MODE_BEFORE);
1975  }
1976 
1980  public function insertQuestionsAfterObject()
1981  {
1982  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
1983  $this->redirectAfterMissingWrite();
1984  }
1985 
1986  $this->insertQuestionsBeforeOrAfter(self::INSERT_MODE_AFTER);
1987  }
1988 
1992  protected function insertQuestionsBeforeOrAfter(int $insert_mode)
1993  {
1994  $target_questions = $this->testrequest->getQuestionIds();
1995  $target_question = $this->testrequest->getQuestionId();
1996  if ($target_questions === [] && $target_question !== 0) {
1997  $target_questions = [$target_question];
1998  }
1999 
2000  if (count($target_questions) === 0) {
2001  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('no_target_selected_for_move'), true);
2002  $this->ctrl->redirect($this, 'questions');
2003  } elseif (count($target_questions) > 1) {
2004  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('too_many_targets_selected_for_move'), true);
2005  $this->ctrl->redirect($this, 'questions');
2006  }
2007 
2008  $this->object->moveQuestions(ilSession::get('tst_qst_move_' . $this->object->getTestId()), $target_questions[0], $insert_mode);
2009  $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_questions_moved'), true);
2010  ilSession::clear('tst_qst_move_' . $this->object->getTestId());
2011  $this->ctrl->redirect($this, 'questions');
2012  }
2013 
2019  public function insertQuestionsObject()
2020  {
2021  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2022  $this->redirectAfterMissingWrite();
2023  }
2024 
2025  $selected_questions = $this->testrequest->getQuestionIds();
2026  $selected_question = $this->testrequest->getQuestionId();
2027  if ($selected_questions === [] && $selected_question !== 0) {
2028  $selected_questions = [$selected_question];
2029  }
2030 
2031  if (count($selected_questions) === 0) {
2032  $this->tpl->setOnScreenMessage('info', $this->lng->txt('tst_insert_missing_question'), true);
2033  $this->ctrl->redirect($this, 'browseForQuestions');
2034  return;
2035  }
2036 
2037  $man_scoring = false;
2038  foreach ($selected_questions as $key => $value) {
2039  $this->object->insertQuestion($this->test_question_set_config_factory->getQuestionSetConfig(), $value);
2040  $man_scoring = $man_scoring || assQuestion::_needsManualScoring($value);
2041  }
2042 
2043  $this->object->saveCompleteStatus($this->test_question_set_config_factory->getQuestionSetConfig());
2044  if ($man_scoring) {
2045  $this->tpl->setOnScreenMessage('info', $this->lng->txt('manscoring_hint'), true);
2046  } else {
2047  $this->tpl->setOnScreenMessage('success', $this->lng->txt('tst_questions_inserted'), true);
2048  }
2049  $this->ctrl->redirect($this, 'questions');
2050  }
2051 
2052  public function addQuestionObject()
2053  {
2054  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2055  $this->redirectAfterMissingWrite();
2056  }
2057 
2058  $this->getTabsManager()->getQuestionsSubTabs();
2060 
2061  $subScreenId = ['createQuestion'];
2062 
2063  $this->ctrl->setParameter($this, 'qtype', $this->testrequest->raw('qtype'));
2064 
2065  $form = new ilPropertyFormGUI();
2066 
2067  $form->setFormAction($this->ctrl->getFormAction($this, "executeCreateQuestion"));
2068  $form->setTitle($this->lng->txt("ass_create_question"));
2069 
2070  $pool = new ilObjQuestionPool();
2071  $questionTypes = $pool->getQuestionTypes(false, true, false);
2072  $options = [];
2073 
2074  // question type
2075  foreach ($questionTypes as $label => $data) {
2076  $options[$data['question_type_id']] = $label;
2077  }
2078  $si = new ilSelectInputGUI($this->lng->txt("question_type"), "qtype");
2079  $si->setOptions($options);
2080  $form->addItem($si, true);
2081 
2082  // position
2083  $questions = $this->object->getQuestionTitlesAndIndexes();
2084  if ($questions) {
2085  $si = new ilSelectInputGUI($this->lng->txt("position"), "position");
2086  $options = ['0' => $this->lng->txt('first')];
2087  foreach ($questions as $key => $title) {
2088  $options[$key] = $this->lng->txt('behind') . ' ' . $title . ' [' . $this->lng->txt('question_id_short') . ': ' . $key . ']';
2089  }
2090  $si->setOptions($options);
2091  $si->setValue($this->testrequest->raw('q_id'));
2092  $form->addItem($si, true);
2093  }
2094 
2095  // content editing mode
2097  $subScreenId[] = 'editMode';
2098 
2099  $ri = new ilRadioGroupInputGUI($this->lng->txt("tst_add_quest_cont_edit_mode"), "add_quest_cont_edit_mode");
2100 
2101  $option_ipe = new ilRadioOption(
2102  $this->lng->txt('tst_add_quest_cont_edit_mode_IPE'),
2104  );
2105  $option_ipe->setInfo($this->lng->txt('tst_add_quest_cont_edit_mode_IPE_info'));
2106  $ri->addOption($option_ipe);
2107 
2108  $option_rte = new ilRadioOption(
2109  $this->lng->txt('tst_add_quest_cont_edit_mode_RTE'),
2111  );
2112  $option_rte->setInfo($this->lng->txt('tst_add_quest_cont_edit_mode_RTE_info'));
2113  $ri->addOption($option_rte);
2114 
2116 
2117  $form->addItem($ri, true);
2118  } else {
2119  $hi = new ilHiddenInputGUI("question_content_editing_type");
2121  $form->addItem($hi, true);
2122  }
2123 
2124  $subScreenId[] = 'poolSelect';
2125 
2126  // use pool
2127  $usage = new ilRadioGroupInputGUI($this->lng->txt("assessment_pool_selection"), "usage");
2128  $usage->setRequired(true);
2129  $no_pool = new ilRadioOption($this->lng->txt("assessment_no_pool"), '1');
2130  $usage->addOption($no_pool);
2131  $existing_pool = new ilRadioOption($this->lng->txt("assessment_existing_pool"), '3');
2132  $usage->addOption($existing_pool);
2133  $new_pool = new ilRadioOption($this->lng->txt("assessment_new_pool"), '2');
2134  $usage->addOption($new_pool);
2135  $form->addItem($usage);
2136 
2137  $usage->setValue('1');
2138 
2139  $questionpools = ilObjQuestionPool::_getAvailableQuestionpools(false, false, true, false, false, "write");
2140  $pools_data = [];
2141  foreach ($questionpools as $key => $p) {
2142  $pools_data[$key] = $p['title'];
2143  }
2144  $pools = new ilSelectInputGUI($this->lng->txt("select_questionpool"), "sel_qpl");
2145  $pools->setOptions($pools_data);
2146  $existing_pool->addSubItem($pools);
2147 
2148  $name = new ilTextInputGUI($this->lng->txt("name"), "txt_qpl");
2149  $name->setSize(50);
2150  $name->setMaxLength(50);
2151  $new_pool->addSubItem($name);
2152 
2153  $form->addCommandButton("executeCreateQuestion", $this->lng->txt("create"));
2154  $form->addCommandButton("questions", $this->lng->txt("cancel"));
2155 
2156  $this->tabs_gui->activateTab('assQuestions');
2157  $this->help->setScreenId('assQuestions');
2158  $this->help->setSubScreenId(implode('_', $subScreenId));
2159 
2160  return $this->tpl->setContent($form->getHTML());
2161  }
2162 
2163  public function questionsObject()
2164  {
2165  $this->ctrl->setParameter($this, 'test_express_mode', '');
2166 
2167  if (!$this->access->checkAccess("write", "", $this->ref_id)) {
2168  // allow only write access
2169  $this->tpl->setOnScreenMessage('info', $this->lng->txt("cannot_edit_test"), true);
2170  $this->ctrl->redirect($this, "infoScreen");
2171  }
2172 
2173  $this->getTabsManager()->getQuestionsSubTabs();
2175 
2176  // #11631, #12994
2177  $this->ctrl->setParameter($this, 'q_id', '');
2178 
2179  if ($this->testrequest->raw("eqid") && $this->testrequest->raw("eqpl")) {
2180  ilUtil::redirect("ilias.php?baseClass=ilObjQuestionPoolGUI&ref_id="
2181  . $this->testrequest->raw("eqpl") . "&cmd=editQuestionForTest&calling_test="
2182  . $this->testrequest->getRefId() . "&q_id=" . $this->testrequest->raw("eqid"));
2183  }
2184 
2185  if ($this->testrequest->raw("up") > 0) {
2186  $this->object->questionMoveUp($this->testrequest->raw("up"));
2187  }
2188  if ($this->testrequest->raw("down") > 0) {
2189  $this->object->questionMoveDown($this->testrequest->raw("down"));
2190  }
2191 
2192  if ($this->testrequest->raw("add")) {
2193  $selected_array = [];
2194  array_push($selected_array, $this->testrequest->raw("add"));
2195  $total = $this->object->evalTotalPersons();
2196  if ($total) {
2197  // the test was executed previously
2198  $this->tpl->setOnScreenMessage('info', sprintf($this->lng->txt("tst_insert_questions_and_results"), $total));
2199  } else {
2200  $this->tpl->setOnScreenMessage('info', $this->lng->txt("tst_insert_questions"));
2201  }
2202  // @PHP8-CR This call seems to be critically important for the method, but I cannot see how to fix it yet.
2203  // I leave the warning "intact" for further analysis, possibly by T&A TechSquad.
2204  $this->insertQuestions($selected_array);
2205  return;
2206  }
2207 
2208  $this->tpl->addBlockFile("ADM_CONTENT", "adm_content", "tpl.il_as_tst_questions.html", "Modules/Test");
2209 
2210  $has_started_test_runs = $this->object->evalTotalPersons() !== 0;
2211  if ($this->access->checkAccess("write", "", $this->ref_id)) {
2212  if ($has_started_test_runs) {
2213  $link = $this->ui_factory->link()->standard(
2214  $this->lng->txt("test_has_datasets_warning_page_view_link"),
2215  $this->ctrl->getLinkTargetByClass(['ilTestResultsGUI', 'ilParticipantsTestResultsGUI'])
2216  );
2217 
2218  $message = $this->lng->txt("test_has_datasets_warning_page_view");
2219  $massage_box = $this->ui_factory->messageBox()->info($message)->withLinks([$link]);
2220  $this->tpl->setCurrentBlock('mess');
2221  $this->tpl->setVariable(
2222  'MESSAGE',
2223  $this->ui_renderer->render($massage_box)
2224  );
2225  $this->tpl->parseCurrentBlock();
2226  } else {
2227  $this->toolbar->addButton($this->lng->txt("ass_create_question"), $this->ctrl->getLinkTarget($this, "addQuestion"));
2228  $this->toolbar->addSeparator();
2230  }
2231  }
2232 
2233  $table_gui = new ilTestQuestionsTableGUI(
2234  $this,
2235  'questions',
2236  $this->object->getRefId(),
2237  $this->access,
2241  );
2242 
2243  $isset = ilSession::get('tst_qst_move_' . $this->object->getTestId()) !== null;
2244  $table_gui->setPositionInsertCommandsEnabled(
2245  $isset
2246  && is_array(ilSession::get('tst_qst_move_' . $this->object->getTestId()))
2247  && count(ilSession::get('tst_qst_move_' . $this->object->getTestId()))
2248  );
2249 
2250  $table_gui->setQuestionPositioningEnabled(!$has_started_test_runs);
2251  $table_gui->setQuestionManagingEnabled(!$has_started_test_runs);
2252  $table_gui->setObligatoryQuestionsHandlingEnabled($this->object->areObligationsEnabled());
2253 
2254  $table_gui->setTotalPoints($this->object->getFixedQuestionSetTotalPoints());
2255 
2256  $table_gui->init();
2257 
2258  $table_gui->setData($this->object->getTestQuestions());
2259 
2260  $this->tpl->setCurrentBlock("adm_content");
2261  $this->tpl->setVariable("ACTION_QUESTION_FORM", $this->ctrl->getFormAction($this));
2262  $this->tpl->setVariable('QUESTIONBROWSER', $table_gui->getHTML());
2263  $this->tpl->parseCurrentBlock();
2264  }
2265 
2267  {
2268  $this->ctrl->setParameterByClass(
2269  ilTestQuestionBrowserTableGUI::class,
2271  $context
2272  );
2273  $this->ctrl->setParameterByClass(
2274  ilTestQuestionBrowserTableGUI::class,
2277  );
2278 
2279  $toolbar->addButton(
2280  $this->lng->txt("tst_browse_for_qpl_questions"),
2281  $this->ctrl->getLinkTargetByClass(
2282  ilTestQuestionBrowserTableGUI::class,
2284  )
2285  );
2286 
2287  $this->ctrl->setParameterByClass(
2288  ilTestQuestionBrowserTableGUI::class,
2291  );
2292 
2293  $toolbar->addButton(
2294  $this->lng->txt("tst_browse_for_tst_questions"),
2295  $this->ctrl->getLinkTargetByClass(
2296  ilTestQuestionBrowserTableGUI::class,
2298  )
2299  );
2300  }
2301 
2302  public function takenObject()
2303  {
2304  }
2305 
2313  public function historyObject()
2314  {
2315  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2316  $this->redirectAfterMissingWrite();
2317  }
2318 
2319  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_HISTORY);
2320  $table_gui = new ilTestHistoryTableGUI($this, 'history');
2321  $table_gui->setTestObject($this->object);
2322  $log = ilObjAssessmentFolder::_getLog(0, time(), $this->object->getId(), true);
2323  $table_gui->setData($log);
2324  $this->tpl->setVariable('ADM_CONTENT', $table_gui->getHTML());
2325  }
2326 
2327  public function initImportForm(string $new_type): ilPropertyFormGUI
2328  {
2329  $form = new ilPropertyFormGUI();
2330  $form->setTarget("_top");
2331  $n_type = $this->testrequest->raw("new_type");
2332  $this->ctrl->setParameter($this, "new_type", $n_type);
2333  $form->setFormAction($this->ctrl->getFormAction($this));
2334  $form->setTitle($this->lng->txt("import_tst"));
2335  $fi = new ilFileInputGUI($this->lng->txt("import_file"), "xmldoc");
2336  $fi->setSuffixes(["zip"]);
2337  $fi->setRequired(true);
2338  $form->addItem($fi);
2339  $tst = new ilObjTest();
2340  $questionpools = $tst->getAvailableQuestionpools(true, false, true, true);
2341  if (count($questionpools)) {
2342  $options = ["-1" => $this->lng->txt("dont_use_questionpool")];
2343  foreach ($questionpools as $key => $value) {
2344  $options[$key] = $value["title"];
2345  }
2346 
2347  $pool = new ilSelectInputGUI($this->lng->txt("select_questionpool"), "qpl");
2348  $pool->setInfo($this->lng->txt('select_question_pool_info'));
2349  $pool->setOptions($options);
2350  $form->addItem($pool);
2351  }
2352 
2353  $form->addCommandButton("importFile", $this->lng->txt("import"));
2354  $form->addCommandButton("cancel", $this->lng->txt("cancel"));
2355 
2356  return $form;
2357  }
2358 
2364  public function participantsActionObject()
2365  {
2366  $command = $_POST["command"];
2367  if (strlen($command)) {
2368  $method = $command . "Object";
2369  if (method_exists($this, $method)) {
2370  $this->$method();
2371  return;
2372  }
2373  }
2374  $this->ctrl->redirect($this, "participants");
2375  }
2376 
2384  public function printObject()
2385  {
2386  if (!$this->access->checkAccess("write", "", $this->ref_id)) {
2387  // allow only write access
2388  $this->tpl->setOnScreenMessage('info', $this->lng->txt("cannot_edit_test"), true);
2389  $this->ctrl->redirect($this, "infoScreen");
2390  }
2391 
2392  $this->getTabsManager()->getQuestionsSubTabs();
2393  $template = new ilTemplate("tpl.il_as_tst_print_test_confirm.html", true, true, "Modules/Test");
2394 
2395  $template->setCurrentBlock("navigation_buttons");
2396  $template->setVariable("BUTTON_PRINT", $this->lng->txt("print"));
2397  $template->parseCurrentBlock();
2398 
2399  $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
2400 
2401  $print_date = mktime((int) date("H"), (int) date("i"), (int) date("s"), (int) date("m"), (int) date("d"), (int) date("Y"));
2402  $max_points = 0;
2403  $counter = 1;
2404  $questionHeaderBlockBuilder = new ilTestQuestionHeaderBlockBuilder($this->lng);
2405  $questionHeaderBlockBuilder->setHeaderMode($this->object->getTitleOutput());
2406 
2407  foreach ($this->object->questions as $question) {
2408  $template->setCurrentBlock("question");
2409  $question_gui = $this->object->createQuestionGUI("", $question);
2410  $question_gui->setPresentationContext(assQuestionGUI::PRESENTATION_CONTEXT_TEST);
2411 
2412  $questionHeaderBlockBuilder->setQuestionTitle($question_gui->object->getTitleForHTMLOutput());
2413  $questionHeaderBlockBuilder->setQuestionPoints($question_gui->object->getMaximumPoints());
2414  $questionHeaderBlockBuilder->setQuestionPosition($counter);
2415  $template->setVariable("QUESTION_HEADER", $questionHeaderBlockBuilder->getHTML());
2416 
2417  $template->setVariable("TXT_QUESTION_ID", $this->lng->txt('question_id_short'));
2418  $template->setVariable("QUESTION_ID", $question_gui->object->getId());
2419  $result_output = $question_gui->getSolutionOutput(0, null, false, true, false, false);
2420  $template->setVariable("SOLUTION_OUTPUT", $result_output);
2421  $template->parseCurrentBlock("question");
2422  $counter++;
2423  $max_points += $question_gui->object->getMaximumPoints();
2424  }
2425 
2426  $template->setVariable("TITLE", strip_tags($this->object->getTitle(), ilObjectGUI::ALLOWED_TAGS_IN_TITLE_AND_DESCRIPTION));
2427  $template->setVariable("PRINT_TEST", ilLegacyFormElementsUtil::prepareFormOutput($this->lng->txt("tst_print")));
2428  $template->setVariable("TXT_PRINT_DATE", ilLegacyFormElementsUtil::prepareFormOutput($this->lng->txt("date")));
2429  $template->setVariable(
2430  "VALUE_PRINT_DATE",
2432  );
2433  $template->setVariable(
2434  "TXT_MAXIMUM_POINTS",
2435  ilLegacyFormElementsUtil::prepareFormOutput($this->lng->txt("tst_maximum_points"))
2436  );
2437  $template->setVariable("VALUE_MAXIMUM_POINTS", ilLegacyFormElementsUtil::prepareFormOutput($max_points));
2438  $this->tpl->setVariable("PRINT_CONTENT", $template->get());
2439  }
2440 
2448  public function reviewobject()
2449  {
2450  if (!$this->access->checkAccess("write", "", $this->ref_id)) {
2451  // allow only write access
2452  $this->tpl->setOnScreenMessage('info', $this->lng->txt("cannot_edit_test"), true);
2453  $this->ctrl->redirect($this, "infoScreen");
2454  }
2455  $this->getTabsManager()->getQuestionsSubTabs();
2456  $template = new ilTemplate("tpl.il_as_tst_print_test_confirm.html", true, true, "Modules/Test");
2457 
2458  $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
2459 
2460  $max_points = 0;
2461  $counter = 1;
2462  $questionHeaderBlockBuilder = new ilTestQuestionHeaderBlockBuilder($this->lng);
2463  $questionHeaderBlockBuilder->setHeaderMode($this->object->getTitleOutput());
2464 
2465  foreach ($this->object->questions as $question) {
2466  $template->setCurrentBlock("question");
2467  $question_gui = $this->object->createQuestionGUI("", $question);
2468  $question_gui->setRenderPurpose(assQuestionGUI::RENDER_PURPOSE_PREVIEW);
2469 
2470  $questionHeaderBlockBuilder->setQuestionTitle($question_gui->object->getTitleForHTMLOutput());
2471  $questionHeaderBlockBuilder->setQuestionPoints($question_gui->object->getMaximumPoints());
2472  $questionHeaderBlockBuilder->setQuestionPosition($counter);
2473  $template->setVariable("QUESTION_HEADER", $questionHeaderBlockBuilder->getHTML());
2474 
2475  $template->setVariable("SOLUTION_OUTPUT", $question_gui->getPreview(false));
2476  $template->parseCurrentBlock("question");
2477  $counter++;
2478  $max_points += $question_gui->object->getMaximumPoints();
2479  }
2480 
2481  $template->setVariable("TITLE", strip_tags($this->object->getTitle(), ilObjectGUI::ALLOWED_TAGS_IN_TITLE_AND_DESCRIPTION));
2482  $template->setVariable(
2483  "PRINT_TEST",
2484  ilLegacyFormElementsUtil::prepareFormOutput($this->lng->txt("review_view"))
2485  );
2486  $template->setVariable("TXT_PRINT_DATE", ilLegacyFormElementsUtil::prepareFormOutput($this->lng->txt("date")));
2487  $usedRelativeDates = ilDatePresentation::useRelativeDates();
2489  $template->setVariable(
2490  "VALUE_PRINT_DATE",
2492  );
2493  ilDatePresentation::setUseRelativeDates($usedRelativeDates);
2494  $template->setVariable(
2495  "TXT_MAXIMUM_POINTS",
2496  ilLegacyFormElementsUtil::prepareFormOutput($this->lng->txt("tst_maximum_points"))
2497  );
2498  $template->setVariable("VALUE_MAXIMUM_POINTS", ilLegacyFormElementsUtil::prepareFormOutput($max_points));
2499 
2500  $template->setCurrentBlock("navigation_buttons");
2501  $template->setVariable("BUTTON_PRINT", $this->lng->txt("print"));
2502  $template->parseCurrentBlock();
2503 
2504  $this->tpl->setVariable("PRINT_CONTENT", $template->get());
2505  }
2506 
2510  public function defaultsObject()
2511  {
2512  if (!$this->access->checkAccess("write", "", $this->ref_id)) {
2513  $this->tpl->setOnScreenMessage('info', $this->lng->txt("cannot_edit_test"), true);
2514  $this->ctrl->redirect($this, "infoScreen");
2515  }
2516 
2517  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_SETTINGS);
2518 
2519  $this->toolbar->setFormAction($this->ctrl->getFormAction($this, 'addDefaults'));
2520  $this->toolbar->addFormButton($this->lng->txt('add'), 'addDefaults');
2521  $this->toolbar->addInputItem(new ilTextInputGUI($this->lng->txt('tst_defaults_defaults_of_test'), 'name'), true);
2522  $table = new ilTestPersonalDefaultSettingsTableGUI($this, 'defaults');
2523  $defaults = $this->object->getAvailableDefaults();
2524  $table->setData($defaults);
2525  $this->tpl->setContent($table->getHTML());
2526  }
2527 
2531  public function deleteDefaultsObject()
2532  {
2533  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2534  $this->redirectAfterMissingWrite();
2535  }
2536 
2537  if (isset($_POST['chb_defaults']) && is_array($_POST['chb_defaults']) && count($_POST['chb_defaults'])) {
2538  foreach ($_POST['chb_defaults'] as $test_default_id) {
2539  $this->object->deleteDefaults($test_default_id);
2540  }
2541  } else {
2542  $this->tpl->setOnScreenMessage('info', $this->lng->txt('select_one'));
2543  }
2544  $this->defaultsObject();
2545  }
2546 
2551  {
2552  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2553  $this->redirectAfterMissingWrite();
2554  }
2555 
2556  $this->applyDefaultsObject(true);
2557  return;
2558  }
2559 
2563  public function applyDefaultsObject($confirmed = false)
2564  {
2565  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2566  $this->redirectAfterMissingWrite();
2567  }
2568 
2569  if (!$confirmed) {
2570  if (!isset($_POST['chb_defaults']) || !is_array($_POST["chb_defaults"]) || 1 !== count($_POST["chb_defaults"])) {
2571  $this->tpl->setOnScreenMessage('info', $this->lng->txt("tst_defaults_apply_select_one"));
2572 
2573  $this->defaultsObject();
2574  return;
2575  }
2576  }
2577 
2578 
2579  // do not apply if user datasets exist
2580  if ($this->object->evalTotalPersons() > 0) {
2581  $this->tpl->setOnScreenMessage('info', $this->lng->txt("tst_defaults_apply_not_possible"));
2582 
2583  $this->defaultsObject();
2584  return;
2585  }
2586 
2587  if (!$confirmed) {
2588  $defaults = $this->object->getTestDefaults((int) $_POST["chb_defaults"][0]);
2589  } else {
2590  $defaults = $this->object->getTestDefaults((int) $_POST["confirmed_defaults_id"]);
2591  }
2592 
2593  $defaultSettings = unserialize($defaults["defaults"]);
2594 
2595  if (isset($defaultSettings['isRandomTest'])) {
2596  if ($defaultSettings['isRandomTest']) {
2597  $newQuestionSetType = ilObjTest::QUESTION_SET_TYPE_RANDOM;
2598  $this->object->setQuestionSetType(ilObjTest::QUESTION_SET_TYPE_RANDOM);
2599  } else {
2600  $newQuestionSetType = ilObjTest::QUESTION_SET_TYPE_FIXED;
2601  $this->object->setQuestionSetType(ilObjTest::QUESTION_SET_TYPE_FIXED);
2602  }
2603  } elseif (isset($defaultSettings['questionSetType'])) {
2604  $newQuestionSetType = $defaultSettings['questionSetType'];
2605  }
2606  $oldQuestionSetType = $this->object->getQuestionSetType();
2607  $questionSetTypeSettingSwitched = ($oldQuestionSetType != $newQuestionSetType);
2608 
2609  $oldQuestionSetConfig = $this->test_question_set_config_factory->getQuestionSetConfig();
2610 
2611  switch (true) {
2612  case !$questionSetTypeSettingSwitched:
2613  case !$oldQuestionSetConfig->doesQuestionSetRelatedDataExist():
2614  case $confirmed:
2615 
2616  break;
2617 
2618  default:
2619 
2620  $confirmation = new ilTestSettingsChangeConfirmationGUI($this->getTestObject());
2621 
2622  $confirmation->setFormAction($this->ctrl->getFormAction($this));
2623  $confirmation->setCancel($this->lng->txt('cancel'), 'defaults');
2624  $confirmation->setConfirm($this->lng->txt('confirm'), 'confirmedApplyDefaults');
2625 
2626  $confirmation->setOldQuestionSetType($this->object->getQuestionSetType());
2627  $confirmation->setNewQuestionSetType($newQuestionSetType);
2628  $confirmation->setQuestionLossInfoEnabled(false);
2629  $confirmation->build();
2630 
2631  $confirmation->addHiddenItem("confirmed_defaults_id", $_POST["chb_defaults"][0]);
2632 
2633  $this->tpl->setContent($this->ctrl->getHTML($confirmation));
2634 
2635  return;
2636  }
2637 
2638  if ($questionSetTypeSettingSwitched && !$this->object->getOfflineStatus()) {
2639  $this->object->setOfflineStatus(true);
2640 
2641  $info = $this->lng->txt("tst_set_offline_due_to_switched_question_set_type_setting");
2642 
2643  $this->tpl->setOnScreenMessage('info', $info, true);
2644  }
2645 
2646  $this->object->applyDefaults($defaults);
2647 
2648  $this->tpl->setOnScreenMessage('success', $this->lng->txt("tst_defaults_applied"), true);
2649 
2650  if ($questionSetTypeSettingSwitched && $oldQuestionSetConfig->doesQuestionSetRelatedDataExist()) {
2651  $oldQuestionSetConfig->removeQuestionSetRelatedData();
2652  }
2653 
2654  $this->ctrl->redirect($this, 'defaults');
2655  }
2656 
2660  public function addDefaultsObject()
2661  {
2662  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2663  $this->redirectAfterMissingWrite();
2664  }
2665 
2666  if (strlen($_POST["name"]) > 0) {
2667  $this->object->addDefaults($_POST['name']);
2668  } else {
2669  $this->tpl->setOnScreenMessage('info', $this->lng->txt("tst_defaults_enter_name"));
2670  }
2671  $this->defaultsObject();
2672  }
2673 
2674  private function isCommandClassAnyInfoScreenChild(): bool
2675  {
2676  if (in_array($this->ctrl->getCmdClass(), self::$infoScreenChildClasses)) {
2677  return true;
2678  }
2679 
2680  return false;
2681  }
2682 
2688  public function infoScreenObject()
2689  {
2690  $this->ctrl->setCmd("showSummary");
2691  $this->ctrl->setCmdClass("ilinfoscreengui");
2692  $this->infoScreen();
2693  }
2694 
2695  public function redirectToInfoScreenObject()
2696  {
2697  $this->ctrl->setCmd("showSummary");
2698  $this->ctrl->setCmdClass("ilinfoscreengui");
2699  $this->infoScreen($this->testrequest->raw('lock') ?? '');
2700  }
2701 
2705  public function infoScreen($session_lock = "")
2706  {
2707  if (!$this->access->checkAccess("visible", "", $this->ref_id) &&
2708  !$this->access->checkAccess("read", "", $this->ref_id)) {
2709  $this->redirectAfterMissingRead();
2710  return '';
2711  }
2712 
2713  if ($this->object->getMainSettings()->getAdditionalSettings()->getHideInfoTab()) {
2714  $this->ctrl->redirectByClass(ilTestScreenGUI::class, ilTestScreenGUI::DEFAULT_CMD);
2715  return '';
2716  }
2717 
2718  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_INFOSCREEN);
2719 
2720  if ($this->access->checkAccess("read", "", $this->ref_id)) {
2721  $this->trackTestObjectReadEvent();
2722  }
2723  $info = new ilInfoScreenGUI($this);
2724 
2725  if ($this->isCommandClassAnyInfoScreenChild()) {
2726  return $this->ctrl->forwardCommand($info);
2727  }
2728 
2730  $this->object,
2731  $this->test_player_factory->getPlayerGUI(),
2732  $this->test_question_set_config_factory->getQuestionSetConfig(),
2733  $this->test_session_factory->getSession(),
2734  $this->db,
2735  $this->access,
2736  $this->ctrl,
2737  $this->lng,
2740  $this->tpl,
2742  );
2743 
2744  $toolbar->setCloseFormTag(false);
2745 
2746  $toolbar->setSessionLockString($session_lock);
2747  $toolbar->build();
2748  $toolbar->sendMessages();
2749 
2750  $info->enablePrivateNotes();
2751 
2752  $info->addSection($this->lng->txt("tst_general_properties"));
2753  $info->addProperty(
2754  $this->lng->txt("author"),
2755  strip_tags(
2756  $this->object->getAuthor(),
2758  )
2759  );
2760  $info->addProperty(
2761  $this->lng->txt("title"),
2762  strip_tags(
2763  $this->object->getTitle(),
2765  )
2766  );
2767 
2768  if ($this->type !== 'tst') {
2769  $info->hideFurtherSections(false);
2770  }
2771 
2772  $info->addSection($this->lng->txt("tst_sequence_properties"));
2773  $info->addProperty(
2774  $this->lng->txt("tst_sequence"),
2775  $this->lng->txt(
2776  $this->object->getMainSettings()->getParticipantFunctionalitySettings()->getPostponedQuestionsMoveToEnd()
2777  ? "tst_sequence_postpone" : "tst_sequence_fixed"
2778  )
2779  );
2780 
2781  $info->addSection($this->lng->txt("tst_heading_scoring"));
2782  $info->addProperty($this->lng->txt("tst_text_count_system"), $this->lng->txt(($this->object->getCountSystem() == COUNT_PARTIAL_SOLUTIONS) ? "tst_count_partial_solutions" : "tst_count_correct_solutions"));
2783  if ($this->object->isRandomTest()) {
2784  $info->addProperty($this->lng->txt("tst_pass_scoring"), $this->lng->txt(($this->object->getPassScoring() == SCORE_BEST_PASS) ? "tst_pass_best_pass" : "tst_pass_last_pass"));
2785  }
2786 
2787  $info->addSection($this->lng->txt("tst_score_reporting"));
2788  $score_reporting_text = "";
2789  switch ($this->object->getScoreReporting()) {
2791  $score_reporting_text = $this->lng->txt("tst_report_after_test");
2792  break;
2794  $score_reporting_text = $this->lng->txt("tst_report_after_first_question");
2795  break;
2797  $score_reporting_text = $this->lng->txt("tst_report_after_date");
2798  break;
2800  $score_reporting_text = $this->lng->txt("tst_report_after_passed");
2801  break;
2802  default:
2803  $score_reporting_text = $this->lng->txt("tst_report_never");
2804  break;
2805  }
2806  $info->addProperty($this->lng->txt("tst_score_reporting"), $score_reporting_text);
2807  $reporting_date = $this->getTestObject()
2808  ->getScoreSettings()
2809  ->getResultSummarySettings()
2810  ->getReportingDate();
2811  if ($reporting_date !== null) {
2812  $info->addProperty(
2813  $this->lng->txt('tst_score_reporting_date'),
2815  $reporting_date
2816  ->format('YmdHis'),
2818  $reporting_date->getTimezone()->getName()
2819  ))
2820  );
2821  }
2822 
2823  $info->addSection($this->lng->txt("tst_session_settings"));
2824  $info->addProperty($this->lng->txt("tst_nr_of_tries"), $this->object->getNrOfTries() === 0 ? $this->lng->txt("unlimited") : (string) $this->object->getNrOfTries());
2825  if ($this->object->getNrOfTries() != 1) {
2826  $info->addProperty(
2827  $this->lng->txt('tst_nr_of_tries_of_user'),
2828  ($this->test_session_factory->getSession()->getPass() === 0) ?
2829  $this->lng->txt("tst_no_tries") : (string) $this->test_session_factory->getSession()->getPass()
2830  );
2831  }
2832 
2833  if ($this->object->getEnableProcessingTime()) {
2834  $info->addProperty($this->lng->txt("tst_processing_time"), $this->object->getProcessingTime());
2835  }
2836 
2837  $starting_time = $this->object->getStartingTime();
2838  if ($this->object->isStartingTimeEnabled() && $starting_time !== 0) {
2839  $info->addProperty($this->lng->txt("tst_starting_time"), ilDatePresentation::formatDate(new ilDateTime($starting_time, IL_CAL_UNIX)));
2840  }
2841  $ending_time = $this->object->getEndingTime();
2842  if ($this->object->isEndingTimeEnabled() && $ending_time != 0) {
2843  $info->addProperty($this->lng->txt("tst_ending_time"), ilDatePresentation::formatDate(new ilDateTime($ending_time, IL_CAL_UNIX)));
2844  }
2845  $info->addMetaDataSections($this->object->getId(), 0, $this->object->getType());
2846 
2847  $this->ctrl->forwardCommand($info);
2848  return null;
2849  }
2850 
2851  protected function removeImportFailsObject()
2852  {
2853  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
2854  $this->redirectAfterMissingWrite();
2855  }
2856 
2857  $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($this->object->getId());
2858  $qsaImportFails->deleteRegisteredImportFails();
2859  $sltImportFails = new ilTestSkillLevelThresholdImportFails($this->object->getId());
2860  $sltImportFails->deleteRegisteredImportFails();
2861 
2862  $this->ctrl->redirect($this, 'infoScreen');
2863  }
2864 
2865  public function addLocatorItems(): void
2866  {
2867  switch ($this->ctrl->getCmd()) {
2868  case "run":
2869  case "infoScreen":
2870  case "redirectToInfoScreen":
2871  case "start":
2872  case "resume":
2873  case "previous":
2874  case "next":
2875  case "summary":
2876  case "finishTest":
2877  case "outCorrectSolution":
2878  case "passDetails":
2879  case "showAnswersOfUser":
2880  case "outUserResultsOverview":
2881  case "backFromSummary":
2882  case "show_answers":
2883  case "setsolved":
2884  case "resetsolved":
2885  case "outTestSummary":
2886  case "outQuestionSummary":
2887  case "gotoQuestion":
2888  case "selectImagemapRegion":
2889  case "confirmSubmitAnswers":
2890  case "finalSubmission":
2891  case "postpone":
2892  case "outUserPassDetails":
2893  case "checkPassword":
2894  $this->locator->addItem(
2895  $this->object->getTitle(),
2896  $this->ctrl->getLinkTargetByClass(ilTestScreenGUI::class, ilTestScreenGUI::DEFAULT_CMD),
2897  '',
2898  $this->testrequest->getRefId()
2899  );
2900  break;
2901  case "eval_stat":
2902  case "evalAllUsers":
2903  case "evalUserDetail":
2904  $this->locator->addItem($this->object->getTitle(), $this->ctrl->getLinkTarget($this, "eval_stat"), "", $this->testrequest->getRefId());
2905  break;
2906  case "create":
2907  case "save":
2908  case "cancel":
2909  case "importFile":
2910  case "cloneAll":
2911  case "importVerifiedFile":
2912  case "cancelImport":
2913  break;
2914  default:
2915  $this->locator->addItem($this->object->getTitle(), $this->ctrl->getLinkTargetByClass(ilTestScreenGUI::class, ilTestScreenGUI::DEFAULT_CMD), '', $this->testrequest->getRefId());
2916  break;
2917  }
2918  }
2919 
2920  public function statisticsObject()
2921  {
2922  }
2923 
2927  public function certificateObject()
2928  {
2929  $this->tabs_gui->activateTab(ilTestTabsManager::TAB_ID_SETTINGS);
2930 
2931  $guiFactory = new ilCertificateGUIFactory();
2932  $output_gui = $guiFactory->create($this->object);
2933 
2934  $output_gui->certificateEditor();
2935  }
2936 
2942  public function getTabs(): void
2943  {
2944  $this->help->setScreenIdComponent("tst");
2945 
2946  if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
2947  $courseLink = ilLink::_getLink($this->getObjectiveOrientedContainer()->getRefId());
2948  $this->getTabsManager()->setParentBackLabel($this->lng->txt('back_to_objective_container'));
2949  $this->getTabsManager()->setParentBackHref($courseLink);
2950  }
2951 
2952  $this->getTabsManager()->perform();
2953  }
2954 
2955  protected function setTitleAndDescription(): void
2956  {
2957  parent::setTitleAndDescription();
2958 
2959  $icon = ilObject::_getIcon($this->object->getId(), 'big', $this->object->getType());
2960  $this->tpl->setTitleIcon($icon, $this->lng->txt('obj_' . $this->object->getType()));
2961  }
2962 
2963  public static function accessViolationRedirect()
2964  {
2966  global $DIC;
2967  $main_tpl = $DIC->ui()->mainTemplate();
2968 
2969  $main_tpl->setOnScreenMessage('failure', $DIC->language()->txt("no_permission"), true);
2970  $DIC->ctrl()->redirectByClass(ilTestScreenGUI::class, ilTestScreenGUI::DEFAULT_CMD);
2971  }
2972 
2979  public static function _goto($target)
2980  {
2981  global $DIC;
2982  $main_tpl = $DIC->ui()->mainTemplate();
2983  $ilAccess = $DIC['ilAccess'];
2984  $ilErr = $DIC['ilErr'];
2985  $lng = $DIC['lng'];
2986 
2987  if ($ilAccess->checkAccess("read", "", (int) $target) || $ilAccess->checkAccess("visible", "", (int) $target)) {
2988  $DIC->ctrl()->setParameterByClass('ilObjTestGUI', 'ref_id', (int) $target);
2989  $DIC->ctrl()->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilTestScreenGUI::class], ilTestScreenGUI::DEFAULT_CMD);
2990  } elseif ($ilAccess->checkAccess("read", "", ROOT_FOLDER_ID)) {
2991  $main_tpl->setOnScreenMessage('info', sprintf(
2992  $lng->txt("msg_no_perm_read_item"),
2994  ), true);
2996  }
2997 
2998  $ilErr->raiseError($lng->txt("msg_no_perm_read_lm"), $ilErr->FATAL);
2999  }
3000 
3001  public function buildPageViewToolbar($qid = 0)
3002  {
3003  if ($this->create_question_mode) {
3004  return;
3005  }
3006  $this->ctrl->saveParameter($this, 'q_mode');
3007 
3008  $this->ctrl->setParameterByClass('iltestexpresspageobjectgui', 'test_express_mode', 1);
3009  $this->ctrl->setParameter($this, 'test_express_mode', 1);
3010  $this->ctrl->setParameterByClass('iltestexpresspageobjectgui', 'q_id', $this->testrequest->raw('q_id'));
3011  $this->ctrl->setParameter($this, 'q_id', $this->testrequest->raw('q_id'));
3012  $this->toolbar->setFormAction($this->ctrl->getFormActionByClass('iltestexpresspageobjectgui', 'edit'));
3013 
3014  if ($this->object->evalTotalPersons() == 0) {
3015  $this->toolbar->addFormButton($this->lng->txt("ass_create_question"), "addQuestion");
3016 
3017  $this->toolbar->addSeparator();
3018 
3020 
3021  $show_separator = true;
3022  }
3023 
3024  $questions = $this->object->getQuestionTitlesAndIndexes();
3025 
3026  // desc
3027  $options = [];
3028  foreach ($questions as $id => $label) {
3029  $options[$id] = $label . ' [' . $this->lng->txt('question_id_short') . ': ' . $id . ']';
3030  }
3031 
3032  $optionKeys = array_keys($options);
3033 
3034  if (!$options) {
3035  $options[] = $this->lng->txt('none');
3036  }
3037 
3038  if (count($questions)) {
3039  if (isset($show_separator) && $show_separator) {
3040  $this->toolbar->addSeparator();
3041  }
3042 
3043  $btn = $this->ui[0]->linkButton()->standard($lng->txt("test_prev_question"), $this->ctrl->getLinkTargetByClass('iltestexpresspageobjectgui', 'prevQuestion'));
3044  $this->toolbar->addComponent($btn);
3045 
3046  if (count($options) <= 1 || $optionKeys[0] == $qid) {
3047  $btn->setDisabled(true);
3048  }
3049 
3050  $btn = $this->ui[0]->linkButton()->standard($lng->txt("test_next_question"), $this->ctrl->getLinkTargetByClass('iltestexpresspageobjectgui', 'nextQuestion'));
3051  $this->toolbar->addComponent($btn);
3052 
3053  if (count($options) <= 1 || $optionKeys[count($optionKeys) - 1] == $qid) {
3054  $btn->setDisabled(true);
3055  }
3056  }
3057 
3058  if (count($questions) > 1) {
3059  $this->toolbar->addSeparator();
3060  $si = new ilSelectInputGUI($this->lng->txt("test_jump_to"), "q_id");
3061  $si->addCustomAttribute("onChange=\"forms['ilToolbar'].submit();\"");
3062  $si->setOptions($options);
3063 
3064  if ($qid) {
3065  $si->setValue($qid);
3066  }
3067 
3068  $this->toolbar->addInputItem($si, true);
3069  }
3070 
3071  $total = $this->object->evalTotalPersons();
3072 
3073  if (count($questions) && !$total) {
3074  $this->ctrl->setParameter($this, 'q_id', $this->testrequest->raw('q_id'));
3075  $this->toolbar->addSeparator();
3076  $this->toolbar->addButton($this->lng->txt("test_delete_page"), $this->ctrl->getLinkTarget($this, "removeQuestions"));
3077  }
3078 
3079  if (count($questions) > 1 && !$total) {
3080  $this->toolbar->addSeparator();
3081  $this->toolbar->addButton($this->lng->txt("test_move_page"), $this->ctrl->getLinkTarget($this, "movePageForm"));
3082  }
3083 
3084  $online_access = false;
3085  if ($this->object->getFixedParticipants()) {
3086  $online_access = ilObjTestAccess::_lookupOnlineTestAccess($this->object->getId(), $this->user->getId()) === true;
3087  }
3088 
3089  if (!$this->object->getOfflineStatus() && $this->object->isComplete($this->test_question_set_config_factory->getQuestionSetConfig())) {
3090  if ((!$this->object->getFixedParticipants() || $online_access) && $this->access->checkAccess("read", "", $this->ref_id)) {
3091  $testSession = $this->test_session_factory->getSession();
3092 
3093  $executable = $this->object->isExecutable($testSession, $this->user->getId(), true);
3094 
3095  if ($executable["executable"]) {
3096  $player_factory = new ilTestPlayerFactory($this->getTestObject());
3097  $player_instance = $player_factory->getPlayerGUI();
3098 
3099  $this->toolbar->addSeparator();
3100  if ($testSession->getActiveId() > 0) {
3101  $this->toolbar->addButton($this->lng->txt('tst_resume_test'), $this->ctrl->getLinkTarget($player_instance, 'resumePlayer'));
3102  } else {
3103  $this->toolbar->addButton($this->lng->txt('tst_start_test'), $this->ctrl->getLinkTarget($player_instance, 'startTest'));
3104  }
3105  }
3106  }
3107  }
3108  }
3109 
3110  public function copyQuestionsToPoolObject()
3111  {
3112  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
3113  $this->redirectAfterMissingWrite();
3114  }
3115 
3116  $this->copyQuestionsToPool($this->testrequest->raw('q_id'), $this->testrequest->raw('sel_qpl'));
3117  $this->ctrl->redirect($this, 'questions');
3118  }
3119 
3124  public function copyQuestionsToPool(array $question_ids, int $qpl_id): stdClass
3125  {
3126  $new_ids = [];
3127  foreach ($question_ids as $q_id) {
3128  $new_id = $this->copyQuestionToPool($q_id, $qpl_id);
3129  $new_ids[$q_id] = $new_id;
3130  }
3131 
3132  $result = new stdClass();
3133  $result->ids = $new_ids;
3134  $result->qpoolid = $qpl_id;
3135 
3136  return $result;
3137  }
3138 
3139  public function copyQuestionToPool(int $source_question_id, int $target_parent_id)
3140  {
3141  $question_gui = assQuestion::instantiateQuestionGUI($source_question_id);
3142 
3143  $new_title = $question_gui->object->getTitle();
3144  if ($this->questioninfo->questionTitleExistsInPool($target_parent_id, $question_gui->object->getTitle())) {
3145  $counter = 2;
3146  while ($this->questioninfo->questionTitleExistsInPool($target_parent_id, $question_gui->object->getTitle() . " ($counter)")) {
3147  $counter++;
3148  }
3149  $new_title = $question_gui->object->getTitle() . " ($counter)";
3150  }
3151 
3152  return $question_gui->object->createNewOriginalFromThisDuplicate($target_parent_id, $new_title);
3153  }
3154 
3159  {
3160  if ($this->testrequest->int('sel_qpl') === 0) {
3161  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("questionpool_not_selected"));
3163  return;
3164  }
3165 
3166  $qpl_id = $this->obj_data_cache->lookupObjId($this->testrequest->int('sel_qpl'));
3167 
3168  $question_ids = $this->testrequest->getQuestionIds();
3169  $question_id = $this->testrequest->getQuestionId();
3170  if ($question_ids === [] && $question_id !== 0) {
3171  $question_ids = [$question_id];
3172  }
3173  $result = $this->copyQuestionsToPool($question_ids, $qpl_id);
3174 
3175  foreach ($result->ids as $oldId => $newId) {
3176  $questionInstance = assQuestion::instantiateQuestion($oldId);
3177 
3178  $original_question_id = $questionInstance->getOriginalId();
3179  if ($original_question_id !== null
3180  && $this->questioninfo->originalQuestionExists($original_question_id)) {
3181  $oldOriginal = assQuestion::instantiateQuestion($original_question_id);
3182  $oldOriginal->delete($oldOriginal->getId());
3183  }
3184  assQuestion::saveOriginalId($questionInstance->getId(), $newId);
3185  }
3186 
3187  $this->tpl->setOnScreenMessage('success', $this->lng->txt('tst_qst_added_to_pool_' . (count($result->ids) > 1 ? 'p' : 's')), true);
3188  $this->ctrl->redirect($this, 'questions');
3189  }
3190 
3192  {
3193  $form = new ilPropertyFormGUI();
3194 
3195  $title = new ilTextInputGUI($this->lng->txt('title'), 'title');
3196  $title->setRequired(true);
3197  $form->addItem($title);
3198 
3199  $description = new ilTextAreaInputGUI($this->lng->txt('description'), 'description');
3200  $form->addItem($description);
3201 
3202  $form->addCommandButton('createQuestionPoolAndCopy', $this->lng->txt('create'));
3203 
3204  if ($this->testrequest->isset('q_id') && is_array($this->testrequest->raw('q_id'))) {
3205  foreach ($this->testrequest->raw('q_id') as $id) {
3206  $hidden = new ilHiddenInputGUI('q_id[]');
3207  $hidden->setValue($id);
3208  $form->addItem($hidden);
3209  }
3210  }
3211 
3212  return $form;
3213  }
3214 
3215  public function copyToQuestionpoolObject()
3216  {
3217  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
3218  $this->redirectAfterMissingWrite();
3219  }
3220 
3221  $this->createQuestionpoolTargetObject('copyQuestionsToPool');
3222  }
3223 
3225  {
3226  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
3227  $this->redirectAfterMissingWrite();
3228  }
3229 
3230  // #13761; All methods use for this request should be revised, thx japo ;-)
3231  if (
3232  'copyAndLinkToQuestionpool' == $this->ctrl->getCmd() &&
3233  (!$this->testrequest->isset('q_id') || !is_array($this->testrequest->raw('q_id')))
3234  ) {
3235  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('tst_no_question_selected_for_moving_to_qpl'), true);
3236  $this->ctrl->redirect($this, 'questions');
3237  }
3238 
3239  foreach ($this->testrequest->getQuestionIds('q_id') as $q_id) {
3240  if (!$this->questioninfo->originalQuestionExists($q_id)) {
3241  continue;
3242  }
3243 
3244  $type = ilObject::_lookupType(assQuestion::lookupParentObjId($this->questioninfo->getOriginalId($q_id)));
3245 
3246  if ($type !== 'tst') {
3247  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('tst_link_only_unassigned'), true);
3248  $this->ctrl->redirect($this, 'questions');
3249  return;
3250  }
3251  }
3252 
3253  $this->createQuestionpoolTargetObject('copyAndLinkQuestionsToPool');
3254  }
3255 
3257  {
3258  if (!$this->access->checkAccess('write', '', $this->object->getRefId())
3259  || !$this->checkPermissionBool('create', '', 'qpl')) {
3260  $this->redirectAfterMissingWrite();
3261  }
3262 
3263  if ($this->testrequest->raw('title')) {
3264  $title = $this->testrequest->raw('title');
3265  } else {
3266  $title = $this->testrequest->raw('txt_qpl');
3267  }
3268 
3269  if (!$title) {
3270  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("questionpool_not_entered"));
3272  return;
3273  }
3274 
3275  $ref_id = $this->createQuestionPool($title, $this->testrequest->raw('description'));
3276  $_REQUEST['sel_qpl'] = $ref_id;
3277 
3278  //if ($_REQUEST['link'])
3279  //{
3281  //}
3282  //else
3283  //{
3284  // $this->copyQuestionsToPoolObject();
3285  //}
3286  }
3287 
3294  public function createQuestionpoolTargetObject($cmd)
3295  {
3296  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
3297  $this->redirectAfterMissingWrite();
3298  }
3299 
3300  $this->getTabsManager()->getQuestionsSubTabs();
3302 
3303  $questionpools = $this->object->getAvailableQuestionpools(
3304  false,
3305  false,
3306  false,
3307  true,
3308  false,
3309  "write"
3310  );
3311 
3312  if (count($questionpools) == 0) {
3313  $form = $this->getTargetQuestionpoolForm($questionpools, 'createQuestionPoolAndCopy');
3314  } else {
3315  $form = $this->getTargetQuestionpoolForm($questionpools, $cmd);
3316 
3317  switch ($cmd) {
3318  case 'copyQuestionsToPool':
3319  break;
3320 
3321  case 'copyAndLinkQuestionsToPool':
3322  $hidden = new ilHiddenInputGUI('link');
3323  $hidden->setValue('1');
3324  $form->addItem($hidden);
3325  break;
3326  }
3327  }
3328 
3329  $this->tpl->setContent($form->getHTML());
3330  }
3331 
3332  protected function getTargetQuestionpoolForm($questionpools, $cmd): ilPropertyFormGUI
3333  {
3334  $form = new ilPropertyFormGUI();
3335  $form->setFormAction($this->ctrl->getFormAction($this));
3336  $form->addCommandButton($cmd, $this->lng->txt('submit'));
3337  $form->addCommandButton('cancelCreateQuestion', $this->lng->txt('cancel'));
3338 
3339  if (count($questionpools) == 0) {
3340  $form->setTitle($this->lng->txt("tst_enter_questionpool"));
3341 
3342  $title = new ilTextInputGUI($this->lng->txt('title'), 'title');
3343  $title->setRequired(true);
3344  $form->addItem($title);
3345 
3346  $description = new ilTextAreaInputGUI($this->lng->txt('description'), 'description');
3347  $form->addItem($description);
3348  } else {
3349  $form->setTitle($this->lng->txt("tst_select_questionpool"));
3350 
3351  $selectOptions = [
3352  '' => $this->lng->txt('please_select')
3353  ];
3354 
3355  foreach ($questionpools as $key => $value) {
3356  $selectOptions[$key] = $value["title"];
3357  }
3358 
3359  $select = new ilSelectInputGUI($this->lng->txt('tst_source_question_pool'), 'sel_qpl');
3360  $select->setRequired(true);
3361  $select->setOptions($selectOptions);
3362 
3363  $form->addItem($select);
3364  }
3365 
3366  if ($this->testrequest->isset('q_id') && is_array($this->testrequest->raw('q_id'))) {
3367  foreach ($this->testrequest->raw('q_id') as $id) {
3368  $hidden = new ilHiddenInputGUI('q_id[]');
3369  $hidden->setValue($id);
3370  $form->addItem($hidden);
3371  }
3372  }
3373 
3374  return $form;
3375  }
3376 
3378  {
3379  if (!$this->access->checkAccess("write", "", $this->ref_id)) {
3380  // allow only write access
3381  $this->tpl->setOnScreenMessage('info', $this->lng->txt("cannot_edit_test"), true);
3382  $this->ctrl->redirect($this, "infoScreen");
3383  }
3384 
3385  $order = $this->testrequest->raw('order') ?? [];
3386  $obligatory_questions = $this->testrequest->raw('obligatory') ?? [];
3387 
3388  foreach ($order as $question_id => $order) {
3389  $orders[$question_id] = $order;
3390  }
3391 
3392  if ($this->object->areObligationsEnabled()) {
3393  foreach ($obligatory_questions as $question_id => $obligation) {
3394  if (!ilObjTest::isQuestionObligationPossible($question_id)) {
3395  unset($obligatory_questions[$question_id]);
3396  }
3397  }
3398  }
3399 
3400  $this->object->setQuestionOrderAndObligations(
3401  $orders,
3402  $obligatory_questions
3403  );
3404 
3405  $this->tpl->setOnScreenMessage('success', $this->lng->txt('saved_successfully'), true);
3406  $this->ctrl->redirect($this, 'questions');
3407  }
3408 
3412  protected function movePageFormObject()
3413  {
3414  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
3415  $this->redirectAfterMissingWrite();
3416  }
3417 
3418  $form = new ilPropertyFormGUI();
3419  $form->setFormAction($this->ctrl->getFormAction($this, "movePage"));
3420  $form->setTitle($this->lng->txt("test_move_page"));
3421 
3422  $old_pos = new ilHiddenInputGUI("q_id");
3423  $old_pos->setValue($this->testrequest->raw('q_id'));
3424  $form->addItem($old_pos);
3425 
3426  $questions = $this->object->getQuestionTitlesAndIndexes();
3427  if (!is_array($questions)) {
3428  $questions = [];
3429  }
3430 
3431  foreach ($questions as $k => $q) {
3432  if ($k == $this->testrequest->raw('q_id')) {
3433  unset($questions[$k]);
3434  continue;
3435  }
3436  $questions[$k] = $this->lng->txt('behind') . ' ' . $q;
3437  }
3438 
3439  $options = [
3440  0 => $this->lng->txt('first')
3441  ];
3442  foreach ($questions as $k => $q) {
3443  $options[$k] = $q . ' [' . $this->lng->txt('question_id_short') . ': ' . $k . ']';
3444  }
3445 
3446  $pos = new ilSelectInputGUI($this->lng->txt("position"), "position_after");
3447  $pos->setOptions($options);
3448  $form->addItem($pos);
3449 
3450  $form->addCommandButton("movePage", $this->lng->txt("submit"));
3451  $form->addCommandButton("showPage", $this->lng->txt("cancel"));
3452 
3453  return $this->tpl->setContent($form->getHTML());
3454  }
3455 
3456  public function movePageObject()
3457  {
3458  if (!$this->access->checkAccess("write", "", $this->ref_id)) {
3459  // allow only write access
3460  $this->tpl->setOnScreenMessage('info', $this->lng->txt("cannot_edit_test"), true);
3461  $this->ctrl->redirect($this, "infoScreen");
3462  }
3463 
3464  $this->object->moveQuestionAfter($this->testrequest->raw('q_id'), $this->testrequest->raw('position_after'));
3465  $this->showPageObject();
3466  }
3467 
3468  public function showPageObject()
3469  {
3470  $this->ctrl->setParameterByClass('iltestexpresspageobjectgui', 'q_id', $this->testrequest->raw('q_id'));
3471  $this->ctrl->redirectByClass('iltestexpresspageobjectgui', 'showPage');
3472  }
3473 
3474  public function copyQuestionObject()
3475  {
3476  if (!$this->access->checkAccess("write", "", $this->ref_id)) {
3477  // allow only write access
3478  $this->tpl->setOnScreenMessage('info', $this->lng->txt("cannot_edit_test"), true);
3479  $this->ctrl->redirect($this, "infoScreen");
3480  }
3481 
3482  if ($this->testrequest->hasQuestionId() && !is_array($this->testrequest->raw('q_id'))) {
3483  $ids = [$this->testrequest->getQuestionId()];
3484  } elseif ($this->testrequest->getQuestionIds()) {
3485  $ids = $this->testrequest->getQuestionIds();
3486  } else {
3487  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('copy_no_questions_selected'), true);
3488  $this->ctrl->redirect($this, 'questions');
3489  }
3490 
3491  $copy_count = 0;
3492 
3493  $questionTitles = $this->object->getQuestionTitles();
3494 
3495  foreach ($ids as $id) {
3496  $question = assQuestion::instantiateQuestionGUI($id);
3497  if ($question) {
3498  $title = $question->object->getTitle();
3499  $i = 2;
3500  while (in_array($title . ' (' . $i . ')', $questionTitles)) {
3501  $i++;
3502  }
3503 
3504  $title .= ' (' . $i . ')';
3505 
3506  $questionTitles[] = $title;
3507 
3508  $new_id = $question->object->duplicate(false, $title);
3509 
3510  $clone = assQuestion::instantiateQuestionGUI($new_id);
3511  $clone->object->setObjId($this->object->getId());
3512  $clone->object->saveToDb();
3513 
3514  $this->object->insertQuestion($this->test_question_set_config_factory->getQuestionSetConfig(), $new_id, true);
3515 
3516  $copy_count++;
3517  }
3518  }
3519 
3520  $this->tpl->setOnScreenMessage('success', $this->lng->txt('copy_questions_success'), true);
3521 
3522  $this->ctrl->redirect($this, 'questions');
3523  }
3524 
3526  {
3527  if (!ilLOSettings::isObjectiveTest($this->ref_id)) {
3528  return;
3529  }
3530 
3531  $path = $this->tree->getPathFull($this->ref_id);
3532 
3533  while ($parent = array_pop($path)) {
3534  if ($parent['type'] === 'crs') {
3535  $container_ref_id = $parent['ref_id'];
3536  break;
3537  }
3538  }
3539 
3540  $container_obj_id = ilObject2::_lookupObjId($container_ref_id);
3541 
3542  $this->objective_oriented_container->setObjId($container_obj_id);
3543  $this->objective_oriented_container->setRefId($container_ref_id);
3544  }
3545 
3547  {
3549  }
3550 
3552  {
3553  return new ilTestScreenGUI(
3554  $this->object,
3555  $this->user,
3556  $this->ui_factory,
3557  $this->ui_renderer,
3558  $this->lng,
3559  $this->refinery,
3560  $this->ctrl,
3561  $this->tpl,
3562  $this->content_style,
3563  $this->http,
3564  $this->tabs_gui,
3565  $this->access,
3566  $this->db,
3567  $this->rbac_system
3568  );
3569  }
3570 }
const MATCHING_QUESTION_IDENTIFIER
initImportForm(string $new_type)
const MULTIPLE_CHOICE_QUESTION_IDENTIFIER
setTestOBJ(ilObjTest $test_object)
const ADDITIONAL_CONTENT_EDITING_MODE_IPE
ilObjectDefinition $obj_definition
const QT_NUMERIC
static get(string $a_var)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
populateQuestionBrowserToolbarButtons(ilToolbarGUI $toolbar, string $context)
static _goto($target)
Redirect script to call a test with the test reference id.
setTestAccess(ilTestAccess $testAccess)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Readable part of repository interface to ilComponentDataDB.
ilTestQuestionSetConfigFactory $test_question_set_config_factory
static appendUrlParameterString(string $a_url, string $a_par, bool $xml_style=false)
exit
Definition: login.php:29
Class ilInfoScreenGUI.
ilTestSessionFactory $test_session_factory
ilTabsGUI $tabs_gui
const ERROR_TEXT_IDENTIFIER
$context
Definition: webdav.php:31
static isQuestionObligationPossible(int $question_id)
createQuestionObject()
Called when a new question should be created from a test.
const IL_INST_ID
Definition: constants.php:40
setCloseFormTag(bool $a_val)
getTabs()
adds tabs to tab gui object
static _getIcon(int $obj_id=0, string $size="big", string $type="", bool $offline=false)
Get icon for repository item.
Export User Interface Class.
Class ilObjTestGUI.
Class ilTestScreenGUI.
static _getLog(int $ts_from, int $ts_to, int $test_id, bool $test_only=false)
Retrieve assessment log datasets from the database.
This class represents a selection list property in a property form.
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
reviewobject()
Review tab to create a print of all questions without points and solutions.
fullscreenObject()
show fullscreen view
GUI class for the workflow of copying objects.
const QUESTION_SET_TYPE_RANDOM
uploadObject($redirect=true)
display status information or report errors messages in case of error
const ROOT_FOLDER_ID
Definition: constants.php:32
__construct($data, int $id=0, bool $call_by_reference=true, bool $prepare_output=true)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getAvailableQuestionpools( $use_object_id=false, $equal_points=false, $could_be_offline=false, $showPath=false, $with_questioncount=false, $permission='read', $usr_id='')
Returns the available question pools for the active user.
prepareOutput(bool $show_sub_objects=true)
cancelCreateQuestionObject()
Called when the creation of a new question is cancelled.
Provides fluid interface to LoggingServices.
This class represents a file property in a property form.
buildPageViewToolbar($qid=0)
ilComponentFactory $component_factory
setInfo(string $a_info)
afterSave(ilObject $new_object)
save object public
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
static getQuestionTypeByTypeId($type_id)
static getImagePath(string $img, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
Help GUI class.
insertQuestionsBeforeObject()
Insert checked questions before the actual selection.
const KPRIM_CHOICE_QUESTION_IDENTIFIER
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false)
getDidacticTemplateVar(string $type)
Get didactic template setting from creation screen.
const LONG_MENU_QUESTION_IDENTIFIER
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const TEXTSUBSET_QUESTION_IDENTIFIER
static lookupParentObjId(int $questionId)
const QT_ORDERING
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Import class.
$refId
Definition: xapitoken.php:58
setTabsManager(ilTestTabsManager $tabs_manager)
historyObject()
Creates the change history for a test.
downloadFileObject()
download file
setSuffixes(array $a_suffixes)
createQuestionpoolTargetObject($cmd)
Called when a new question should be created from a test Important: $cmd may be overwritten if no que...
createObject()
create new object form
setOptions(array $a_options)
Scoring class for tests.
redirectTo_ilObjTestSettingsMainGUI_showForm_Object()
ilDBInterface $db
confirmRemoveQuestionsObject()
Remove questions from the test after confirmation.
static prepareFormOutput($a_str, bool $a_strip=false)
const IL_CAL_UNIX
UIRenderer $ui_renderer
static getStyleSheetLocation(string $mode="output", string $a_css_name="", string $a_css_location="")
get full style sheet file name (path inclusive) of current user
infoScreen($session_lock="")
show information screen
UIFactory $ui_factory
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static $infoScreenChildClasses
static _getQuestionGUI(string $question_type='', int $question_id=-1)
Creates a question gui representation and returns the alias to the question gui.
copyQuestionToPool(int $source_question_id, int $target_parent_id)
addDefaultsObject()
Adds the defaults of this test to the defaults.
Base Exception for all Exceptions relating to Modules/Test.
$ilErr
Definition: raiseError.php:17
$path
Definition: ltiservices.php:32
participantsActionObject()
Evaluates the actions on the participants page.
const FILE_UPLOAD_IDENTIFIER
ilObjectDataCache $obj_data_cache
uploadTst()
imports test and question(s)
static _lookupObjId(int $ref_id)
static instantiateQuestionGUI(int $a_question_id)
setCreationMode(bool $mode=true)
If true, a creation screen is displayed the current [ref_id] does belong to the parent class The mode...
cancelRemoveQuestionsObject()
Cancels the removal of questions from the test.
Interface ilCtrlBaseClassInterface describes ilCtrl base classes.
global $DIC
Definition: feed.php:28
defaultsObject()
Displays the settings page for test defaults.
HTTPServices $http
ContentStyle $content_style
ilLanguage $lng
const QT_FILEUPLOAD
copyAndLinkQuestionsToPoolObject()
ilObjectDataCache $ilObjDataCache
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _lookupOnlineTestAccess($a_test_id, $a_user_id)
Checks if a user is allowd to run an online exam.
static instantiateQuestion(int $question_id)
const ALLOWED_TAGS_IN_TITLE_AND_DESCRIPTION
const QT_KPRIM_CHOICE
Importer class for files.
static _needsManualScoring(int $question_id)
static http()
Fetches the global http state from ILIAS.
This class represents a property in a property form.
__construct(VocabulariesInterface $vocabularies)
addButton(string $a_txt, string $a_cmd, string $a_target="", ?int $a_acc_key=null, string $a_additional_attrs='', string $a_id="", string $a_class='submit')
ilGlobalTemplateInterface $tpl
ilObjTestSettingsMainGUI: ilPropertyFormGUI ilObjTestSettingsMainGUI: ilConfirmationGUI ilObjTestSe...
static _lookupTitle(int $obj_id)
const NUMERIC_QUESTION_IDENTIFIER
ilNavigationHistory $navigation_history
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
copyQuestionsToPool(array $question_ids, int $qpl_id)
$log
Definition: result.php:33
removeQuestionsObject()
Called when a selection of questions should be removed from the test.
const ORDERING_HORIZONTAL_IDENTIFIER
const QT_FORMULA
const COUNT_PARTIAL_SOLUTIONS
ilTestObjectiveOrientedContainer $objective_oriented_container
applyDefaultsObject($confirmed=false)
Applies the selected test defaults.
download_paragraphObject()
download source code paragraph
ilTestPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI ilTestPageGUI: ilPublicUserProfile...
const QT_MULTIPLE_CHOICE_SR
Class ilObjectGUI Basic methods of all Output classes.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
setValue(string $a_value)
const ORDERING_QUESTION_IDENTIFIER
insertQuestionsAfterObject()
Insert checked questions after the actual selection.
ilTestPlayerFactory $test_player_factory
static _recordReadEvent(string $a_type, int $a_ref_id, int $obj_id, int $usr_id, bool $isCatchupWriteEvents=true, $a_ext_rc=null, $a_ext_time=null)
InternalRequestService $testrequest
createQuestionPool($name="dummy", $description="")
Creates a new questionpool and returns the reference id.
ilTestAccess $test_access
Class ilObjFile.
const QT_ERRORTEXT
string $key
Consumer key/client ID value.
Definition: System.php:193
showEditTestPageGUI(string $cmd)
Output class for assessment test evaluation.
ilToolbarGUI $toolbar
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
infoScreenObject()
this one is called from the info button in the repository not very nice to set cmdClass/Cmd manually...
insertQuestionsBeforeOrAfter(int $insert_mode)
const TEXT_QUESTION_IDENTIFIER
Basic GUI class for assessment questions.
addDidacticTemplateOptions(array &$options)
const QT_LONG_MENU
$txt
Definition: error.php:14
setRequired(bool $a_required)
static getContentStylePath(int $a_style_id, bool $add_random=true, bool $add_token=true)
get content style path static (to avoid full reading)
Last visited history for repository items.
static saveOriginalId(int $questionId, int $originalId)
setCustomRolesForSelection(array $a_roles)
Set custom roles for mapping to LTI roles.
getTargetQuestionpoolForm($questionpools, $cmd)
ILIAS Filesystem Util Archive LegacyArchives $archives
const QT_MULTIPLE_CHOICE_MR
checkPermissionBool(string $perm, string $cmd="", string $type="", ?int $ref_id=null)
QuestionInfoService $questioninfo
static isObjectiveTest(int $a_trst_ref_id)
Check if test ref_id is used in an objective course.
importFileObject(int $parent_id=null)
form for new test object import
static redirect(string $a_script)
Class that handles PDF generation for test and assessment.
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
printObject()
Print tab to create a print of all questions with points and solutions.
executeCommand()
execute command
exportObject()
Gateway for exports initiated from workspace, as there is a generic forward to {objTypeMainGUI}::expo...
const QT_MATCHING
setTestAccess(ilTestAccess $test_access)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
SkillService $skills_service
importVerifiedFileObject()
imports question(s) into the questionpool (after verification)
certificateObject()
Shows the certificate editor.
sendParagraph(string $par_id, string $filename)
LoggingServices $logging_services
addCustomAttribute(string $a_attr)
getReturnLocation(string $cmd, string $default_location="")
Get return location for command (command is method name without "Object", e.g.
This class represents a text area property in a property form.
const QT_TEXTSUBSET
const ADDITIONAL_CONTENT_EDITING_MODE_RTE
ilAccessHandler $access
setTestAccess(ilTestAccess $test_access)
executeCreateQuestionObject()
Called when a new question should be created from a test after confirmation.
initQuestion($questionId, $parentObjId)
static isAdditionalQuestionContentEditingModePageObjectEnabled()
Returns the fact wether content editing with ilias page editor is enabled for questions or not...
$q
Definition: shib_logout.php:21
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const QUESTION_SET_TYPE_FIXED
movePageFormObject()
Move current page.
ilTestTabsManager $tabs_manager
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
moveQuestionsObject()
Marks selected questions for moving.
$message
Definition: xapiexit.php:32
New PermissionGUI (extends from old ilPermission2GUI) RBAC related output.
Service GUI class for tests.
insertQuestionsObject()
Insert questions from the questionbrowser into the test.
const IL_CAL_TIMESTAMP
const QT_IMAGEMAP
GlobalScreen $global_screen
deleteDefaultsObject()
Deletes selected test defaults.
static _lookupType(int $id, bool $reference=false)
static setUseRelativeDates(bool $a_status)
set use relative dates
backObject()
Called when the back button in the question browser was pressed.
const SINGLE_CHOICE_QUESTION_IDENTIFIER
setTestQuestionSetConfig(ilTestQuestionSetConfig $test_question_set_config)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
addHeaderAction()
Add header action menu.
static clear(string $a_var)
ilTestExpressPageObjectGUI: assMultipleChoiceGUI, assClozeTestGUI, assMatchingQuestionGUI ilTestExpr...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static set(string $a_var, $a_val)
Set a value.
showMediaFullscreen(int $a_style_id=0)
show fullscreen view of media object
const CLOZE_TEST_IDENTIFIER
Question identifier constants.
const SCORE_BEST_PASS
static _setImportDirectory($a_import_dir=null)
static getInstanceFromAjaxCall()
(Re-)Build instance from ajax call
static _gotoRepositoryRoot(bool $raise_error=false)
Goto repository root.
static _getImportDirectory()
Get the import directory location of the test.
const QT_ORDERING_HORIZONTAL
const IMAGEMAP_QUESTION_IDENTIFIER
ilComponentRepository $component_repository
const FORMULA_QUESTION_IDENTIFIER
removeQuestionsForm($checked_questions)
Displays a form to confirm the removal of questions from the test.