ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilLegalDocumentsAdministrationGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
40 
42 {
43  private readonly Container $container;
44  private readonly UI $ui;
45  private readonly Administration $admin;
46 
47  public function __construct(
48  private readonly string $parent_class,
49  private readonly Config $config,
50  private readonly Closure $after_document_deletion,
51  ?Container $container = null
52  ) {
53  $this->container = $container ?? $GLOBALS['DIC'];
54  $this->container->language()->loadLanguageModule('ldoc');
55  $this->ui = new UI(
56  $this->config->legalDocuments()->id(),
57  $this->container->ui(),
58  $this->container->language()
59  );
60  $this->admin = new Administration($this->config, $this->container, $this->ui);
61  }
62 
63  public function executeCommand(): void
64  {
65  $cmd = $this->container->ctrl()->getCmd('documents');
66  if (!$this->isCommand($cmd)) {
67  throw new Exception('Unknown command: ' . $cmd);
68  }
69  $this->$cmd();
70  }
71 
72  public function history(): void
73  {
74  if (!$this->admin->canReadUserAdministration()) {
75  $this->container['ilErr']->raiseError($this->container->language()->txt('permission_denied'), $this->container['ilErr']->WARNING);
76  }
77  $this->container->tabs()->activateTab('history');
78  $this->admin->setContent($this->config->legalDocuments()->history()->table(
79  $this,
80  'history',
81  'historyResetFilter',
82  'searchUser'
83  ));
84  }
85 
86  public function searchUser(): void
87  {
88  $auto = new ilUserAutoComplete();
89  $auto->setSearchFields(['login', 'firstname', 'lastname', 'email']);
90  $auto->enableFieldSearchableCheck(false);
91  $auto->setMoreLinkAvailable(true);
92 
93  if ($this->container->http()->wrapper()->query()->has('fetchall')) {
94  $auto->setLimit(ilUserAutoComplete::MAX_ENTRIES);
95  }
96 
97  if ($this->container->http()->wrapper()->query()->has('term')) {
98  $query = ilUtil::stripSlashes(
99  $this->container->http()->wrapper()->query()->retrieve('term', $this->container->refinery()->kindlyTo()->string())
100  );
101  $response = $this->container->http()
102  ->response()
103  ->withHeader(ResponseHeader::CONTENT_TYPE, 'application/json')
104  ->withBody(Streams::ofString($auto->getList($query)));
105  $this->container->http()->saveResponse($response);
106  }
107 
108  $this->container->http()->sendResponse();
109  $this->container->http()->close();
110  }
111 
112  public function historyResetFilter(): void
113  {
114  $this->history();
115  }
116 
117  public function addDocument(): void
118  {
119  $this->admin->requireEditable();
120  $this->ctrlTo('setParameterByClass', 'hash', $this->config->legalDocuments()->document()->hash());
121  $this->ctrlTo('redirectByClass', 'editDocument');
122  }
123 
124  public function addCriterion(): void
125  {
126  $this->admin->requireEditable();
127  $this->container->tabs()->clearTargets();
128  $this->container->tabs()->setBackTarget($this->container->language()->txt('back'), $this->ctrlTo('getLinkTargetByClass', 'documents'));
129 
130  $document = $this->admin->currentDocument()->value();
131 
132  $this->container->language()->loadLanguageModule('meta');
133 
134  $url = $this->admin->targetWithDoc($this, $document, 'addCriterion', 'getFormAction');
135  $form = $this->admin->criterionForm($url, $document);
136 
137  $form = $this->admin->withFormData($form, function (array $x) use ($document) {
138  $content = new CriterionContent(...$x[0]['content']);
139  $this->returnWithResult($this->config->legalDocuments()->document()->validateCriteriaContent($document->criteria(), $content)->map(
140  fn() => $this->config->legalDocuments()->document()->repository()->createCriterion($document, $content)
141  ), 'doc_crit_attached', 'documents');
142  });
143 
144  $this->admin->setContent($form);
145  }
146 
147  public function editCriterion(): void
148  {
149  $this->admin->requireEditable();
150  $this->admin->withDocumentAndCriterion(function (Document $document, Criterion $criterion) {
151  $this->container->language()->loadLanguageModule('meta');
152  $url = $this->admin->targetWithDocAndCriterion($this, $document, $criterion, 'editCriterion', 'getFormAction');
153  $form = $this->admin->criterionForm($url, $document, $criterion->content());
154  $form = $this->admin->withFormData($form, function (array $data) use ($document, $criterion) {
155  $content = new CriterionContent(...$data[0]['content']);
156  $criteria = array_filter($document->criteria(), fn(Criterion $other) => $other->id() !== $criterion->id());
157  $this->returnWithResult($this->config->legalDocuments()->document()->validateCriteriaContent($criteria, $content)->map(
158  fn() => $this->config->legalDocuments()->document()->repository()->updateCriterionContent($criterion->id(), $content)
159  ), 'doc_crit_changed', 'documents');
160  });
161 
162  $this->container->tabs()->clearTargets();
163  $this->container->tabs()->setBackTarget($this->container->language()->txt('back'), $this->ctrlTo('getLinkTargetByClass', 'documents'));
164  $condition = $this->config->legalDocuments()->document()->toCondition($criterion->content());
165  $this->container->ui()->mainTemplate()->setTitle(join(' - ', [$document->content()->title(), $condition->definition()->translatedType()]));
166  $this->admin->setContent($form);
167  });
168  }
169 
170  public function deleteCriterion(): void
171  {
172  $this->admin->requireEditable();
173  $this->admin->withDocumentAndCriterion(function (Document $document, Criterion $criterion) {
174  $this->config->legalDocuments()->document()->repository()->deleteCriterion($criterion->id());
175  $this->returnWithMessage('doc_crit_detached', 'documents');
176  });
177  }
178 
179  public function upload(): void
180  {
181  $this->admin->requireEditable();
182  $this->admin->idOrHash($this, function (Closure $link, string $title, DocumentId $id) {
183  $raw_content = $this->admin->uploadContent();
184  $sanitised_value = trim((new HTMLPurifier())->purify($raw_content));
185  if ($this->admin->isInvalidHTML($sanitised_value)) {
186  $sanitised_value = nl2br($sanitised_value);
187  }
188 
189  $this->config->legalDocuments()->document()->repository()->updateDocumentContent($id, new DocumentContent('html', $title, $sanitised_value));
190  $this->admin->exitWithJsonResponse(['status' => 1]);
191  });
192  }
193 
194  public function documents(): void
195  {
196  $this->container->language()->loadLanguageModule('meta');
197  $this->container->tabs()->activateTab('documents');
198 
199  if ($this->config->editable()) {
200  $this->container->toolbar()->addStickyItem($this->admin->addDocumentButton($this->ctrlTo('getLinkTargetByClass', 'addDocument')));
201  }
202 
203  $edit_links = $this->config->editable() ? new AdministrationEditLinks($this, $this->admin) : null;
204  $this->admin->setContent($this->config->legalDocuments()->document()->table($this, __FUNCTION__, $edit_links));
205  }
206 
207  public function deleteDocuments(): void
208  {
209  $documents = $this->admin->retrieveDocuments();
210  if ($documents === []) {
211  $this->ui->mainTemplate()->setOnScreenMessage('failure', $this->ui->txt('select_at_least_one_object'), true);
212  $this->ctrlTo('redirectByClass', 'documents');
213  }
214  $this->deleteDocumentsConfirmation($documents);
215  }
216 
217  public function deleteDocument(): void
218  {
219  $this->deleteDocumentsConfirmation([$this->admin->currentDocument()->value()]);
220  }
221 
222  public function deleteConfirmed(): void
223  {
224  $this->admin->requireEditable();
225  $docs = $this->admin->retrieveDocuments();
226  $this->admin->deleteDocuments($docs);
227  ($this->after_document_deletion)();
228  $this->returnWithMessage(count($docs) === 1 ? 'deleted_documents_s' : 'deleted_documents_p', 'documents');
229  }
230 
231  public function editDocument(): void
232  {
233  $this->admin->requireEditable();
234  $this->container->tabs()->clearTargets();
235  $this->admin->idOrHash($this, function (Closure $link, string $title, DocumentId $id, bool $may_be_new) {
236  $content = fn() => $this->config->legalDocuments()->document()->repository()->findId($id)->map(fn($d) => $d->content());
237  $form = $this->admin->documentForm($link, $title, $content, $may_be_new);
238  $form = $this->admin->withFormData($form, function ($data) use (/* $edit_link, */$id) {
239  $this->config->legalDocuments()->document()->repository()->updateDocumentTitle($id, $data[0]['title']);
240  $this->returnWithMessage('saved_successfully', 'documents');
241  });
242 
243  $this->container->tabs()->setBackTarget($this->container->language()->txt('back'), $this->ctrlTo('getLinkTargetByClass', 'documents'));
244  $this->container->tabs()->activateTab('documents');
245  $this->admin->setContent($form);
246  });
247  }
248 
249  public function saveOrder(): void
250  {
251  $this->admin->requireEditable();
252  try {
253  $this->admin->withDocumentsAndOrder($this->admin->saveDocumentOrder(...));
254  $this->returnWithMessage('saved_successfully', 'documents');
255  } catch (ConstraintViolationException) {
256  $this->ui->mainTemplate()->setOnScreenMessage('failure', $this->ui->txt('ldoc_order_invalid'), true);
257  $this->ctrlTo('redirectByClass', 'documents');
258  }
259 
260  }
261 
265  public function tabs(array $run_after = []): void
266  {
267  $this->admin->tabs([
268  $this->tab('documents', $this->ui->txt('agreement_documents_tab_label')),
269  $this->tab('history', $this->ui->txt('acceptance_history'), $this->admin->canReadUserAdministration()),
270  ], $run_after);
271  }
272 
273  private function tab(string $cmd, string $label, bool $can_access = true): array
274  {
275  return [$cmd, $label, $this->ctrlTo('getLinkTargetByClass', $cmd), $can_access];
276  }
277 
278  public function admin(): Administration
279  {
280  return $this->admin;
281  }
282 
283  private function ctrlTo(string $method, ...$args)
284  {
285  $path = [$this->parent_class, self::class];
286  if ($method === 'setParameterByClass') {
287  $path = self::class;
288  }
289  return $this->container->ctrl()->$method($path, ...$args);
290  }
291 
292  private function isCommand(string $cmd): bool
293  {
294  $reflection = new ReflectionClass($this);
295  return $reflection->hasMethod($cmd)
296  && $reflection->getMethod($cmd)->isPublic()
297  && (string) $reflection->getMethod($cmd)->getReturnType() === 'void'
298  && $reflection->getMethod($cmd)->getNumberOfParameters() === 0;
299  }
300 
304  private function deleteDocumentsConfirmation(array $documents): void
305  {
306  $this->admin->requireEditable();
307  $this->container->tabs()->activateTab('documents');
308  $this->admin->setContent($this->admin->deleteDocumentsConfirmation(
309  $this->ctrlTo('getFormActionByClass', 'ignored'),
310  'deleteConfirmed',
311  'documents',
312  $documents
313  ));
314  }
315 
319  private function criterionErrorMessage($error): string
320  {
321  if (!is_string($error)) {
322  throw $error;
323  }
324 
325  return match ($error) {
326  ProvideDocument::CRITERION_ALREADY_EXISTS => $this->ui->txt('criterion_assignment_must_be_unique'),
327  ProvideDocument::CRITERION_WOULD_NEVER_MATCH => $this->ui->txt('criterion_assignment_cannot_match'),
328  default => $error,
329  };
330  }
331 
332  private function returnWithMessage(string $message, string $command): void
333  {
334  $this->ui->mainTemplate()->setOnScreenMessage('success', $this->ui->txt($message), true);
335  $this->ctrlTo('redirectByClass', $command);
336  }
337 
338  private function returnWithResult(Result $result, string $success_message, string $target): void
339  {
340  if ($result->isOk()) {
341  $this->ui->mainTemplate()->setOnScreenMessage('success', $this->ui->txt($success_message), true);
342  } else {
343  $this->ui->mainTemplate()->setOnScreenMessage('failure', $this->criterionErrorMessage($result->error()), true);
344  }
345 
346  $this->ctrlTo('redirectByClass', $target);
347  }
348 }
tab(string $cmd, string $label, bool $can_access=true)
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
A result encapsulates a value or an error and simplifies the handling of those.
Definition: Result.php:14
$response
Definition: xapitoken.php:93
Customizing of pimple-DIC for ILIAS.
Definition: Container.php:35
$path
Definition: ltiservices.php:32
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
returnWithResult(Result $result, string $success_message, string $target)
$GLOBALS["DIC"]
Definition: wac.php:31
error()
Get the encapsulated error.
$url
Definition: ltiregstart.php:35
__construct(private readonly string $parent_class, private readonly Config $config, private readonly Closure $after_document_deletion, ?Container $container=null)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$message
Definition: xapiexit.php:32