ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
Administration.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
30 use ilDateTime;
33 use Closure;
40 use Exception;
47 
49 {
51  private readonly Closure $confirmation;
52 
56  public function __construct(
57  private readonly Config $config,
58  private readonly Container $container,
59  private readonly UI $ui,
60  ?Closure $confirmation = null
61  ) {
62  $this->confirmation = $confirmation ?? fn() => new Confirmation($this->container->language());
63  }
64 
68  public function deleteDocumentsConfirmation(string $form_link, string $submit_command, string $cancel_command, array $documents): string
69  {
70  $items = array_column(array_map(fn($x) => [$x->id(), $x->content()->title()], $documents), 1, 0);
71 
72  return (($this->confirmation)())->render(
73  $form_link,
74  $submit_command,
75  $cancel_command,
76  $this->ui->txt('sure_delete_documents_p'),
77  $items
78  );
79  }
80 
84  public function deleteDocuments(array $documents): void
85  {
86  array_map(
87  $this->config->legalDocuments()->document()->repository()->deleteDocument(...),
88  $documents
89  );
90  }
91 
95  public function withDocumentAndCriterion(Closure $proc): void
96  {
97  $document = $this->currentDocument()->value();
98  $criterion_id = ($this->container->http()->request()->getQueryParams()['criterion_id'] ?? null);
99  if (null === $criterion_id) {
100  throw new InvalidArgumentException('Missing query parameter criterion_id.');
101  }
102  $criterion_id = (int) $criterion_id;
103 
104  $criterion = $this->find(
105  fn($criterion) => $criterion->id() === $criterion_id,
106  $document->criteria()
107  );
108  if (!$criterion) {
109  throw new InvalidArgumentException('Invalid criterion_id given.');
110  }
111 
112  $proc($document, $criterion);
113  }
114 
118  public function retrieveDocuments(): array
119  {
120  $ids = $this->retrieveIds();
121  $documents = $this->config->legalDocuments()->document()->repository()->select($ids);
122  if (count($documents) !== count($ids)) {
123  throw new InvalidArgumentException('List contains invalid documents.');
124  }
125 
126  return $documents;
127  }
128 
132  public function retrieveIds(): array
133  {
134  $r = $this->container->refinery();
135  return $this->container->http()->wrapper()->post()->retrieve('ids', $this->container->refinery()->byTrying([
136  $r->in()->series([$r->null(), $r->always([])]),
137  $r->to()->listOf($r->kindlyTo()->int())
138  ]));
139  }
140 
144  public function idOrHash(object $gui, Closure $then): void
145  {
146  $with_doc_id = fn($document) => $then($this->willLinkWith($gui, ['doc_id' => $document->id()]), $document->content()->title(), new NumberId($document), false);
147  $with_hash = fn(string $hash) => $then($this->willLinkWith($gui, ['hash' => $hash]), '', new HashId($hash), true);
148  $try_hash = fn() => new Ok($with_hash($this->requireDocumentHash()));
149 
150  $this->currentDocument()
151  ->map($with_doc_id)
152  ->except($try_hash)
153  ->value();
154 
155  }
156 
157  public function targetWithDoc(object $gui, Document $document, string $cmd, string $method = 'getLinkTarget'): string
158  {
159  $link = $this->willLinkWith($gui, ['doc_id' => (string) $document->id()]);
160  return $link($cmd, $method);
161  }
162 
163  public function targetWithDocAndCriterion(object $gui, Document $document, Criterion $criterion, string $cmd, string $method = 'getLinkTarget'): string
164  {
165  $link = $this->willLinkWith($gui, [
166  'doc_id' => (string) $document->id(),
167  'criterion_id' => (string) $criterion->id(),
168  ]);
169 
170  return $link($cmd, $method);
171  }
172 
178  public function willLinkWith($gui, array $parameters = []): Closure
179  {
180  $class = is_string($gui) ? $gui : $gui::class;
181  return function (string $cmd, ?string $method = null) use ($gui, $class, $parameters): string {
182  $method ??= $class === $gui ? 'getLinkTargetByClass' : 'getLinkTarget';
183  $array = $this->container->ctrl()->getParameterArrayByClass($class);
184  foreach ($parameters as $key => $value) {
185  $this->container->ctrl()->setParameterByClass($class, (string) $key, $value);
186  }
187  $link = $this->container->ctrl()->$method($gui, $cmd);
188  foreach ($parameters as $key => $_) {
189  $this->container->ctrl()->setParameterByClass($class, (string) $key, $array[$key] ?? '');
190  }
191 
192  return $link;
193  };
194  }
195 
199  public function withFormData(Form $form, Closure $then): Form
200  {
201  $request = $this->container->http()->request();
202  if ($request->getMethod() !== 'POST') {
203  return $form;
204  }
205  $form = $form->withRequest($request);
206  $data = $form->getData();
207 
208  if ($data !== null) {
209  $then($data);
210  }
211 
212  return $form;
213  }
214 
221  public function find(Closure $predicate, array $array)
222  {
223  foreach ($array as $value) {
224  if ($predicate($value)) {
225  return $value;
226  }
227  }
228 
229  return null;
230  }
231 
235  public function currentDocument(): Result
236  {
237  $repo = $this->config->legalDocuments()->document()->repository();
238  $doc_id = $this->container->http()->request()->getQueryParams()['doc_id'] ?? null;
239  return $this->container->refinery()->kindlyTo()->int()->applyTo(new Ok($doc_id))->then($repo->find(...));
240  }
241 
242  public function criterionForm(string $url, Document $document, ?CriterionContent $criterion = null): Form
243  {
244  $groups = $this->config->legalDocuments()->document()->conditionGroups($criterion);
245  $group = $this->ui->create()->input()->field()->switchableGroup($groups->choices(), $this->ui->txt('form_criterion'));
246  $value = $criterion ? $criterion->type() : $groups->defaultSelection();
247  if ($value) {
248  $group = $group->withValue($value);
249  }
250 
251  $title = $this->ui->create()->input()->field()->text($this->ui->txt('form_document'))->withValue($document->content()->title())->withDisabled(true);
252 
253  $section = $this->ui->create()->input()->field()->section([
254  $title,
255  'content' => $group,
256  ], $this->ui->txt($criterion ? 'form_edit_criterion_head' : 'form_attach_criterion_head'));
257 
258  return $this->ui->create()->input()->container()->form()->standard($url, [$section]);
259  }
260 
261  public function requireDocumentHash(): string
262  {
263  return $this->container->http()->wrapper()->query()->retrieve('hash', $this->container->refinery()->to()->string());
264  }
265 
270  public function tabs(array $tabs, array $run_after = []): void
271  {
272  foreach ($tabs as $tab) {
273  $this->addTab(...$tab);
274  if (isset($run_after[$tab[0]])) {
275  $run_after[$tab[0]]();
276  }
277  }
278  }
279 
280  public function uploadContent(): string
281  {
282  $value = null;
283  $upload = $this->container->upload();
284  $upload->register(new PreProcessor(function (string $content) use (&$value): void {
285  $value = $content;
286  }));
287  $upload->process();
288  $result_array = $upload->getResults();
289  if (count($result_array) !== 1 || !current($result_array)->isOk()) {
290  throw new Exception('Unexpected upload result.');
291  }
292 
293  return $value;
294  }
295 
299  public function setContent($component): void
300  {
301  $this->ui->mainTemplate()->setContent($this->render($component));
302  }
303 
304  public function addDocumentButton(string $add_document_link): Component
305  {
306  return $this->ui->create()->button()->primary(
307  $this->ui->txt('add_document_btn_label'),
308  $add_document_link
309  );
310  }
311 
315  public function setVariable(string $variable, $component): void
316  {
317  $this->ui->mainTemplate()->setVariable($variable, $this->render($component));
318  }
319 
323  public function render($component): string
324  {
325  if (is_string($component)) {
326  return $component;
327  }
328  return $this->container->ui()->renderer()->render($component);
329  }
330 
334  public function resetBox(DateTimeImmutable $reset_date, array $buttons = []): Component
335  {
336  $reset_date = new ilDateTime($reset_date->getTimeStamp(), IL_CAL_UNIX);
337  return $this->ui->create()
338  ->messageBox()
339  ->info(sprintf($this->ui->txt('last_reset_date'), ilDatePresentation::formatDate($reset_date)))
340  ->withButtons($buttons);
341  }
342 
343  public function resetButton(string $confirm_reset_link): Button
344  {
345  return $this->ui->create()->button()->standard(
346  $this->ui->txt('reset_for_all_users'),
347  $confirm_reset_link
348  );
349  }
350 
355  public function documentForm(Closure $link, string $title, Closure $document_content, bool $may_be_new): Form
356  {
357  $edit_link = $link('editDocument');
358  $content_title = $may_be_new ? 'form_document' : 'form_document_new';
359 
360  $section = $this->ui->create()->input()->field()->section([
361  'title' => $this->ui->create()->input()->field()->text($this->ui->txt('title'))->withRequired(true)->withValue($title),
362  'content' => $this->ui->create()->input()->field()->file(new UploadHandler($link, $document_content, $this->ui->txt(...)), $this->ui->txt($content_title))->withAcceptedMimeTypes([
363  'text/html',
364  'text/plain',
365  ])->withRequired($may_be_new),
366  ], $this->ui->txt($may_be_new ? 'form_new_doc_head' : 'form_edit_doc_head'));
367 
368  return $this->ui->create()->input()->container()->form()->standard($edit_link, [$section]);
369  }
370 
375  public function saveDocumentOrder(array $documents, array $order_by_document): void
376  {
377  $update = $this->config->legalDocuments()->document()->repository()->updateDocumentOrder(...);
378 
379  usort($documents, fn($document, $other) => $order_by_document[$document->id()] - $order_by_document[$other->id()]);
380 
381  array_map(
382  fn($document, int $order) => $update(new NumberId($document), $order),
383  $documents,
384  range(10, 10 * count($documents), 10)
385  );
386  }
387 
394  public function withDocumentsAndOrder(Closure $proc)
395  {
396  // kindlyTo->int() does not accept numbers of the form "01".
397  $to_int = $this->container->refinery()->byTrying([
398  $this->container->refinery()->kindlyTo()->int(),
399  $this->container->refinery()->in()->series([
400  $this->container->refinery()->to()->string(),
401  $this->container->refinery()->custom()->transformation(fn($s) => ltrim($s, '0') ?: '0'),
402  $this->container->refinery()->kindlyTo()->int(),
403  ]),
404  ]);
405 
406  $order = $this->container->http()->request()->getParsedBody()['order'] ?? null;
407  if (!is_array($order)) {
408  throw new InvalidArgumentException('Invalid order given. List of numbers expected.');
409  }
410 
411  $order = array_map($to_int, $order);
412  $document_ids = array_map($to_int, array_keys($order));
413  $order = array_combine($document_ids, array_values($order));
414 
415  $documents = $this->config->legalDocuments()->document()->repository()->all();
416 
417  foreach ($documents as $document) {
418  if (!isset($order[$document->id()])) {
419  $order[$document->id()] = $document->meta()->sorting();
420  }
421  }
422 
423  return $proc($documents, $order);
424  }
425 
426  public function exitWithJsonResponse($value): void
427  {
428  // ... The content type cannot be set to application/json, because the components/ILIAS/UI/src/templates/js/Input/Field/file.js:392
429  // does not expect that the content type is correct and parses it again ...
430  $this->container->http()->saveResponse($this->container->http()->response()/* ->withHeader('Content-Type', 'application/json') */->withBody(
431  Streams::ofString(json_encode($value))
432  ));
433 
434  $this->container->http()->sendResponse();
435  $this->container->http()->close();
436  }
437 
438  public function requireEditable(): void
439  {
440  if (!$this->config->editable()) {
441  $this->container['ilErr']->raiseError($this->container->language()->txt('permission_denied'), $this->container['ilErr']->WARNING);
442  }
443  }
444 
445  public function externalSettingsMessage(bool $enabled): Component
446  {
447  $message_box = $this->ui->create()->messageBox()->info(
448  $this->ui->txt('withdrawal_usr_deletion') . ': ' . $this->ui->txt($enabled ? 'enabled' : 'disabled')
449  );
450 
451  if (!$this->canWriteUserAdministration()) {
452  return $message_box;
453  }
454 
455  return $message_box->withLinks([
456  $this->ui->create()->link()->standard(
457  $this->ui->txt('adm_external_setting_edit'),
458  $this->willLinkWith(ilObjUserFolderGUI::class, ['ref_id' => (string) USER_FOLDER_ID])('generalSettings')
459  )
460  ]);
461  }
462 
463  public function isInvalidHTML(string $string): bool
464  {
465  return !$this->isValidHTML($string);
466  }
467 
468  public function isValidHTML(string $string): bool
469  {
470  return (new ValidHTML())->isTrue($string);
471  }
472 
473  public function canReadUserAdministration(): bool
474  {
475  return $this->container->rbac()->system()->checkAccess('read', USER_FOLDER_ID);
476  }
477 
478  private function canWriteUserAdministration(): bool
479  {
480  return $this->container->rbac()->system()->checkAccess('write', USER_FOLDER_ID);
481  }
482 
483  private function addTab(string $id, string $text, string $link, bool $can_access = true): void
484  {
485  if ($can_access) {
486  $this->container->tabs()->addTab($id, $text, $link);
487  }
488  }
489 }
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ilObjUser $user=null,)
This describes commonalities between all forms.
Definition: Form.php:32
confirmation()
description: > Example for rendering a confirmation message box.
const USER_FOLDER_ID
Definition: constants.php:33
setVariable(string $variable, $component)
criterionForm(string $url, Document $document, ?CriterionContent $criterion=null)
deleteDocumentsConfirmation(string $form_link, string $submit_command, string $cancel_command, array $documents)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
targetWithDoc(object $gui, Document $document, string $cmd, string $method='getLinkTarget')
withFormData(Form $form, Closure $then)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
tabs(array $tabs, array $run_after=[])
$url
Definition: shib_logout.php:63
const IL_CAL_UNIX
withRequest(ServerRequestInterface $request)
Get a form like this where data from the request is attached.
Customizing of pimple-DIC for ILIAS.
Definition: Container.php:35
$container
Definition: wac.php:13
find(Closure $predicate, array $array)
A
$text
Definition: xapiexit.php:21
idOrHash(object $gui, Closure $then)
A result encapsulates a value or an error and simplifies the handling of those.
Definition: Ok.php:16
saveDocumentOrder(array $documents, array $order_by_document)
__construct(private readonly Config $config, private readonly Container $container, private readonly UI $ui, ?Closure $confirmation=null)
resetBox(DateTimeImmutable $reset_date, array $buttons=[])
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:59
static ofString(string $string)
Creates a new stream with an initial value.
Definition: Streams.php:41
targetWithDocAndCriterion(object $gui, Document $document, Criterion $criterion, string $cmd, string $method='getLinkTarget')
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:24
addTab(string $id, string $text, string $link, bool $can_access=true)
getData()
Get the data in the form if all inputs are ok, where the transformation is applied if one was added...
documentForm(Closure $link, string $title, Closure $document_content, bool $may_be_new)
willLinkWith($gui, array $parameters=[])
resetButton(string $confirm_reset_link)
addDocumentButton(string $add_document_link)
$r