ILIAS  trunk Revision v12.0_alpha-1540-g00f839d5fa1
class.TestScreenGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
26use ILIAS\Data\Factory as DataFactory;
33use ILIAS\UI\Factory as UIFactory;
34use ILIAS\UI\Renderer as UIRenderer;
35use ILIAS\HTTP\Services as HTTPServices;
37use ILIAS\Style\Content\Service as ContentStyle;
38
45{
46 public const DEFAULT_CMD = 'testScreen';
47
48 private readonly \ilTestPassesSelector $test_passes_selector;
49 private readonly int $ref_id;
50 private readonly MainSettings $main_settings;
51 private readonly \ilTestSession $test_session;
52 private readonly DataFactory $data_factory;
53 private \ilTestPasswordChecker $password_checker;
54
55 public function __construct(
56 private readonly \ilObjTest $object,
57 private readonly \ilObjUser $user,
58 private readonly UIFactory $ui_factory,
59 private readonly UIRenderer $ui_renderer,
60 private readonly \ilLanguage $lng,
61 private readonly Refinery $refinery,
62 private readonly \ilCtrlInterface $ctrl,
63 private readonly \ilGlobalTemplateInterface $tpl,
64 private readonly ContentStyle $content_style,
65 private readonly HTTPServices $http,
66 private readonly TabsManager $tabs_manager,
67 private readonly \ilAccessHandler $access,
68 private readonly \ilTestAccess $test_access,
69 private readonly \ilDBInterface $database,
70 private readonly \ilRbacSystem $rbac_system
71 ) {
72 $this->ref_id = $this->object->getRefId();
73 $this->main_settings = $this->object->getMainSettings();
74 $this->data_factory = new DataFactory();
75
76 $this->test_session = (new \ilTestSessionFactory($this->object, $this->database, $this->user))->getSession();
77
78 $this->test_passes_selector = new \ilTestPassesSelector($this->database, $this->object);
79 $this->test_passes_selector->setActiveId($this->test_session->getActiveId());
80 $this->test_passes_selector->setLastFinishedPass($this->test_session->getLastFinishedPass());
81 $this->password_checker = new \ilTestPasswordChecker($this->rbac_system, $this->user, $this->object, $this->lng);
82 }
83
84 public function executeCommand(): void
85 {
86 if ($this->access->checkAccess('read', '', $this->ref_id)) {
87 $this->{$this->ctrl->getCmd(self::DEFAULT_CMD)}();
88 return;
89 }
90
91 $this->tabs_manager->activateTab(TabsManager::TAB_ID_TEST);
92
93 if (!$this->object->getMainSettings()->getAdditionalSettings()->getHideInfoTab()) {
94 $this->ctrl->redirectByClass([\ilRepositoryGUI::class, \ilObjTestGUI::class, \ilInfoScreenGUI::class]);
95 }
96
97 $this->tpl->setOnScreenMessage('failure', sprintf(
98 $this->lng->txt('msg_no_perm_read_item'),
99 $this->object->getTitle()
100 ), true);
101 $this->ctrl->setParameterByClass(\ilRepositoryGUI::class, 'ref_id', ROOT_FOLDER_ID);
102 $this->ctrl->redirectByClass(\ilRepositoryGUI::class);
103 }
104
105 public function testScreen(): void
106 {
107 $this->tabs_manager->activateTab(TabsManager::TAB_ID_TEST);
108 $this->tpl->setPermanentLink($this->object->getType(), $this->ref_id);
109
110 $elements = [];
111
112 if ($this->areSkillLevelThresholdsMissing()) {
113 $elements = [$this->getSkillLevelThresholdsMissingInfo()];
114 }
115 $elements = $this->handleRenderMessageBox($elements);
116 $elements = $this->handleRenderIntroduction($elements);
117
118 if ($this->testCanBeStarted()) {
119 $this->tpl->setContent(
120 $this->ui_renderer->render(
121 $this->handleRenderLauncher(
122 $elements
123 )
124 )
125 );
126 return;
127 }
128
129 $this->tpl->setContent(
130 $this->ui_renderer->render(
131 $this->addOfflineMessageBoxIfNecessary(
132 $elements
133 )
134 )
135 );
136 }
137
138 private function addOfflineMessageBoxIfNecessary(array $elements): array
139 {
140 if (!$this->object->getOfflineStatus()) {
141 return $elements;
142 }
143
144 $offline_message_box = $this->ui_factory->messageBox()->info($this->lng->txt('test_is_offline'));
145
146 if (!$this->access->checkAccess('write', '', $this->object->getRefId())) {
147 $elements[] = $offline_message_box;
148 return $elements;
149 }
150
151 $elements[] = $offline_message_box->withLinks([
152 $this->ui_factory->link()->standard(
153 $this->lng->txt('test_edit_settings'),
154 $this->ctrl->getLinkTargetByClass(SettingsMainGUI::class)
155 )
156 ]);
157 return $elements;
158 }
159
160 private function handleRenderMessageBox(array $elements): array
161 {
162 $message_box_message = '';
163 $message_box_message_elements = [];
164
165 $exam_conditions_enabled = $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled();
166 $password_enabled = $this->main_settings->getAccessSettings()->getPasswordEnabled();
167 $test_behaviour_settings = $this->main_settings->getTestBehaviourSettings();
168
169 if ($exam_conditions_enabled && $password_enabled) {
170 $message_box_message_elements[] = $this->lng->txt('tst_launcher_status_message_conditions_and_password');
171 } elseif ($exam_conditions_enabled) {
172 $message_box_message_elements[] = $this->lng->txt('tst_launcher_status_message_conditions');
173 } elseif ($password_enabled) {
174 $message_box_message_elements[] = $this->lng->txt('tst_launcher_status_message_password');
175 }
176
177 if ($test_behaviour_settings->getProcessingTimeEnabled() && !$this->isUserOutOfProcessingTime()) {
178 $message_box_message_elements[] = sprintf(
179 $this->lng->txt('tst_time_limit_message'),
180 $test_behaviour_settings->getProcessingTimeAsMinutes()
181 );
182 }
183
184 $nr_of_tries = $this->object->getNrOfTries();
185
186 if ($nr_of_tries !== 0) {
187 $message_box_message_elements[] = sprintf($this->lng->txt('tst_attempt_limit_message'), $nr_of_tries);
188 }
189
190 if ($this->object->isStartingTimeEnabled() && !$this->object->startingTimeReached()) {
191 $message_box_message_elements[] = sprintf(
192 $this->lng->txt('detail_starting_time_not_reached'),
193 \ilDatePresentation::formatDate(new \ilDateTime($this->object->getStartingTime(), IL_CAL_UNIX))
194 );
195 }
196
197 if ($this->object->isEndingTimeEnabled() && !$this->object->endingTimeReached()) {
198 $message_box_message_elements[] = sprintf(
199 $this->lng->txt('tst_exam_ending_time_message'),
200 \ilDatePresentation::formatDate(new \ilDateTime($this->object->getEndingTime(), IL_CAL_UNIX))
201 );
202 }
203
204 foreach ($message_box_message_elements as $message_box_message_element) {
205 $message_box_message .= ' ' . $message_box_message_element;
206 }
207
208 if (!empty($message_box_message)) {
209 $elements[] = $this->ui_factory->messageBox()->info($message_box_message);
210 }
211
212 return $elements;
213 }
214
215 private function handleRenderIntroduction(array $elements): array
216 {
217 $introduction = $this->object->getIntroduction();
218
219 if (
220 $this->main_settings->getIntroductionSettings()->getIntroductionEnabled() &&
221 !empty($introduction)
222 ) {
223 $this->content_style->gui()->addCss($this->tpl, $this->ref_id);
224 $elements[] = $this->ui_factory->panel()->standard(
225 $this->lng->txt('tst_introduction'),
226 $this->ui_factory->legacy()->content($introduction),
227 );
228 }
229
230 return $elements;
231 }
232
233 private function handleRenderLauncher(array $elements): array
234 {
235 $elements[] = $this->getLauncher();
236 return $elements;
237 }
238
239 private function getLauncher(): Launcher
240 {
241 $launcher_factory = $this->ui_factory->launcher();
242
243 if ($this->object->isStartingTimeEnabled() && !$this->object->startingTimeReached()) {
244 return $launcher_factory
245 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
246 ->withButtonLabel(sprintf(
247 $this->lng->txt('detail_starting_time_not_reached'),
248 \ilDatePresentation::formatDate(new \ilDateTime($this->object->getStartingTime(), IL_CAL_UNIX))
249 ), false)
250 ;
251 }
252
253 if ($this->object->isEndingTimeEnabled() && $this->object->endingTimeReached()) {
254 return $launcher_factory
255 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
256 ->withButtonLabel(sprintf(
257 $this->lng->txt('detail_ending_time_reached'),
258 \ilDatePresentation::formatDate(new \ilDateTime($this->object->getEndingTime(), IL_CAL_UNIX))
259 ), false)
260 ;
261 }
262
263 if ($this->isUserOutOfProcessingTime()) {
264 return $launcher_factory
265 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
266 ->withButtonLabel($this->lng->txt('tst_out_of_time_message'), false)
267 ;
268 }
269
270 $participant_access = $this->test_access->isParticipantAllowed(
271 $this->object->getId(),
272 $this->user->getId()
273 );
274
275 if ($participant_access === ParticipantAccess::NOT_INVITED) {
276 return $launcher_factory
277 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
278 ->withButtonLabel($this->lng->txt('tst_exam_not_assigned_participant_disclaimer'), false)
279 ;
280 }
281
282 if ($participant_access !== ParticipantAccess::ALLOWED) {
283 return $launcher_factory
284 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
285 ->withButtonLabel($participant_access->getAccessForbiddenMessage($this->lng), false)
286 ;
287 }
288
289 if (!$this->hasAvailablePasses()) {
290 return $launcher_factory
291 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
292 ->withButtonLabel($this->lng->txt('tst_launcher_button_label_passes_limit_reached'), false);
293 }
294
295 if ($this->blockUserAfterHavingPassed()) {
296 return $launcher_factory
297 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
298 ->withButtonLabel($this->lng->txt('tst_already_passed_cannot_retake'), false)
299 ;
300 }
301
302 $next_pass_allowed_timestamp = 0;
303 if (!$this->object->isNextPassAllowed($this->test_passes_selector, $next_pass_allowed_timestamp)) {
304 return $launcher_factory
305 ->inline($this->data_factory->link('', $this->data_factory->uri($this->http->request()->getUri()->__toString())))
306 ->withButtonLabel(
307 sprintf(
308 $this->lng->txt('wait_for_next_pass_hint_msg'),
309 \ilDatePresentation::formatDate(new \ilDateTime($next_pass_allowed_timestamp, IL_CAL_UNIX)),
310 ),
311 false
312 )
313 ;
314 }
315
316 if ($this->lastPassSuspended()) {
317 return $launcher_factory->inline($this->getResumeLauncherLink());
318 }
319
320 if ($this->isModalLauncherNeeded()) {
321 return $this->buildModalLauncher();
322 }
323 return $launcher_factory->inline($this->getStartLauncherLink());
324 }
325
326 private function getResumeLauncherLink(): Link
327 {
328 return $this->data_factory->link(
329 $this->lng->txt('tst_resume_test'),
330 $this->buildLauncherLinkUrl(\ilTestPlayerCommands::RESUME_PLAYER)
331 );
332 }
333
334 private function buildModalLauncher(): Launcher
335 {
336 $launcher = $this->ui_factory->launcher()->inline($this->getModalLauncherLink())
337 ->withInputs(
338 $this->ui_factory->input()->field()->group($this->getModalLauncherInputs()),
339 function (Result $result) {
340 $this->evaluateLauncherModalForm($result);
341 },
343 )->withModalSubmitLabel($this->lng->txt('continue'));
344
345 $request = $this->http->request();
346 $key = 'launcher_id';
347 if (array_key_exists($key, $request->getQueryParams())
348 && $request->getQueryParams()[$key] === 'exam_modal') {
349 $launcher = $launcher->withRequest($request);
350 }
351
352 return $launcher;
353 }
354
355 private function getModalLauncherLink(): Link
356 {
357 return $this->data_factory->link(
358 $this->lng->txt('tst_exam_start'),
359 $this->data_factory->uri(
360 $this->http->request()->getUri()->__toString()
361 )->withParameter('launcher_id', 'exam_modal')
362 );
363 }
364
365 private function getModalLauncherInputs(): array
366 {
367 if ($this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled()) {
368 $modal_inputs['exam_conditions'] = $this->ui_factory->input()->field()->checkbox(
369 $this->lng->txt('tst_exam_conditions'),
370 $this->lng->txt('tst_exam_conditions_label')
371 )->withRequired(true)
372 ->withAdditionalTransformation(
373 $this->refinery->custom()->constraint(
374 static fn(bool $value): bool => $value,
375 $this->lng->txt('tst_exam_conditions_not_checked_message'),
376 )
377 );
378 }
379
380 if ($this->main_settings->getAccessSettings()->getPasswordEnabled()) {
381 $modal_inputs['exam_password'] = $this->ui_factory->input()->field()->password(
382 $this->lng->txt('tst_exam_password'),
383 $this->lng->txt('tst_exam_password_label')
384 )->withRevelation(true)
385 ->withRequired(true)
386 ->withAdditionalTransformation(
387 $this->refinery->custom()->constraint(
388 fn(Password $value): bool => $value->toString() === $this->main_settings->getAccessSettings()->getPassword(),
389 $this->lng->txt('tst_exam_password_invalid_message'),
390 )
391 );
392 }
393
394 if ($this->user->isAnonymous()) {
395 $access_code_input = $this->ui_factory->input()->field()->text(
396 $this->lng->txt('tst_exam_access_code'),
397 $this->lng->txt('tst_exam_access_code_label')
398 )->withAdditionalTransformation(
399 $this->refinery->custom()->constraint(
400 fn(string $value): bool => $value === '' || $this->test_session->isAccessCodeUsed($value),
401 $this->lng->txt('tst_exam_access_code_invalid_message'),
402 )
403 );
404
405 $access_code_from_session = $this->test_session->getAccessCodeFromSession();
406 if ($access_code_from_session) {
407 $access_code_input = $access_code_input->withValue($access_code_from_session);
408 }
409
410 $modal_inputs['exam_access_code'] = $access_code_input;
411 }
412
413 if (
414 $this->test_passes_selector->getLastFinishedPass() >= 0
415 && $this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
416 ) {
417 $modal_inputs['exam_use_previous_answers'] = $this->ui_factory->input()->field()->checkbox(
418 $this->lng->txt('tst_exam_use_previous_answers'),
419 $this->lng->txt('tst_exam_use_previous_answers_label')
420 )->withAdditionalTransformation(
421 $this->refinery->custom()->transformation(
422 static fn(bool $value): string => $value ? '1' : '0'
423 )
424 );
425 }
426
427 return $modal_inputs ?? [];
428 }
429
431 {
432 $exam_conditions_enabled = $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled();
433 $password_enabled = $this->main_settings->getAccessSettings()->getPasswordEnabled();
434
435 if ($exam_conditions_enabled && $password_enabled) {
436 $modal_message_box_message = $this->lng->txt('tst_exam_modal_message_conditions_and_password');
437 } elseif ($exam_conditions_enabled) {
438 $modal_message_box_message = $this->lng->txt('tst_exam_modal_message_conditions');
439 } elseif ($password_enabled) {
440 $modal_message_box_message = $this->lng->txt('tst_exam_modal_message_password');
441 }
442
443 return isset($modal_message_box_message) ? $this->ui_factory->messageBox()->info($modal_message_box_message) : null;
444 }
445
446 private function getStartLauncherLink(): Link
447 {
448 return $this->data_factory->link(
449 $this->lng->txt('tst_exam_start'),
450 $this->buildLauncherLinkUrl(\ilTestPlayerCommands::INIT_TEST)
451 );
452 }
453
454 private function buildLauncherLinkUrl(
455 string $cmd
456 ): \ILIAS\Data\URI {
457 return $this->data_factory->uri(
458 ILIAS_HTTP_PATH . '/' . $this->ctrl->getLinkTargetByClass(
459 [
460 \ilRepositoryGUI::class,
461 \ilObjTestGUI::class,
462 $this->object->isFixedTest()
465 ],
466 $cmd
467 )
468 );
469 }
470
471 private function evaluateLauncherModalForm(Result $result): void
472 {
473 if ($result->isError()) {
474 return;
475 }
476
477 $anonymous = $this->user->isAnonymous();
478 if (array_key_exists('exam_access_code', $result->value())) {
479 $value = $result->value()['exam_access_code'];
480 if ($anonymous && !empty($value)) {
481 $this->test_session->setAccessCodeToSession($value);
482 } else {
483 $this->test_session->unsetAccessCodeInSession();
484 }
485 }
486
487 if (
488 !$anonymous &&
489 $this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
490 ) {
491 $this->user->setPref(
492 'tst_use_previous_answers',
493 $result->value()['exam_use_previous_answers'] ?? '0'
494 );
495 $this->user->update();
496 }
497
498 if ($this->main_settings->getAccessSettings()->getPasswordEnabled()) {
499 $this->checkPassword($result);
500 }
501
502 $this->ctrl->redirectByClass(
503 (new \ilTestPlayerFactory($this->object))->getPlayerGUI()::class,
505 );
506 }
507
508 private function checkPassword(
509 Result $result
510 ): void {
511 $password = $result->value()['exam_password']?->toString();
512 if ($password === $this->main_settings->getAccessSettings()->getPassword()) {
513 \ilSession::set('tst_password_' . $this->object->getTestId(), $password);
514 return;
515 }
516
517 \ilSession::set('tst_password_' . $this->object->getTestId(), '');
518 $this->test_session->setPasswordChecked(false);
519 }
520
521 private function testCanBeStarted(): bool
522 {
523 if ($this->object->getOfflineStatus()
524 || !$this->object->isComplete($this->object->getQuestionSetConfig())) {
525 return false;
526 }
527
528 return true;
529 }
530
531 private function isUserOutOfProcessingTime(): bool
532 {
533 $test_behaviour_settings = $this->object->getMainSettings()->getTestBehaviourSettings();
534 if (!$test_behaviour_settings->getProcessingTimeEnabled()
535 || $test_behaviour_settings->getResetProcessingTime()) {
536 return false;
537 }
538
539 $active_id = $this->test_passes_selector->getActiveId();
540 $last_started_pass = $this->test_session->getLastStartedPass();
541 return $last_started_pass !== null
542 && $this->object->isMaxProcessingTimeReached(
543 $this->object->getStartingTimeOfUser($active_id, $last_started_pass),
544 $active_id
545 );
546 }
547
548 private function blockUserAfterHavingPassed(): bool
549 {
550 if ($this->main_settings->getTestBehaviourSettings()->getBlockAfterPassedEnabled()) {
551 return $this->test_passes_selector->getLastFinishedPass() >= 0
552 && $this->test_passes_selector->hasTestPassedOnce($this->test_session->getActiveId());
553 }
554
555 return false;
556 }
557
558 private function hasAvailablePasses(): bool
559 {
560 $nr_of_tries = $this->object->getNrOfTries();
561
562 return $nr_of_tries === 0 || (count($this->test_passes_selector->getExistingPasses()) <= $nr_of_tries && count($this->test_passes_selector->getClosedPasses()) < $nr_of_tries);
563 }
564
565 private function lastPassSuspended(): bool
566 {
567 return (count($this->test_passes_selector->getExistingPasses()) - count($this->test_passes_selector->getClosedPasses())) === 1;
568 }
569
570 private function isModalLauncherNeeded(): bool
571 {
572 return (
573 $this->main_settings->getIntroductionSettings()->getExamConditionsCheckboxEnabled()
574 || $this->main_settings->getAccessSettings()->getPasswordEnabled()
575 || $this->main_settings->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed()
576 && $this->test_passes_selector->getLastFinishedPass() >= 0
577 || $this->user->isAnonymous()
578 );
579 }
580
582 {
583 return $this->ui_factory->messageBox()->failure(
584 $this->lng->txt('tst_skl_level_thresholds_missing')
585 )->withLinks([
586 $this->ui_factory->link()->standard(
587 $this->lng->txt('tst_skl_level_thresholds_link'),
588 $this->ctrl->getLinkTargetByClass(
589 [
590 \ilRepositoryGUI::class,
591 \ilObjTestGUI::class,
592 \ilTestSkillAdministrationGUI::class,
593 \ilTestSkillLevelThresholdsGUI::class
594 ],
596 )
597 )
598 ]);
599 }
600
601 private function areSkillLevelThresholdsMissing(): bool
602 {
603 if (!$this->object->isSkillServiceEnabled()) {
604 return false;
605 }
606
607 $questionContainerId = $this->object->getId();
608
609 $assignmentList = new \ilAssQuestionSkillAssignmentList($this->database);
610 $assignmentList->setParentObjId($questionContainerId);
611 $assignmentList->loadFromDb();
612
613 foreach ($assignmentList->getUniqueAssignedSkills() as $data) {
614 foreach ($data['skill']->getLevelData() as $level) {
615 $threshold = new \ilTestSkillLevelThreshold($this->database);
616 $threshold->setTestId($this->object->getTestId());
617 $threshold->setSkillBaseId($data['skill_base_id']);
618 $threshold->setSkillTrefId($data['skill_tref_id']);
619 $threshold->setSkillLevelId($level['id']);
620
621 if (!$threshold->dbRecordExists()) {
622 return true;
623 }
624 }
625 }
626
627 return false;
628 }
629}
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Builds data types.
Definition: Factory.php:36
A password is used as part of credentials for authentication.
Definition: Password.php:31
The scope of this class is split ilias-conform URI's into components.
Definition: URI.php:35
Class Services.
Definition: Services.php:38
__construct(private readonly \ilObjTest $object, private readonly \ilObjUser $user, private readonly UIFactory $ui_factory, private readonly UIRenderer $ui_renderer, private readonly \ilLanguage $lng, private readonly Refinery $refinery, private readonly \ilCtrlInterface $ctrl, private readonly \ilGlobalTemplateInterface $tpl, private readonly ContentStyle $content_style, private readonly HTTPServices $http, private readonly TabsManager $tabs_manager, private readonly \ilAccessHandler $access, private readonly \ilTestAccess $test_access, private readonly \ilDBInterface $database, private readonly \ilRbacSystem $rbac_system)
readonly ilTestPassesSelector $test_passes_selector
@ilCtrl_Calls ILIAS\Test\Settings\MainSettings\SettingsMainGUI: ilPropertyFormGUI @ilCtrl_Calls ILIAS...
const IL_CAL_UNIX
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
@classDescription Date and time handling
language handling
Class ilObjTestGUI.
User class.
class ilRbacSystem system function like checkAccess, addActiveRole ... Supporting system functions ar...
Class ilRepositoryGUI.
static set(string $a_var, $a_val)
Set a value.
const ROOT_FOLDER_ID
Definition: constants.php:32
$http
Definition: deliver.php:30
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
A result encapsulates a value or an error and simplifies the handling of those.
Definition: Result.php:29
isError()
Get to know if the result is an error.
value()
Get the encapsulated value.
withButtonLabel(string $label, bool $launchable=true)
Labels the button that launches the process; if the process is not launchable for the user,...
withInputs(Group $fields, \Closure $evaluation, ?MessageBox\MessageBox $instruction=null)
If the Launcher is configured with Inputs, an Roundtrip Modal is shown with these Inputs.
withLinks(array $links)
Get a Message Box like this, but with links.
An entity that renders components to a string output.
Definition: Renderer.php:31
Interface ilAccessHandler This interface combines all available interfaces which can be called via gl...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Interface ilDBInterface.
static http()
Fetches the global http state from ILIAS.
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
global $lng
Definition: privfeed.php:26