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