ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilObjQuestionPoolGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
40 use ILIAS\Style\Content\Service as ContentStyle;
41 
67 {
69 
70  public const SUPPORTED_IMPORT_MIME_TYPES = [MimeType::APPLICATION__ZIP, MimeType::TEXT__XML];
71  public const DEFAULT_CMD = 'questions';
72 
74  protected Service $taxonomy;
75  protected ilDBInterface $db;
77  protected ilHelpGUI $help;
88  private ContentStyle $content_style;
89 
93 
94  public function __construct()
95  {
97  global $DIC;
98  $this->type = 'qpl';
99 
100  $this->db = $DIC['ilDB'];
101  $this->log = $DIC['ilLog'];
102  $this->help = $DIC['ilHelp'];
103  $this->global_screen = $DIC['global_screen'];
104  $this->component_factory = $DIC['component.factory'];
105  $this->component_repository = $DIC['component.repository'];
106  $this->navigation_history = $DIC['ilNavigationHistory'];
107  $this->ui_service = $DIC->uiService();
108  $this->taxonomy = $DIC->taxonomy();
109  $this->http = $DIC->http();
110  $this->archives = $DIC->archives();
111  $this->content_style = $DIC->contentStyle();
112 
113  $this->data_factory = new DataFactory();
114 
115  $local_dic = QuestionPoolDIC::dic();
116  $this->request_data_collector = $local_dic['request_data_collector'];
117  $this->questionrepository = $local_dic['question.general_properties.repository'];
118  $this->global_test_settings = $local_dic['global_test_settings'];
119 
120  parent::__construct('', $this->request_data_collector->getRefId(), true, false);
121 
122  $this->ctrl->saveParameter($this, [
123  'ref_id',
124  'test_ref_id',
125  'test_express_mode',
126  'q_id',
127  'tax_node',
128  'consumer_context'
129  ]);
130  $this->ctrl->saveParameterByClass('ilAssQuestionPageGUI', 'consumer_context');
131  $this->ctrl->saveParameterByClass('ilobjquestionpoolgui', 'consumer_context');
132 
133  $this->lng->loadLanguageModule('assessment');
134 
135  $here_uri = $this->data_factory->uri($this->request->getUri()->__toString());
136  $url_builder = new URLBuilder($here_uri);
137  $query_params_namespace = ['qpool', 'table'];
138  list($url_builder, $action_parameter_token, $row_id_token) = $url_builder->acquireParameters(
139  $query_params_namespace,
140  'action', //this is the actions's parameter name
141  'qids' //this is the parameter name to be used for row-ids
142  );
143  $this->url_builder = $url_builder;
144  $this->action_parameter_token = $action_parameter_token;
145  $this->row_id_token = $row_id_token;
146 
147  $this->notes_service->gui()->initJavascript();
148  }
149 
150  public function executeCommand(): void
151  {
152  $write_access = $this->access->checkAccess('write', '', $this->request_data_collector->getRefId());
153 
154  if ((!$this->access->checkAccess('read', '', $this->request_data_collector->getRefId()))
155  && (!$this->access->checkAccess('visible', '', $this->request_data_collector->getRefId()))) {
156  $this->ilias->raiseError($this->lng->txt('permission_denied'), $this->ilias->error_obj->MESSAGE);
157  }
158 
159  if (!$this->getCreationMode() &&
160  $this->access->checkAccess('read', '', $this->request_data_collector->getRefId())) {
161  if ('qpl' === $this->object->getType()) {
162  $this->navigation_history->addItem(
163  $this->request_data_collector->getRefId(),
164  ilLink::_getLink($this->request_data_collector->getRefId(), "qpl"),
165  'qpl',
166  );
167  }
168  }
169 
170  $cmd = $this->ctrl->getCmd(self::DEFAULT_CMD);
171  $next_class = $this->ctrl->getNextClass($this);
172  $q_id = $this->request_data_collector->getQuestionId() ?? null;
173 
174  if (in_array($next_class, ['', 'ilobjquestionpoolgui']) && $cmd == self::DEFAULT_CMD) {
175  $q_id = -1;
176  }
177 
178  $this->prepareOutput();
179 
180  $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_print.css'), 'print');
181 
182  $q_type = $this->request_data_collector->string('question_type');
183  switch ($next_class) {
184  case 'ilcommonactiondispatchergui':
186  $this->ctrl->forwardCommand($gui);
187  break;
188 
189  case 'ilobjectmetadatagui':
190  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
191  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->WARNING);
192  }
193  $md_gui = new ilObjectMetaDataGUI($this->object);
194  $this->ctrl->forwardCommand($md_gui);
195  break;
196 
197  case 'ilassquestionpreviewgui':
198  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
199  $this->redirectAfterMissingWrite();
200  }
201 
202  $this->ctrl->saveParameterByClass(ilAssQuestionPreviewGUI::class, 'q_id');
203  $this->ctrl->saveParameterByClass(ilAssQuestionHintRequestGUI::class, 'q_id');
204  $this->ctrl->saveParameter($this, 'q_id');
205  $gui = new ilAssQuestionPreviewGUI(
206  $this->ctrl,
207  $this->rbac_system,
208  $this->tabs_gui,
209  $this->toolbar,
210  $this->tpl,
211  $this->ui_factory,
212  $this->lng,
213  $this->db,
214  $this->refinery->random(),
216  $this->http,
219  );
220 
221  $question_gui = assQuestion::instantiateQuestionGUI($this->request_data_collector->int('q_id'));
222  $gui->setPrimaryCmd(
223  $this->lng->txt('edit_question'),
224  $this->ctrl->getLinkTargetByClass(
225  get_class($question_gui),
226  'editQuestion'
227  )
228  );
229  $gui->addAdditionalCmd(
230  $this->lng->txt('edit_page'),
231  $this->ctrl->getLinkTargetByClass(
232  ilAssQuestionPageGUI::class,
233  'edit'
234  )
235  );
236 
237  $gui->initQuestion(
238  $question_gui,
239  $this->object->getId()
240  );
241  $gui->initPreviewSettings($this->object->getRefId());
242  $gui->initPreviewSession($this->user->getId(), $this->fetchAuthoringQuestionIdParamater());
243  $gui->initHintTracking();
244  $this->ctrl->clearParameterByClass(self::class, 'q_id');
245  $this->tabs_gui->setBackTarget(
246  $this->lng->txt('backtocallingpool'),
247  $this->ctrl->getLinkTargetByClass(self::class, self::DEFAULT_CMD)
248  );
249 
250  $this->help->setScreenIdComponent('qpl');
251 
252  $this->ctrl->forwardCommand($gui);
253  break;
254 
255  case 'ilassquestionpagegui':
256  if ($cmd == 'finishEditing') {
257  $this->ctrl->redirectByClass('ilassquestionpreviewgui', 'show');
258  break;
259  }
260  if ($cmd === 'edit' && !$this->access->checkAccess('write', '', $this->object->getRefId())) {
261  $this->redirectAfterMissingWrite();
262  }
263  $this->tpl->setCurrentBlock('ContentStyle');
264  $this->tpl->setVariable('LOCATION_CONTENT_STYLESHEET', ilObjStyleSheet::getContentStylePath(0));
265  $this->tpl->parseCurrentBlock();
266 
267  $this->tpl->setCurrentBlock('SyntaxStyle');
268  $this->tpl->setVariable('LOCATION_SYNTAX_STYLESHEET', ilObjStyleSheet::getSyntaxStylePath());
269  $this->tpl->parseCurrentBlock();
271  $question_gui->setRenderPurpose(assQuestionGUI::RENDER_PURPOSE_PREVIEW);
272  $question_gui->setQuestionTabs();
273  $question_gui->getObject()->setObjId($this->object->getId());
274  $question_gui->setQuestionActionCmd('');
275 
276  if ($this->object->getType() === 'qpl') {
277  $question_gui->addHeaderAction();
278  }
279 
280  $question = $question_gui->getObject();
281 
282  if ($this->questionrepository->isInActiveTest($question->getObjId())) {
283  $this->tpl->setOnScreenMessage(
284  'failure',
285  $this->lng->txt('question_is_part_of_running_test'),
286  true
287  );
288  $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
289  }
290 
291  $this->ctrl->saveParameter($this, 'q_id');
292  $this->lng->loadLanguageModule('content');
293  $this->ctrl->setReturnByClass('ilAssQuestionPageGUI', 'view');
294  $this->ctrl->setReturn($this, self::DEFAULT_CMD);
295  $page_gui = new ilAssQuestionPageGUI($this->request_data_collector->getQuestionId());
296  $page_gui->obj->addUpdateListener(
297  $question,
298  'updateTimestamp'
299  );
300  $page_gui->setEditPreview(true);
301  $page_gui->setEnabledTabs(false);
302  $page_gui->setQuestionHTML([$question_gui->getObject()->getId() => $question_gui->getPreview(true)]);
303  $page_gui->setTemplateTargetVar('ADM_CONTENT');
304  $page_gui->setOutputMode('edit');
305  $page_gui->setHeader($question->getTitleForHTMLOutput());
306  $page_gui->setPresentationTitle($question->getTitleForHTMLOutput());
307  $ret = $this->ctrl->forwardCommand($page_gui);
308  if ($ret != '') {
309  $this->tpl->setContent($ret);
310  }
311  break;
312 
313  case 'ilpermissiongui':
314  $perm_gui = new ilPermissionGUI($this);
315  $this->ctrl->forwardCommand($perm_gui);
316  break;
317 
318  case 'ilobjectcopygui':
319  $cp = new ilObjectCopyGUI($this);
320  $cp->setType('qpl');
321  $this->ctrl->forwardCommand($cp);
322  break;
323 
324  case 'ilexportgui':
325  $exp_gui = new ilExportGUI($this);
326  $ret = $this->ctrl->forwardCommand($exp_gui);
327  break;
328 
329  case strtolower(ilInfoScreenGUI::class):
330  $this->infoScreenForward();
331  break;
332 
333  case 'ilassquestionhintsgui':
334  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
335  $this->redirectAfterMissingWrite();
336  }
337 
338  $this->ctrl->setReturn($this, self::DEFAULT_CMD);
339  $question_gui = assQuestionGUI::_getQuestionGUI(
340  $q_type,
342  );
343  $question = $question_gui->getObject();
344  $question->setObjId($this->object->getId());
345  $question_gui->setObject($question);
346  $question_gui->setQuestionTabs();
347 
348  if ($this->questionrepository->isInActiveTest($question_gui->getObject()->getObjId())) {
349  $this->tpl->setOnScreenMessage(
350  'failure',
351  $this->lng->txt('question_is_part_of_running_test'),
352  true
353  );
354  $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
355  }
356 
357  $this->help->setScreenIdComponent('qpl');
358 
359  if ($this->object->getType() == 'qpl' && $write_access) {
360  $question_gui->addHeaderAction();
361  }
362  $gui = new ilAssQuestionHintsGUI($question_gui);
363 
364  $gui->setEditingEnabled(
365  $this->access->checkAccess('write', '', $this->object->getRefId())
366  );
367 
368  $this->ctrl->forwardCommand($gui);
369 
370  break;
371 
372  case 'illocalunitconfigurationgui':
373  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
374  $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->WARNING);
375  }
376  $question_gui = assQuestionGUI::_getQuestionGUI(
377  $q_type,
379  );
380  $question = $question_gui->getObject();
381  $question->setObjId($this->object->getId());
382  $question_gui->setObject($question);
383  $question_gui->setQuestionTabs();
384 
385  $this->ctrl->setReturn($this, self::DEFAULT_CMD);
386  $gui = new ilLocalUnitConfigurationGUI(
387  new ilUnitConfigurationRepository($this->request_data_collector->getQuestionId())
388  );
389  $this->ctrl->forwardCommand($gui);
390  break;
391 
392  case 'ilassquestionfeedbackeditinggui':
393  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
394  $this->redirectAfterMissingWrite();
395  }
396 
397  $this->ctrl->setReturn($this, self::DEFAULT_CMD);
398  $question_gui = assQuestionGUI::_getQuestionGUI(
399  $q_type,
401  );
402  $question = $question_gui->getObject();
403  $question->setObjId($this->object->getId());
404  $question_gui->setObject($question);
405  $question_gui->setQuestionTabs();
406 
407  if ($this->questionrepository->isInActiveTest($question_gui->getObject()->getObjId())) {
408  $this->tpl->setOnScreenMessage(
409  'failure',
410  $this->lng->txt('question_is_part_of_running_test'),
411  true
412  );
413  $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
414  }
415 
416  $this->help->setScreenIdComponent('qpl');
417 
418  if ($this->object->getType() == 'qpl' && $write_access) {
419  $question_gui->addHeaderAction();
420  }
422  $question_gui,
423  $this->ctrl,
424  $this->access,
425  $this->tpl,
426  $this->tabs_gui,
427  $this->lng,
428  $this->help,
429  $this->request_data_collector,
430  $this->content_style,
431  true
432  );
433  $this->ctrl->forwardCommand($gui);
434 
435  break;
436 
437  case 'ilobjquestionpoolsettingsgeneralgui':
439  $this->ctrl,
440  $this->access,
441  $this->lng,
442  $this->tpl,
443  $this->tabs_gui,
444  $this,
445  $this->refinery,
446  $this->ui_factory,
447  $this->ui_renderer,
448  $this->request,
449  );
450  $this->ctrl->forwardCommand($gui);
451  break;
452 
453  case strtolower(ilTaxonomySettingsGUI::class):
454  if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
455  $this->redirectAfterMissingWrite();
456  }
457 
459  $obj = $this->object;
461  $this->object,
462  $this->db,
463  $this->refinery,
464  $this->component_repository,
465  $this->ctrl,
466  $this->tabs_gui,
467  $this->lng,
468  $this->taxonomy
469  );
470 
471  $forwarder->forward();
472 
473  break;
474 
475  case 'ilquestionpoolskilladministrationgui':
476  $obj = $this->object;
478  $this->ilias,
479  $this->ctrl,
480  $this->refinery,
481  $this->access,
482  $this->tabs_gui,
483  $this->tpl,
484  $this->lng,
485  $this->db,
486  $this->component_repository,
487  $obj,
488  $this->ref_id
489  );
490 
491  $this->ctrl->forwardCommand($gui);
492  break;
493 
494  case 'ilbulkeditquestionsgui':
495  if (!$this->access->checkAccess('read', '', $this->object->getRefId())) {
496  $this->redirectAfterMissingWrite();
497  }
498  $this->tabs_gui->setBackTarget(
499  $this->lng->txt('backtocallingpool'),
500  $this->ctrl->getLinkTargetByClass(self::class, self::DEFAULT_CMD)
501  );
502  $this->tabs_gui->addTarget(
503  'edit_questions',
504  '#',
505  '',
506  $this->ctrl->getCmdClass(),
507  ''
508  );
509  $this->tabs_gui->setTabActive('edit_questions');
510 
511  $gui = new \ilBulkEditQuestionsGUI(
512  $this->tpl,
513  $this->ctrl,
514  $this->lng,
515  $this->ui_factory,
516  $this->ui_renderer,
517  $this->refinery,
518  $this->request,
519  $this->request_wrapper,
520  $this->object->getId(),
521  );
522  $this->ctrl->forwardCommand($gui);
523  break;
524 
525  case 'ilobjquestionpoolgui':
526  case '':
527  //table actions.
528  if ($action = $this->request_data_collector->string($this->action_parameter_token->getName())) {
529  $ids = $this->request_data_collector->raw($this->row_id_token->getName()) ?? null;
530 
531  if (is_null($ids)) {
532  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('msg_no_questions_selected'), true);
533  $this->ctrl->redirect($this, self::DEFAULT_CMD);
534  }
535  if ($ids[0] === 'ALL_OBJECTS') {
536  $ids = $this->object->getAllQuestionIds();
537  }
538  if (!is_array($ids)) {
539  $ids = explode(',', $ids);
540  }
541  $ids = array_map('intval', $ids);
542 
543  $class = strtolower($this->questionrepository->getForQuestionId(current($ids))->getGuiClassName());
544  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", current($ids));
545  $this->ctrl->setParameterByClass("ilAssQuestionPreviewGUI", "q_id", current($ids));
546  $this->ctrl->setParameterByClass('ilAssQuestionFeedbackEditingGUI', 'q_id', current($ids));
547  $this->ctrl->setParameterByClass('ilAssQuestionHintsGUI', 'q_id', current($ids));
548  $this->ctrl->setParameterByClass($class, "q_id", current($ids));
549 
550  switch ($action) {
551  case 'preview':
552  $url = $this->ctrl->getLinkTargetByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW);
553  $this->ctrl->redirectToURL($url);
554  break;
555  case 'statistics':
556  $url = $this->ctrl->getLinkTargetByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_STATISTICS);
557  $this->ctrl->redirectToURL($url);
558  break;
559  case 'edit_question':
560  $url = $this->ctrl->getLinkTargetByClass($class, 'editQuestion');
561  $this->ctrl->redirectToURL($url);
562  break;
563  case 'edit_page':
564  $url = $this->ctrl->getLinkTargetByClass('ilAssQuestionPageGUI', 'edit');
565  $this->ctrl->redirectToURL($url);
566  break;
567  case 'feedback':
568  $url = $this->ctrl->getLinkTargetByClass('ilAssQuestionFeedbackEditingGUI', ilAssQuestionFeedbackEditingGUI::CMD_SHOW);
569  $this->ctrl->redirectToURL($url);
570  break;
571  case 'hints':
572  $url = $this->ctrl->getLinkTargetByClass('ilAssQuestionHintsGUI', ilAssQuestionHintsGUI::CMD_SHOW_LIST);
573  $this->ctrl->redirectToURL($url);
574  break;
575  case 'move':
576  $this->moveQuestions($ids);
577  $this->ctrl->redirect($this, self::DEFAULT_CMD);
578  break;
579  case 'copy':
580  $this->copyQuestions($ids);
581  $this->ctrl->redirect($this, self::DEFAULT_CMD);
582  break;
583  case 'delete':
584  $this->confirmDeleteQuestions($ids);
585  break;
586  case 'export':
587  $this->exportQuestions($ids);
588  $this->ctrl->redirect($this, self::DEFAULT_CMD);
589  break;
590  case 'comments':
593  $this->object->getRefId(),
594  'quest',
595  $this->object->getId(),
596  'quest',
597  current($ids)
598  );
599  echo ''
600  . '<script>'
601  . ' event = new Event("click");'
603  . '</script>'
604  ;
605  exit();
606 
610  $this->ctrl->clearParameters($this);
611  $this->ctrl->setParameterByClass(
612  ilBulkEditQuestionsGUI::class,
614  implode(',', $ids)
615  );
616  $url = $this->ctrl->getLinkTargetByClass(
617  ilBulkEditQuestionsGUI::class,
618  $action
619  );
620  $this->ctrl->redirectToURL($url);
621  break;
622 
623  default:
624  throw new \Exception("'$action'" . " not implemented");
625  }
626  break;
627  }
628 
629 
630  if ($cmd == self::DEFAULT_CMD) {
631  $this->ctrl->setParameter($this, 'q_id', '');
632  }
633  $cmd .= 'Object';
634  $ret = $this->$cmd();
635  break;
636 
637  default:
638  if (in_array(
639  $cmd,
640  ['editQuestion', 'save', 'suggestedsolution', 'uploadImage', 'removeImage']
641  ) && !$this->access->checkAccess(
642  'write',
643  '',
644  $this->object->getRefId()
645  )) {
646  $this->redirectAfterMissingWrite();
647  }
648 
649  $this->ctrl->setReturnByClass(self::class, self::DEFAULT_CMD);
650 
651  $qid = $this->fetchAuthoringQuestionIdParamater();
652  $question_gui = assQuestionGUI::_getQuestionGUI(
653  $q_type,
654  $qid
655  );
656  $question_gui->setEditContext(assQuestionGUI::EDIT_CONTEXT_AUTHORING);
657  $question = $question_gui->getObject();
658  $question->setObjId($this->object->getId());
659  $question_gui->setObject($question);
660 
661  if ($this->object->getType() === 'qpl') {
662  $question_gui->setTaxonomyIds($this->object->getTaxonomyIds());
663 
664  if ($write_access) {
665  $question_gui->addHeaderAction();
666  }
667  }
668 
669  $this->help->setScreenIdComponent('qpl');
670 
671  if ($qid === 0 && $question_gui->cmdNeedsExistingQuestion($cmd)) {
672  $question_gui->getObject()->createNewQuestion();
673  }
674 
675  $question_gui->setQuestionTabs();
676 
677  if (!in_array($cmd, ['save', 'saveReturn'])) {
678  $question_gui->$cmd();
679  return;
680  }
681 
682  if (!$question_gui->saveQuestion()) {
683  return;
684  }
685  $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_obj_modified'), true);
686  if ($cmd === 'saveReturn') {
687  $this->ctrl->setParameterByClass(
688  ilAssQuestionPreviewGUI::class,
689  'q_id',
690  (string) $question_gui->getObject()->getId()
691  );
692  $this->ctrl->redirectToURL(
693  $this->ctrl->getLinkTargetByClass(ilAssQuestionPreviewGUI::class, ilAssQuestionPreviewGUI::CMD_SHOW)
694  );
695  }
696 
697  if ($cmd === 'save') {
698  $this->tabs_gui->activateTab('edit_question');
699  $question_gui->editQuestion(false, false);
700  }
701  break;
702  }
703 
704  if (!(strtolower($this->request_data_collector->raw('baseClass')) == 'iladministrationgui'
705  || strtolower($this->request_data_collector->raw('baseClass')) == 'ilrepositorygui')
706  && $this->getCreationMode() != true) {
707  $this->tpl->printToStdout();
708  }
709  }
710 
711  protected function redirectAfterMissingWrite()
712  {
713  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('no_permission'), true);
714  $target_class = get_class($this->object) . 'GUI';
715  $this->ctrl->setParameterByClass($target_class, 'ref_id', $this->ref_id);
716  $this->ctrl->redirectByClass($target_class);
717  }
718 
723  protected function exportObject(): void
724  {
725  $this->ctrl->redirectByClass('ilQuestionPoolExportGUI');
726  }
727 
728  public function downloadFileObject(): void
729  {
730  $file = explode('_', $this->request_data_collector->raw('file_id'));
731  $fileObj = new ilObjFile((int) $file[count($file) - 1], false);
732  $fileObj->sendFile();
733  exit;
734  }
735 
739  public function fullscreenObject(): void
740  {
741  $page_gui = new ilAssQuestionPageGUI($this->request_data_collector->raw('pg_id'));
742  $page_gui->showMediaFullscreen();
743  }
744 
748  public function download_paragraphObject(): void
749  {
750  $pg_obj = new ilAssQuestionPage($this->request_data_collector->raw('pg_id'));
751  $pg_obj->sendParagraph($this->request_data_collector->raw('par_id'), $this->request_data_collector->raw('downloadtitle'));
752  exit;
753  }
754 
755  public function importVerifiedFileObject(): void
756  {
757  if ($this->creation_mode
758  && !$this->checkPermissionBool('create', '', $this->request_data_collector->string('new_type'))
759  || !$this->creation_mode
760  && !$this->checkPermissionBool('read', '', $this->object->getType())) {
761  $this->redirectAfterMissingWrite();
762  return;
763  }
764 
765  $file_to_import = ilSession::get('path_to_import_file');
766  list($subdir, $importdir, $xmlfile, $qtifile) = $this->buildImportDirectoriesFromImportFile($file_to_import);
767 
768  $new_obj = new ilObjQuestionPool(0, true);
769  $new_obj->setType($this->request_data_collector->raw('new_type'));
770  $new_obj->setTitle('dummy');
771  $new_obj->setDescription('questionpool import');
772  $new_obj->create(true);
773  $new_obj->createReference();
774  $new_obj->putInTree($this->request_data_collector->getRefId());
775  $new_obj->setPermissions($this->request_data_collector->getRefId());
776 
778  'importVerifiedFile',
779  $importdir,
780  $qtifile,
781  $this->request
782  );
783 
784  if (is_file($importdir . DIRECTORY_SEPARATOR . 'manifest.xml')) {
786  $new_obj,
787  $selected_questions,
788  $file_to_import
789  );
790  } else {
792  $new_obj,
793  $selected_questions,
794  $qtifile,
795  $importdir,
796  $xmlfile
797  );
798 
799  $new_obj->fromXML($xmlfile);
800 
801  $new_obj->update();
802  $new_obj->saveToDb();
803  }
804  $this->cleanupAfterImport($importdir);
805 
806  $this->tpl->setOnScreenMessage('success', $this->lng->txt('object_imported'), true);
807  $this->ctrl->setParameterByClass(self::class, 'ref_id', $new_obj->getRefId());
808  $this->ctrl->redirectByClass(self::class);
809  }
810 
811  public function importVerifiedQuestionsFileObject(): void
812  {
813  $file_to_import = ilSession::get('path_to_import_file');
814 
815  if (mb_substr($file_to_import, -3) === 'xml') {
816  $importdir = dirname($file_to_import);
818  'importVerifiedQuestionsFile',
819  $importdir,
820  $file_to_import,
821  $this->request
822  );
824  $this->getObject(),
825  $selected_questions,
826  $file_to_import,
827  $importdir
828  );
829  } else {
830  list($subdir, $importdir, $xmlfile, $qtifile) = $this->buildImportDirectoriesFromImportFile($file_to_import);
832  'importVerifiedQuestionsFile',
833  $importdir,
834  $qtifile,
835  $this->request
836  );
837  if (is_file($importdir . DIRECTORY_SEPARATOR . 'manifest.xml')) {
839  $this->getObject(),
840  $selected_questions,
841  $file_to_import
842  );
843  } else {
845  $this->getObject(),
846  $selected_questions,
847  $qtifile,
848  $importdir,
849  $xmlfile
850  );
851  }
852  }
853 
854  $this->cleanupAfterImport($importdir);
855 
856  $this->tpl->setOnScreenMessage('success', $this->lng->txt('object_imported'), true);
857  $this->questionsObject();
858  }
859 
860  public function uploadQuestionsImportObject(): void
861  {
862  $import_questions_modal = $this->buildImportQuestionsModal()->withRequest($this->request);
863  $data = $import_questions_modal->getData();
864  if ($data === null) {
865  $this->questionsObject(
866  $import_questions_modal->withOnLoad(
867  $import_questions_modal->getShowSignal()
868  )
869  );
870  return;
871  }
872  $path_to_imported_file_in_temp_dir = $data['import_file'][0];
873  $this->importQuestionsFile($path_to_imported_file_in_temp_dir);
874  }
875 
877  {
878  $constraint = $this->refinery->custom()->constraint(
879  function ($vs): bool {
880  if ($vs === []) {
881  return false;
882  }
883  return true;
884  },
885  $this->lng->txt('msg_no_files_selected')
886  );
887 
888  $file_upload_input = $this->ui_factory->input()->field()
889  ->file(new \QuestionPoolImportUploadHandlerGUI(), $this->lng->txt('import_file'))
890  ->withAcceptedMimeTypes(self::SUPPORTED_IMPORT_MIME_TYPES)
891  ->withMaxFiles(1)
892  ->withAdditionalTransformation($constraint);
893  return $this->ui_factory->modal()->roundtrip(
894  $this->lng->txt('import'),
895  [],
896  ['import_file' => $file_upload_input],
897  $this->ctrl->getFormActionByClass(self::class, 'uploadQuestionsImport')
898  )->withSubmitLabel($this->lng->txt('import'));
899  }
900 
902  ilObjQuestionPool $obj,
903  array $selected_questions,
904  string $file_to_import
905  ): void {
906 
907  ilSession::set('qpl_import_selected_questions', $selected_questions);
908  $imp = new ilImport($this->request_data_collector->getRefId());
909  $map = $imp->getMapping();
910  $map->addMapping('components/ILIAS/TestQuestionPool', 'qpl', 'new_id', (string) $obj->getId());
911  $imp->importObject($obj, $file_to_import, basename($file_to_import), 'qpl', 'components/ILIAS/TestQuestionPool', true);
912  }
913 
914  private function importQuestionsFromQtiFile(
915  ilObjQuestionPool $obj,
916  array $selected_questions,
917  string $qtifile,
918  string $importdir,
919  string $xmlfile = ''
920  ): void {
921  $qti_parser = new ilQTIParser(
922  $importdir,
923  $qtifile,
925  $obj->getId(),
926  $selected_questions
927  );
928  $qti_parser->startParsing();
929 
930  if ($xmlfile === '') {
931  return;
932  }
933 
934  $cont_parser = new ilQuestionPageParser(
935  $obj,
936  $xmlfile,
937  $importdir
938  );
939  $cont_parser->setQuestionMapping($qti_parser->getImportMapping());
940  $cont_parser->startParsing();
941  }
942 
943  private function cleanupAfterImport(string $importdir): void
944  {
945  ilFileUtils::delDir($importdir);
946  $this->deleteUploadedImportFile(ilSession::get('path_to_uploaded_file_in_temp_dir'));
947  ilSession::clear('path_to_import_file');
948  ilSession::clear('path_to_uploaded_file_in_temp_dir');
949  }
950 
951  public function createQuestionObject(): void
952  {
953  $form = $this->buildQuestionCreationForm()->withRequest($this->request);
954  $data_with_section = $form->getData();
955  if ($data_with_section === null) {
956  $this->createQuestionFormObject($form);
957  return;
958  }
959  $data = $data_with_section[0];
960 
961  $this->ctrl->setReturnByClass(self::class, self::DEFAULT_CMD);
962 
964  $question_gui = assQuestionGUI::_getQuestionGUI(
966  );
967  $question = $question_gui->getObject();
968  $question->setObjId($this->object->getId());
969  $question->setAdditionalContentEditingMode($data['editing_type']);
970  $question_gui->setObject($question);
971  $question_gui->setQuestionTabs();
972  $question_gui->editQuestion();
973  }
974 
975  public function afterSave(ilObject $new_object): void
976  {
977  // always send a message
978  $this->tpl->setOnScreenMessage('success', $this->lng->txt('object_added'), true);
979 
981  'ilias.php?ref_id=' . $new_object->getRefId() .
982  '&baseClass=ilObjQuestionPoolGUI'
983  );
984  }
985 
986  public function confirmDeleteQuestions(array $ids): void
987  {
988  $rbacsystem = $this->rbac_system;
989 
990  $questionIdsToDelete = array_filter(array_map('intval', $ids));
991  if (0 === count($questionIdsToDelete)) {
992  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_delete_select_none'), true);
993  $this->ctrl->redirect($this, self::DEFAULT_CMD);
994  }
995 
996  $this->tpl->setOnScreenMessage('question', $this->lng->txt('qpl_confirm_delete_questions'));
997  $deleteable_questions = $this->object->getDeleteableQuestionDetails($questionIdsToDelete);
998  $table_gui = new ilQuestionBrowserTableGUI($this, self::DEFAULT_CMD, (($rbacsystem->checkAccess('write', $this->request_data_collector->getRefId()) ? true : false)), true);
999  $table_gui->setShowRowsSelector(false);
1000  $table_gui->setLimit(PHP_INT_MAX);
1001  $table_gui->setEditable($rbacsystem->checkAccess('write', $this->request_data_collector->getRefId()));
1002  $table_gui->setData($deleteable_questions);
1003  $this->tpl->setVariable('ADM_CONTENT', $table_gui->getHTML());
1004  }
1005 
1009  public function deleteQuestionsObject(): void
1010  {
1011  $rbacsystem = $this->rbac_system;
1012 
1013  $questionIdsToDelete = $this->request_data_collector->isset('q_id') ? (array) $this->request_data_collector->raw('q_id') : [];
1014  if ($questionIdsToDelete === [] && $this->request_data_collector->isset('q_id')) {
1015  $questionIdsToDelete = [$this->request_data_collector->getQuestionId()];
1016  }
1017 
1018  $questionIdsToDelete = array_filter(array_map('intval', $questionIdsToDelete));
1019  if ($questionIdsToDelete === []) {
1020  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_delete_select_none'), true);
1021  $this->ctrl->redirect($this, self::DEFAULT_CMD);
1022  }
1023 
1024  $this->tpl->setOnScreenMessage('question', $this->lng->txt('qpl_confirm_delete_questions'));
1025  $deleteable_questions = &$this->object->getDeleteableQuestionDetails($questionIdsToDelete);
1026  $table_gui = new ilQuestionBrowserTableGUI(
1027  $this,
1028  self::DEFAULT_CMD,
1029  (($rbacsystem->checkAccess('write', $this->request_data_collector->getRefId()) ? true : false)),
1030  true
1031  );
1032  $table_gui->setShowRowsSelector(false);
1033  $table_gui->setLimit(PHP_INT_MAX);
1034  $table_gui->setEditable($rbacsystem->checkAccess('write', $this->request_data_collector->getRefId()));
1035  $table_gui->setData($deleteable_questions);
1036  $this->tpl->setVariable('ADM_CONTENT', $table_gui->getHTML());
1037  }
1038 
1042  public function confirmDeleteQuestionsObject(): void
1043  {
1044  $qst_ids = $this->request_data_collector->intArray('q_id');
1045  foreach ($qst_ids as $value) {
1046  $this->object->deleteQuestion((int) $value);
1047  $this->object->cleanupClipboard((int) $value);
1048  }
1049  if ($qst_ids !== []) {
1050  $this->tpl->setOnScreenMessage('success', $this->lng->txt('qpl_questions_deleted'), true);
1051  }
1052 
1053  $this->ctrl->setParameter($this, 'q_id', '');
1054  $this->ctrl->redirect($this, self::DEFAULT_CMD);
1055  }
1056 
1057  public function cancelDeleteQuestionsObject(): void
1058  {
1059  $this->ctrl->redirect($this, self::DEFAULT_CMD);
1060  }
1061 
1062  public function exportQuestions(array $ids): void
1063  {
1064  if ($ids !== []) {
1065  $qpl_exp = new ilQuestionpoolExport($this->object, 'xml', $ids);
1066  // @PHP8-CR: This seems to be a pointer to an issue with exports. I like to leave this open for now and
1067  // schedule a thorough examination / analysis for later, eventually involved T&A TechSquad
1068  $export_file = $qpl_exp->buildExportFile();
1069  $filename = $export_file;
1070  $filename = preg_replace('/.*\//', '', $filename);
1071  if ($export_file === '') {
1072  $export_file = 'StandIn';
1073  }
1075  exit();
1076  } else {
1077  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_export_select_none'), true);
1078  }
1079  }
1080 
1081  protected function renoveImportFailsObject(): void
1082  {
1083  $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($this->object->getId());
1084  $qsaImportFails->deleteRegisteredImportFails();
1085 
1086  $this->ctrl->redirectByClass(
1087  [
1088  ilRepositoryGUI::class,
1089  self::class,
1090  ilInfoScreenGUI::class
1091  ]
1092  );
1093  }
1094 
1098  public function questionsObject(RoundTripModal $import_questions_modal = null): void
1099  {
1100  if (!$this->access->checkAccess("read", "", $this->request_data_collector->getRefId())) {
1101  $this->infoScreenForward();
1102  return;
1103  }
1104 
1105  $this->object->purgeQuestions();
1106  $qsa_import_fails = new ilAssQuestionSkillAssignmentImportFails($this->object->getId());
1107  if ($qsa_import_fails->failedImportsRegistered()) {
1108  $button = $this->ui_factory->button()->standard(
1109  $this->lng->txt('ass_skl_import_fails_remove_btn'),
1110  $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'renoveImportFails')
1111  );
1112  $this->tpl->setOnScreenMessage(
1113  'failure',
1114  $qsa_import_fails->getFailedImportsMessage($this->lng) . '<br />' . $this->ui_renderer->render(
1115  $button
1116  )
1117  );
1118  }
1119 
1120  $out = [];
1121  if ($this->rbac_system->checkAccess('write', $this->request_data_collector->getRefId())) {
1122  $btn = $this->ui_factory->button()->primary(
1123  $this->lng->txt('ass_create_question'),
1124  $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'createQuestionForm')
1125  );
1126  $this->toolbar->addComponent($btn);
1127 
1128  if ($import_questions_modal === null) {
1129  $import_questions_modal = $this->buildImportQuestionsModal();
1130  }
1131 
1132  $btn_import = $this->ui_factory->button()->standard(
1133  $this->lng->txt('import'),
1134  $import_questions_modal->getShowSignal()
1135  );
1136  $this->toolbar->addComponent($btn_import);
1137  $out[] = $this->ui_renderer->render($import_questions_modal);
1138 
1139  if (ilSession::get('qpl_clipboard') != null && count(ilSession::get('qpl_clipboard'))) {
1140  $btn_paste = $this->ui_factory->button()->standard(
1141  $this->lng->txt('paste'),
1142  $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'paste')
1143  );
1144  $this->toolbar->addComponent($btn_paste);
1145  }
1146  }
1147 
1148  $this->tpl->setPermanentLink($this->object->getType(), $this->object->getRefId());
1149  $out[] = $this->getTable();
1150  $this->tpl->setContent(implode('', $out));
1151  }
1152 
1154  {
1155  $q_id = $this->request_data_collector->getQuestionId();
1156 
1157  if ($q_id === 0 || $this->object->checkQuestionParent($q_id)) {
1158  return $q_id;
1159  }
1160 
1161  throw new ilTestQuestionPoolException('question id does not relate to parent object!');
1162  }
1163 
1164  private function createQuestionFormObject(Form $form = null): void
1165  {
1166  $this->help->setScreenId('assQuestions');
1167  if ($this->global_test_settings->isPageEditorEnabled()) {
1168  $this->help->setSubScreenId('createQuestion_editMode');
1169  } else {
1170  $this->help->setSubScreenId('createQuestion');
1171  }
1172 
1173  $this->tpl->setContent(
1174  $this->ui_renderer->render(
1175  $form ?? $this->buildQuestionCreationForm()
1176  )
1177  );
1178  }
1179 
1180  private function buildQuestionCreationForm(): Form
1181  {
1182  $inputs['question_type'] = $this->buildInputQuestionType();
1183  $inputs['editing_type'] = $this->buildInputEditingType();
1184 
1185  $section = [
1186  $this->ui_factory->input()->field()->section($inputs, $this->lng->txt('ass_create_question'))
1187  ];
1188 
1189  $form = $this->ui_factory->input()->container()->form()->standard(
1190  $this->ctrl->getFormAction($this, 'createQuestion'),
1191  $section
1192  )->withSubmitLabel($this->lng->txt('create'));
1193 
1194  return $form;
1195  }
1196 
1197  private function buildInputQuestionType(): Select
1198  {
1199  $question_types = (new ilObjQuestionPool())->getQuestionTypes(false, true, false);
1200  $options = [];
1201  foreach ($question_types as $label => $data) {
1202  $options[$data['question_type_id']] = $label;
1203  }
1204 
1205  return $this->ui_factory->input()->field()->select(
1206  $this->lng->txt('question_type'),
1207  $options
1208  )->withRequired(true);
1209  }
1210 
1211  private function buildInputEditingType(): Input
1212  {
1213  if (!$this->global_test_settings->isPageEditorEnabled()) {
1214  return $this->ui_factory->input()->field()->hidden()->withValue(
1216  );
1217  }
1218 
1219  return $this->ui_factory->input()->field()->radio($this->lng->txt('tst_add_quest_cont_edit_mode'))
1220  ->withOption(
1222  $this->lng->txt('tst_add_quest_cont_edit_mode_IPE'),
1223  $this->lng->txt('tst_add_quest_cont_edit_mode_IPE_info')
1224  )->withOption(
1226  $this->lng->txt('tst_add_quest_cont_edit_mode_RTE'),
1227  $this->lng->txt('tst_add_quest_cont_edit_mode_RTE_info')
1228  )
1230  }
1231 
1232  public function printObject(): void
1233  {
1234  $this->tabs_gui->activateTab('print_view');
1235  $this->ctrl->setParameter($this, 'output', 'overview');
1236  $output_link = $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'print');
1237  $this->ctrl->setParameter($this, 'output', 'detailed_output_solutions');
1238  $output_link_detailed = $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'print');
1239  $this->ctrl->setParameter($this, 'output', 'detailed_output_printview');
1240  $output_link_printview = $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'print');
1241 
1242  $mode = $this->ui_factory->dropdown()->standard([
1243  $this->ui_factory->button()->shy($this->lng->txt('overview'), $output_link),
1244  $this->ui_factory->button()->shy($this->lng->txt('detailed_output_solutions'), $output_link_detailed),
1245  $this->ui_factory->button()->shy($this->lng->txt('detailed_output_printview'), $output_link_printview)
1246  ])->withLabel($this->lng->txt('output_mode'));
1247 
1248  $output = $this->request_data_collector->raw('output') ?? '';
1249 
1250  $table_gui = new ilQuestionPoolPrintViewTableGUI($this, 'print', $output);
1251  $data = $this->object->getPrintviewQuestions();
1252  $totalPoints = 0;
1253  foreach ($data as $d) {
1254  $totalPoints += $d['points'];
1255  }
1256  $table_gui->setTotalPoints($totalPoints);
1257  $table_gui->initColumns();
1258  $table_gui->setData($data);
1259  $this->tpl->setContent($this->ui_renderer->render($mode) . $table_gui->getHTML());
1260  }
1261 
1262  public function updateObject(): void
1263  {
1264  $this->object->update();
1265  $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_obj_modified'), true);
1266  }
1267 
1268  public function pasteObject(): void
1269  {
1270  if (ilSession::get('qpl_clipboard') != null) {
1271  if ($this->object->pasteFromClipboard()) {
1272  $this->tpl->setOnScreenMessage('success', $this->lng->txt('qpl_paste_success'), true);
1273  } else {
1274  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('qpl_paste_error'), true);
1275  }
1276  } else {
1277  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_paste_no_objects'), true);
1278  }
1279  $this->ctrl->redirect($this, self::DEFAULT_CMD);
1280  }
1281 
1282  public function copyQuestions(array $ids): void
1283  {
1284  if ($ids) {
1285  foreach ($ids as $id) {
1286  $this->object->copyToClipboard($id);
1287  }
1288  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_copy_insert_clipboard'), true);
1289  } else {
1290  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_copy_select_none'), true);
1291  }
1292  }
1293 
1294  public function moveQuestions(array $ids): void
1295  {
1296  if ($ids) {
1297  foreach ($ids as $id) {
1298  $this->object->moveToClipboard($id);
1299  }
1300  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_move_insert_clipboard'), true);
1301  } else {
1302  $this->tpl->setOnScreenMessage('info', $this->lng->txt('qpl_move_select_none'), true);
1303  }
1304  }
1305 
1306  public function createExportExcel(): void
1307  {
1308  $rbacsystem = $this->rbac_system;
1309  if ($rbacsystem->checkAccess('write', $this->request_data_collector->getRefId())) {
1310  $question_ids = &$this->object->getAllQuestionIds();
1311  $qpl_exp = new ilQuestionpoolExport($this->object, 'xlsx', $question_ids);
1312  $qpl_exp->buildExportFile();
1313  $this->ctrl->redirectByClass('ilquestionpoolexportgui', '');
1314  }
1315  }
1316 
1317  public function editQuestionForTestObject(): void
1318  {
1319  $this->ctrl->redirectByClass(ilAssQuestionPreviewGUI::class, 'show');
1320  }
1321 
1322  protected function importQuestionsFile(string $path_to_uploaded_file_in_temp_dir): void
1323  {
1324  if (!$this->temp_file_system->hasDir($path_to_uploaded_file_in_temp_dir)
1325  || ($files = $this->temp_file_system->listContents($path_to_uploaded_file_in_temp_dir)) === []) {
1326  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('obj_import_file_error'));
1327  }
1328 
1329  $file_to_import = $this->import_temp_directory . DIRECTORY_SEPARATOR . $files[0]->getPath();
1330  $qtifile = $file_to_import;
1331  $importdir = dirname($file_to_import);
1332 
1333 
1334  if ($this->temp_file_system->getMimeType($files[0]->getPath()) === MimeType::APPLICATION__ZIP) {
1336  ->withZipOutputPath($this->getImportTempDirectory());
1337  $unzip = $this->archives->unzip($this->temp_file_system->readStream($files[0]->getPath()), $options);
1338  $unzip->extract();
1339  list($subdir, $importdir, $xmlfile, $qtifile) = $this->buildImportDirectoriesFromImportFile($file_to_import);
1340  }
1341  if (!file_exists($qtifile)) {
1342  ilFileUtils::delDir($importdir);
1343  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('cannot_find_xml'), true);
1344  $this->questionsObject();
1345  return;
1346  }
1347 
1348  ilSession::set('path_to_import_file', $file_to_import);
1349  ilSession::set('path_to_uploaded_file_in_temp_dir', $path_to_uploaded_file_in_temp_dir);
1350 
1351  $form = $this->buildImportQuestionsSelectionForm(
1352  'importVerifiedQuestionsFile',
1353  $importdir,
1354  $qtifile,
1355  $path_to_uploaded_file_in_temp_dir
1356  );
1357 
1358  if ($form === null) {
1359  return;
1360  }
1361 
1362  $panel = $this->ui_factory->panel()->standard(
1363  $this->lng->txt('import_question'),
1364  [
1365  $this->ui_factory->legacy($this->lng->txt('qpl_import_verify_found_questions')),
1366  $form
1367  ]
1368  );
1369  $this->tpl->setContent($this->ui_renderer->render($panel));
1370  $this->tpl->printToStdout();
1371  exit;
1372  }
1373 
1374  protected function importFile(string $file_to_import, string $path_to_uploaded_file_in_temp_dir): void
1375  {
1376  list($subdir, $importdir, $xmlfile, $qtifile) = $this->buildImportDirectoriesFromImportFile($file_to_import);
1377 
1379  ->withZipOutputPath($this->getImportTempDirectory());
1380 
1381  $unzip = $this->archives->unzip(Streams::ofResource(fopen($file_to_import, 'r')), $options);
1382  $unzip->extract();
1383 
1384  if (!file_exists($qtifile)) {
1385  ilFileUtils::delDir($importdir);
1386  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('cannot_find_xml'), true);
1387  return;
1388  }
1389 
1390  ilSession::set('path_to_import_file', $file_to_import);
1391  ilSession::set('path_to_uploaded_file_in_temp_dir', $path_to_uploaded_file_in_temp_dir);
1392 
1393  $this->ctrl->setParameterByClass(self::class, 'new_type', $this->type);
1394  $form = $this->buildImportQuestionsSelectionForm(
1395  'importVerifiedFile',
1396  $importdir,
1397  $qtifile,
1398  $path_to_uploaded_file_in_temp_dir
1399  );
1400 
1401  if ($form === null) {
1402  return;
1403  }
1404 
1405  $panel = $this->ui_factory->panel()->standard(
1406  $this->lng->txt('import_qpl'),
1407  [
1408  $this->ui_factory->legacy($this->lng->txt('qpl_import_verify_found_questions')),
1409  $form
1410  ]
1411  );
1412  $this->tpl->setContent($this->ui_renderer->render($panel));
1413  $this->tpl->printToStdout();
1414  exit;
1415  }
1416 
1417  public function addLocatorItems(): void
1418  {
1419  $ilLocator = $this->locator;
1420 
1421  switch ($this->ctrl->getCmd()) {
1422  case 'create':
1423  case 'importFile':
1424  case 'cancel':
1425  break;
1426  default:
1427  $this->ctrl->clearParameterByClass(self::class, 'q_id');
1428  $ilLocator->addItem(
1429  $this->object->getTitle(),
1430  $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], ''),
1431  '',
1432  $this->request_data_collector->getRefId()
1433  );
1434  $this->ctrl->setParameter($this, 'q_id', $this->request_data_collector->getQuestionId());
1435  break;
1436  }
1437 
1438  if (!is_array($this->request_data_collector->raw('q_id')) && $this->request_data_collector->raw('q_id') > 0 && $this->request_data_collector->raw(
1439  'cmd'
1440  ) !== self::DEFAULT_CMD) {
1441  $question_gui = assQuestionGUI::_getQuestionGUI('', $this->request_data_collector->getQuestionId());
1442  if ($question_gui !== null && $question_gui->getObject() instanceof assQuestion) {
1443  $question = $question_gui->getObject();
1444  $question->setObjId($this->object->getId());
1445  $question_gui->setObject($question);
1446  $title = $question_gui->getObject()->getTitleForHTMLOutput();
1447  if (!$title) {
1448  $title = $this->lng->txt('new') . ': ' . $this->questionrepository->getForQuestionId(
1449  $question_gui->getObject()->getId()
1450  )->getTypeName($this->lng);
1451  }
1452  $ilLocator->addItem($title, $this->ctrl->getLinkTargetByClass(get_class($question_gui), 'editQuestion'));
1453  } else {
1454  // Workaround for context issues: If no object was found, redirect without q_id parameter
1455  $this->ctrl->setParameter($this, 'q_id', '');
1456  $this->ctrl->redirect($this);
1457  }
1458  }
1459  }
1460 
1464  public function setTitleAndDescription(): void
1465  {
1466  parent::setTitleAndDescription();
1467 
1468  if (!is_array($this->request_data_collector->raw('q_id')) && $this->request_data_collector->raw('q_id') > 0 && $this->request_data_collector->raw(
1469  'cmd'
1470  ) !== self::DEFAULT_CMD) {
1471  $question_gui = assQuestionGUI::_getQuestionGUI('', $this->request_data_collector->getQuestionId());
1472  if ($question_gui->getObject() instanceof assQuestion) {
1473  $question = $question_gui->getObject();
1474  $question->setObjId($this->object->getId());
1475  $question_gui->setObject($question);
1476  $title = $this->object->getTitle() . ': ' . $question_gui->getObject()->getTitle();
1477  if (!$title) {
1478  $title = $this->lng->txt('new') . ': ' . $this->questionrepository->getForQuestionId(
1479  $question_gui->getObject()->getId()
1480  )->getTypeName($this->lng);
1481  }
1482  $this->tpl->setTitle(
1483  $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform(
1484  $title,
1485  )
1486  );
1487  $this->tpl->setDescription(
1488  $question_gui->getObject()->getDescriptionForHTMLOutput()
1489  );
1490  $this->tpl->setTitleIcon(ilObject2::_getIcon($this->object->getId(), 'big', $this->object->getType()));
1491  } else {
1492  // Workaround for context issues: If no object was found, redirect without q_id parameter
1493  $this->ctrl->setParameter($this, 'q_id', '');
1494  $this->ctrl->redirect($this);
1495  }
1496  } else {
1497  $this->tpl->setTitle(
1498  $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform(
1499  $this->object->getTitle()
1500  )
1501  );
1502  $this->tpl->setDescription(
1503  $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform(
1504  $this->object->getLongDescription()
1505  )
1506  );
1507  $this->tpl->setTitleIcon(ilObject2::_getIcon($this->object->getId(), 'big', $this->object->getType()));
1508  }
1509  }
1510 
1516  public function getTabs(): void
1517  {
1518  $with_write_access = $this->access->checkAccess('write', '', $this->object->getRefId());
1519  $with_read_access = $this->access->checkAccess('read', '', $this->object->getRefId());
1520 
1521  $this->help->setScreenIdComponent('qpl');
1522 
1523  switch ($this->ctrl->getNextClass()) {
1524  case '':
1525  case strtolower(ilInfoScreenGUI::class):
1526  case strtolower(ilPermissionGUI::class):
1527  case strtolower(ilObjectMetaDataGUI::class):
1528  case strtolower(ilExportGUI::class):
1529  case strtolower(ilQuestionPoolSkillAdministrationGUI::class):
1530  break;
1531 
1532  case strtolower(ilTaxonomySettingsGUI::class):
1533  case strtolower(ilObjQuestionPoolSettingsGeneralGUI::class):
1534  if ($with_write_access) {
1535  $this->addSettingsSubTabs($this->tabs_gui);
1536  }
1537 
1538  break;
1539 
1540  default:
1541  return;
1542  }
1543  // questions
1544  $force_active = false;
1545  $commands = $this->request_data_collector->raw('cmd');
1546  if (is_array($commands)) {
1547  foreach ($commands as $key => $value) {
1548  if (preg_match('/^delete_.*/', $key, $matches) ||
1549  preg_match('/^addSelectGap_.*/', $key, $matches) ||
1550  preg_match('/^addTextGap_.*/', $key, $matches) ||
1551  preg_match('/^deleteImage_.*/', $key, $matches) ||
1552  preg_match('/^upload_.*/', $key, $matches) ||
1553  preg_match('/^addSuggestedSolution_.*/', $key, $matches)
1554  ) {
1555  $force_active = true;
1556  }
1557  }
1558  }
1559 
1560  $force_active = $force_active || $this->request_data_collector->isset('imagemap_x');
1561  if (!$force_active) {
1562  $force_active = strtolower($this->ctrl->getCmdClass()) === strtolower(self::class)
1563  || $this->ctrl->getCmdClass() === '' && $this->ctrl->getCmd() === ''
1564  ? true
1565  : false;
1566  }
1567  if ($with_read_access) {
1568  $this->tabs_gui->addTarget(
1569  'assQuestions',
1570  $this->ctrl->getLinkTargetByClass(
1571  [ilRepositoryGUI::class, self::class],
1572  self::DEFAULT_CMD
1573  ),
1574  [
1575  self::DEFAULT_CMD,
1576  'filter',
1577  'resetFilter',
1578  'createQuestion',
1579  'importQuestions',
1580  'deleteQuestions',
1581  'filterQuestionBrowser',
1582  'view',
1583  'preview',
1584  'editQuestion',
1585  'exec_pg',
1586  'addItem',
1587  'upload',
1588  'save',
1589  'cancel',
1590  'addSuggestedSolution',
1591  'cancelExplorer',
1592  'linkChilds',
1593  'removeSuggestedSolution',
1594  'add',
1595  'addYesNo',
1596  'addTrueFalse',
1597  'createGaps',
1598  'setMediaMode',
1599  'uploadingImage',
1600  'uploadingImagemap',
1601  'addArea',
1602  'deletearea',
1603  'saveShape',
1604  'back',
1605  'addPair',
1606  'uploadingJavaapplet',
1607  'addParameter',
1608  'assessment',
1609  'addGIT',
1610  'addST',
1611  'addPG',
1612  'delete',
1613  'toggleGraphicalAnswers',
1614  'deleteAnswer',
1615  'deleteImage',
1616  'removeJavaapplet'
1617  ],
1618  '',
1619  '',
1620  $force_active
1621  );
1622  }
1623  if ($with_read_access) {
1624  $this->tabs_gui->addTab(
1625  'info_short',
1626  $this->lng->txt('info_short'),
1627  $this->ctrl->getLinkTargetByClass(
1628  [
1629  ilRepositoryGUI::class,
1630  self::class,
1631  ilInfoScreenGUI::class
1632  ]
1633  )
1634  );
1635  }
1636 
1637  if ($with_write_access) {
1638  // properties
1639  $this->tabs_gui->addTarget(
1640  'settings',
1641  $this->ctrl->getLinkTargetByClass(ilObjQuestionPoolSettingsGeneralGUI::class),
1642  [],
1643  [ilObjQuestionPoolSettingsGeneralGUI::class, ilObjTaxonomyGUI::class]
1644  );
1645 
1646  // skill service
1647  if ($this->isSkillsTabRequired()) {
1648  $link = $this->ctrl->getLinkTargetByClass(
1649  [ilQuestionPoolSkillAdministrationGUI::class, ilAssQuestionSkillAssignmentsGUI::class],
1651  );
1652 
1653  $this->tabs_gui->addTarget('qpl_tab_competences', $link, [], []);
1654  }
1655  }
1656 
1657  if ($with_read_access) {
1658  // print view
1659  $this->tabs_gui->addTarget(
1660  'print_view',
1661  $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'print'),
1662  ['print'],
1663  '',
1664  ''
1665  );
1666  }
1667 
1668  if ($with_write_access) {
1669  $mdgui = new ilObjectMetaDataGUI($this->object);
1670  $mdtab = $mdgui->getTab();
1671  if ($mdtab) {
1672  $this->tabs_gui->addTarget(
1673  'meta_data',
1674  $mdtab,
1675  '',
1676  'ilmdeditorgui'
1677  );
1678  }
1679  }
1680 
1681  if ($with_write_access) {
1682  $this->tabs_gui->addTarget(
1683  'export',
1684  $this->ctrl->getLinkTargetByClass(ilExportGUI::class, ''),
1685  '',
1686  'ilexportgui'
1687  );
1688  }
1689 
1690  if ($this->access->checkAccess('edit_permission', '', $this->object->getRefId())) {
1691  $this->tabs_gui->addTarget(
1692  'perm_settings',
1693  $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class, ilPermissionGUI::class], 'perm'),
1694  ['perm', 'info', 'owner'],
1695  'ilpermissiongui'
1696  );
1697  }
1698  }
1699 
1700  private function isSkillsTabRequired(): bool
1701  {
1702  if (!($this->object instanceof ilObjQuestionPool)) {
1703  return false;
1704  }
1705 
1706  if (!$this->object->isSkillServiceEnabled()) {
1707  return false;
1708  }
1709 
1711  return false;
1712  }
1713 
1714  return true;
1715  }
1716 
1717  private function addSettingsSubTabs(ilTabsGUI $tabs): void
1718  {
1719  $tabs->addSubTab(
1721  $this->lng->txt('qpl_settings_subtab_general'),
1722  $this->ctrl->getLinkTargetByClass(ilObjQuestionPoolSettingsGeneralGUI::class),
1723  );
1724 
1725  $tabs->addSubTab(
1726  'tax_settings',
1727  $this->lng->txt('qpl_settings_subtab_taxonomies'),
1728  $this->ctrl->getLinkTargetByClass(ilTaxonomySettingsGUI::class, ''),
1729  );
1730  }
1731 
1732  public function infoScreenObject(): void
1733  {
1734  $this->ctrl->redirectByClass(
1735  [
1736  ilRepositoryGUI::class,
1737  self::class,
1738  ilInfoScreenGUI::class
1739  ]
1740  );
1741  }
1742 
1743  public function infoScreenForward(): void
1744  {
1745  if (!$this->access->checkAccess('visible', '', $this->ref_id)) {
1746  $this->error->raiseError($this->lng->txt('msg_no_perm_read'));
1747  }
1748 
1749  $this->tabs_gui->activateTab('info_short');
1750  $info = new ilInfoScreenGUI($this);
1751  $info->enablePrivateNotes();
1752  $info->addMetaDataSections($this->object->getId(), 0, $this->object->getType());
1753 
1754  $this->ctrl->forwardCommand($info);
1755  }
1756 
1757  public static function _goto($a_target): void
1758  {
1760  global $DIC;
1761  $main_tpl = $DIC->ui()->mainTemplate();
1762  $ilAccess = $DIC['ilAccess'];
1763  $ilErr = $DIC['ilErr'];
1764  $lng = $DIC['lng'];
1765  $ctrl = $DIC['ilCtrl'];
1766 
1767  $target_ref_id = (int) $a_target;
1768 
1769  if ($ilAccess->checkAccess('write', '', $target_ref_id)
1770  || $ilAccess->checkAccess('read', '', $target_ref_id)
1771  ) {
1772  $ctrl->setParameterByClass(ilObjQuestionPoolGUI::class, 'ref_id', $a_target);
1773  $ctrl->redirectByClass([ilRepositoryGUI::class, ilObjQuestionPoolGUI::class], self::DEFAULT_CMD);
1774  return;
1775  }
1776  if ($ilAccess->checkAccess('visible', '', $target_ref_id)) {
1777  $DIC->ctrl()->setParameterByClass(ilInfoScreenGUI::class, 'ref_id', $a_target);
1778  $DIC->ctrl()->redirectByClass(
1779  [
1780  ilRepositoryGUI::class,
1781  self::class,
1782  ilInfoScreenGUI::class
1783  ]
1784  );
1785  }
1786  if ($ilAccess->checkAccess('read', '', ROOT_FOLDER_ID)) {
1787  $main_tpl->setOnScreenMessage(
1788  'info',
1789  sprintf(
1790  $lng->txt('msg_no_perm_read_item'),
1792  ),
1793  true
1794  );
1796  return;
1797  }
1798  $ilErr->raiseError($lng->txt('msg_no_perm_read_lm'), $ilErr->FATAL);
1799  }
1800 
1801  protected function getTable(): string
1802  {
1805 
1806  $table = new QuestionTable(
1807  $f,
1808  $r,
1809  $this->data_factory,
1810  $this->refinery,
1811  $this->url_builder,
1812  $this->action_parameter_token,
1813  $this->row_id_token,
1814  $this->db,
1815  $this->lng,
1816  $this->component_repository,
1817  $this->rbac_system,
1818  $this->user,
1819  $this->taxonomy->domain(),
1821  $this->object->getId(),
1822  $this->request_data_collector->getRefId()
1823  );
1824 
1829  $filter_action = $this->ctrl->getLinkTarget($this, self::DEFAULT_CMD);
1830  $filter = $table->getFilter($this->ui_service, $filter_action);
1831 
1832  $filter_params = $this->ui_service->filter()->getData($filter);
1833 
1834  if ($filter_params) {
1835  foreach (array_filter($filter_params) as $item => $value) {
1836  switch ($item) {
1837  case 'taxonomies':
1838  foreach ($value as $tax_value) {
1839  if ($tax_value === 'null') {
1840  $table->addTaxonomyFilterNoTaxonomySet(true);
1841  } else {
1842  $tax_nodes = explode('-', $tax_value);
1843  $tax_id = array_shift($tax_nodes);
1844  $table->addTaxonomyFilter(
1845  $tax_id,
1846  $tax_nodes,
1847  $this->object->getId(),
1848  $this->object->getType()
1849  );
1850  }
1851  }
1852  break;
1853  case 'commented':
1854  $table->setCommentFilter((int) $value);
1855  break;
1856  default:
1857  $table->addFieldFilter($item, $value);
1858  }
1859  }
1860  }
1861 
1862  return $r->render([
1863  $filter,
1864  $table->getTable()
1865  ->withRequest($this->request)
1866  ]);
1867  }
1868 }
const ADDITIONAL_CONTENT_EDITING_MODE_IPE
ilNavigationHistory $navigation_history
setEditPreview(bool $a_editpreview)
Set Display first Edit tab, then Preview tab, instead of Page and Edit.
static get(string $a_var)
afterSave(ilObject $new_object)
static getStyleSheetLocation(string $mode="output", string $a_css_name="")
get full style sheet file name (path inclusive) of current user
Class ilObjectMetaDataGUI.
Readable part of repository interface to ilComponentDataDB.
ilRbacSystem $rbac_system
importQuestionsFile(string $path_to_uploaded_file_in_temp_dir)
This describes commonalities between all forms.
Definition: Form.php:32
redirectByClass( $a_class, string $a_cmd=null, string $a_anchor=null, bool $is_async=false)
static _getIcon(int $obj_id=0, string $size="big", string $type="", bool $offline=false)
Get icon for repository item.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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...
confirmDeleteQuestionsObject()
delete questions after confirmation
GUI class for the workflow of copying objects.
const ROOT_FOLDER_ID
Definition: constants.php:32
prepareOutput(bool $show_sub_objects=true)
static getQuestionTypeByTypeId($type_id)
Help GUI class.
importFile(string $file_to_import, string $path_to_uploaded_file_in_temp_dir)
buildImportQuestionsSelectionForm(string $form_cmd, string $importdir, string $qtifile, string $path_to_uploaded_file_in_temp_dir=null)
acquireParameters(array $namespace, string ... $names)
Definition: URLBuilder.php:137
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This describes select field.
Definition: Select.php:28
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Import class.
setParameterByClass(string $a_class, string $a_parameter, $a_value)
Component logger with individual log levels by component id.
$url
Definition: shib_logout.php:63
getTabs()
adds tabs to tab gui object
download_paragraphObject()
download source code paragraph
RequestDataCollector $request_data_collector
exportObject()
Gateway for exports initiated from workspace, as there is a generic forward to {objTypeMainGUI}::expo...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Refinery $refinery
static _getQuestionGUI(string $question_type='', int $question_id=-1)
Creates a question gui representation and returns the alias to the question gui.
const CMD_SHOW_LIST
command constants
importObject(?object $a_new_obj, string $a_tmp_file, string $a_filename, string $a_type, string $a_comp="", bool $a_copy_file=false)
$ilErr
Definition: raiseError.php:17
static _lookupObjId(int $ref_id)
static deliverFileLegacy(string $a_file, ?string $a_filename=null, ?string $a_mime=null, ?bool $isInline=false, ?bool $removeAfterDelivery=false, ?bool $a_exit_after=true)
Interface ilCtrlBaseClassInterface describes ilCtrl base classes.
deleteUploadedImportFile(string $path_to_uploaded_file_in_temp_dir)
ilLanguage $lng
ilComponentRepository $component_repository
addSubTab(string $a_id, string $a_text, string $a_link, string $a_frame="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static http()
Fetches the global http state from ILIAS.
UIFactory $ui_factory
importQuestionsFromQtiFile(ilObjQuestionPool $obj, array $selected_questions, string $qtifile, string $importdir, string $xmlfile='')
deleteQuestionsObject()
delete questions confirmation screen
ilComponentFactory $component_factory
static _lookupTitle(int $obj_id)
ILIAS Notes Service $notes_service
setTitleAndDescription()
called by prepare output
questionsObject(RoundTripModal $import_questions_modal=null)
list questions of question pool
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
importQuestionPoolWithValidManifest(ilObjQuestionPool $obj, array $selected_questions, string $file_to_import)
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
Class ilObjFile.
$out
Definition: buildRTE.php:24
global $DIC
Definition: shib_login.php:25
GeneralQuestionPropertiesRepository $questionrepository
Legacy Content Object Parser.
Class ilObjForumAdministration.
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:59
Class ilObjQuestionPoolGUI.
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.
withValue($value)
Get an input like this with another value displayed on the client side.
$filename
Definition: buildRTE.php:78
checkPermissionBool(string $perm, string $cmd="", string $type="", ?int $ref_id=null)
static redirect(string $a_script)
static buildAjaxHash(int $node_type, ?int $node_id, string $obj_type, int $obj_id, string $sub_type=null, int $sub_id=null, int $news_id=0)
Build ajax hash.
fullscreenObject()
show fullscreen view
retrieveSelectedQuestionsFromImportQuestionsSelectionForm(string $form_cmd, string $importdir, string $qtifile, ServerRequestInterface $request)
sendParagraph(string $par_id, string $filename)
__construct(Container $dic, ilPlugin $plugin)
const ADDITIONAL_CONTENT_EDITING_MODE_RTE
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
GlobalTestSettings $global_test_settings
This describes commonalities between all inputs.
Definition: Input.php:46
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
array buildImportDirectoriesFromImportFile(string $file_to_import)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setPrimaryCmd(string $label, string $cmd)
static getListCommentsJSCall(string $a_hash, string $a_update_code=null)
Get list comments js call.
URLBuilder.
Definition: URLBuilder.php:39
ilLocatorGUI $locator
static clear(string $a_var)
UIRenderer $ui_renderer
static set(string $a_var, $a_val)
Set a value.
showMediaFullscreen(int $a_style_id=0)
show fullscreen view of media object
static getInstanceFromAjaxCall()
(Re-)Build instance from ajax call
static _gotoRepositoryRoot(bool $raise_error=false)
Goto repository root.
cleanupAfterImport(string $importdir)
$r