ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.MarkSchemaGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
36 
42 {
43  private const DEFAULT_CMD = 'showMarkSchema';
45  private bool $editable;
49 
50  public function __construct(
51  private \ilObjTest $test,
52  private \ilObjUser $active_user,
53  private \ilLanguage $lng,
54  private \ilCtrlInterface $ctrl,
55  private \ilGlobalTemplateInterface $tpl,
56  private \ilToolbarGUI $toolbar,
57  private TestLogger $logger,
58  private RequestWrapper $post_wrapper,
60  private ResponseHandler $response_handler,
61  private Request $request,
62  private Refinery $refinery,
63  private UIFactory $ui_factory,
64  private UIRenderer $ui_renderer
65  ) {
66  $this->mark_schema = $test->getMarkSchema();
67  $this->editable = $test->marksEditable();
68  $uri = ILIAS_HTTP_PATH . '/' . $this->ctrl->getLinkTargetByClass([\ilRepositoryGUI::class, \ilObjTestGUI::class, self::class], self::DEFAULT_CMD);
69  $url_builder = new URLBuilder(
70  (new DataFactory())->uri($uri)
71  );
72 
73  list(
74  $this->url_builder,
75  $this->action_parameter_token,
76  $this->row_id_token
77  ) = $url_builder->acquireParameters(
78  ['marks', 'overview_table'],
79  'action', //this is the actions's parameter name
80  'step_id' //this is the parameter name to be used for row-ids
81  );
82  }
83 
84  public function executeCommand(): void
85  {
86  $cmd = $this->ctrl->getCmd(self::DEFAULT_CMD);
87  $this->$cmd();
88  }
89 
90  protected function showMarkSchema(?RoundTripModal $add_mark_modal = null): void
91  {
92  if (!$this->editable) {
93  $this->tpl->setOnScreenMessage('info', $this->lng->txt('cannot_edit_marks'));
94  }
95 
96  $this->runTableCommand();
97 
98  if ($add_mark_modal === null) {
99  $add_mark_modal = $this->buildMarkModal();
100  }
101 
102  $mark_schema_table = new MarkSchemaTable(
103  $this->mark_schema,
104  $this->editable,
105  $this->lng,
106  $this->url_builder,
107  $this->action_parameter_token,
108  $this->row_id_token,
109  $this->ui_factory
110  );
111 
112  $confirmation_modal = $this->buildResetConfirmationModal();
113 
114  $this->populateToolbar($confirmation_modal, $add_mark_modal);
115 
116  $this->tpl->setContent(
117  $this->ui_renderer->render([
118  $mark_schema_table->getTable()->withRequest($this->request),
119  $confirmation_modal,
120  $add_mark_modal
121  ])
122  );
123  }
124 
125  protected function saveMark(): void
126  {
128 
129  $modal = $this->buildMarkModal()->withRequest($this->request);
130  $data = $modal->getData();
131  if ($data === null) {
132  $this->showMarkSchema($modal->withOnLoad($modal->getShowSignal()));
133  return;
134  }
135 
136  $mark_steps = $this->mark_schema->getMarkSteps();
137  $mark_steps[$data['index']] = $data['mark'];
138  $new_schema = $this->checkSchemaForErrors($this->mark_schema->withMarkSteps($mark_steps));
139  if (is_string($new_schema)) {
140  $this->tpl->setOnScreenMessage('failure', $new_schema);
141  $this->showMarkSchema();
142  return;
143  }
144  $this->mark_schema = $new_schema;
145  $this->test->storeMarkSchema(
146  $this->mark_schema
147  );
148  $this->test->onMarkSchemaSaved();
149  $this->tpl->setOnScreenMessage('success', $this->lng->txt('saved_successfully'), true);
150 
151  if ($this->logger->isLoggingEnabled()) {
152  $this->logger->logTestAdministrationInteraction(
153  $this->logger->getInteractionFactory()->buildTestAdministrationInteraction(
154  $this->test->getRefId(),
155  $this->active_user->getId(),
156  TestAdministrationInteractionTypes::MARK_SCHEMA_MODIFIED,
157  $this->mark_schema->toLog($this->logger->getAdditionalInformationGenerator())
158  )
159  );
160  }
161 
162  $this->showMarkSchema();
163  }
164 
165  protected function resetToSimpleMarkSchema(): void
166  {
168 
169  $this->mark_schema = $this->mark_schema->createSimpleSchema(
170  $this->lng->txt('failed_short'),
171  $this->lng->txt('failed_official'),
172  0,
173  false,
174  $this->lng->txt('passed_short'),
175  $this->lng->txt('passed_official'),
176  50,
177  true
178  );
179  $this->test->storeMarkSchema($this->mark_schema);
180  if ($this->logger->isLoggingEnabled()) {
181  $this->logger->logTestAdministrationInteraction(
182  $this->logger->getInteractionFactory()->buildTestAdministrationInteraction(
183  $this->test->getRefId(),
184  $this->active_user->getId(),
185  TestAdministrationInteractionTypes::MARK_SCHEMA_RESET,
186  []
187  )
188  );
189  }
190  $this->showMarkSchema();
191  }
192 
193  protected function deleteMarkSteps(): void
194  {
196 
197  if (!$this->post_wrapper->has('interruptive_items')) {
198  $this->showMarkSchema();
199  return;
200  }
201 
202  $marks_to_be_deleted = $this->post_wrapper->retrieve(
203  'interruptive_items',
204  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int())
205  );
206 
207  $new_schema = $this->removeMarksAndCheckNewSchema($marks_to_be_deleted);
208  if (is_string($new_schema)) {
209  $this->tpl->setOnScreenMessage('failure', $new_schema);
210  $this->showMarkSchema();
211  return;
212  }
213 
214  $this->mark_schema = $new_schema;
215  $this->test->storeMarkSchema($new_schema);
216 
217  if ($this->logger->isLoggingEnabled()) {
218  $this->logger->logTestAdministrationInteraction(
219  $this->logger->getInteractionFactory()->buildTestAdministrationInteraction(
220  $this->test->getRefId(),
221  $this->active_user->getId(),
222  TestAdministrationInteractionTypes::MARK_SCHEMA_MODIFIED,
223  $this->mark_schema->toLog($this->logger->getAdditionalInformationGenerator())
224  )
225  );
226  }
227 
228  $this->showMarkSchema();
229  }
230 
232  {
233  return $this->ui_factory->modal()->interruptive(
234  $this->lng->txt('tst_mark_reset_to_simple_mark_schema'),
235  $this->lng->txt('tst_mark_reset_to_simple_mark_schema_confirmation'),
236  $this->ctrl->getFormActionByClass(MarkSchemaGUI::class, 'resetToSimpleMarkSchema')
237  )->withActionButtonLabel($this->lng->txt('tst_mark_reset_to_simple_mark_schema'));
238  }
239 
240  private function buildMarkModal(?Mark $mark = null, int $mark_index = -1): RoundTripModal
241  {
242  $title_lng_var = 'edit';
243  if ($mark === null) {
244  $title_lng_var = 'create';
245  $mark = new Mark();
246  }
247  return $this->ui_factory->modal()->roundtrip(
248  $this->lng->txt($title_lng_var),
249  [],
250  [
251  'mark' => $mark->toForm(
252  $this->lng,
253  $this->ui_factory->input()->field(),
256  ),
257  'index' => $this->ui_factory->input()->field()->hidden()
258  ->withValue($mark_index)
259  ],
260  $this->ctrl->getFormActionByClass(MarkSchemaGUI::class, 'saveMark')
261  );
262  }
263 
264  private function editMark(array $affected_marks): void
265  {
267 
268  $affected_mark = current($affected_marks);
269  $mark_steps = $this->mark_schema->getMarkSteps();
270  $this->response_handler->sendAsync(
271  $this->ui_renderer->renderAsync(
272  $this->buildMarkModal($mark_steps[$affected_mark], $affected_mark)
273  )
274  );
275  }
276 
277  private function populateToolbar(InterruptiveModal $confirmation_modal, RoundTripModal $add_mark_modal): void
278  {
279  if (!$this->editable) {
280  return;
281  }
282  $create_simple_schema_button = $this->ui_factory->button()->standard(
283  $this->lng->txt('tst_mark_reset_to_simple_mark_schema'),
284  $confirmation_modal->getShowSignal()
285  );
286  $this->toolbar->addComponent($create_simple_schema_button);
287 
288  $add_mark_button = $this->ui_factory->button()->standard(
289  $this->lng->txt('tst_mark_create_new_mark_step'),
290  $add_mark_modal->getShowSignal()
291  );
292  $this->toolbar->addComponent($add_mark_button);
293  }
294 
295  public function runTableCommand(): void
296  {
297  $action = $this->getTableActionQueryString();
298  if (!$this->editable || $action === null) {
299  return;
300  }
301 
302  $affected_marks = $this->getTableAffectedItemsFromQuery();
303  if ($affected_marks === null) {
304  $this->response_handler->sendAsync(
305  $this->ui_renderer->renderAsync(
306  $this->ui_factory->modal()->roundtrip(
307  $this->lng->txt('error'),
308  $this->ui_factory->messageBox()->failure($this->lng->txt('tst_delete_missing_mark'))
309  )
310  )
311  );
312  }
313 
314  switch ($action) {
316  $this->editMark($affected_marks);
317  break;
318 
320  $this->confirmMarkDeletion($affected_marks);
321  break;
322  }
323  }
324 
325  private function confirmMarkDeletion(array $marks_to_delete): void
326  {
328  $this->exitOnSchemaError($this->removeMarksAndCheckNewSchema($marks_to_delete));
329 
330  $confirm_delete_modal = $this->ui_factory->modal()->interruptive(
331  $this->lng->txt('confirm'),
332  $this->lng->txt('delete_mark_confirmation'),
333  $this->ctrl->getFormActionByClass(MarkSchemaGUI::class, 'deleteMarkSteps')
334  )->withActionButtonLabel($this->lng->txt('delete'))
335  ->withAffectedItems($this->buildInteruptiveItems($marks_to_delete));
336 
337  $this->response_handler->sendAsync(
338  $this->ui_renderer->renderAsync($confirm_delete_modal)
339  );
340  }
341 
342  private function buildInteruptiveItems(array $affected_marks): array
343  {
344  $mark_steps = $this->mark_schema->getMarkSteps();
345  $marks_to_be_deleted = [];
346  foreach ($affected_marks as $affected_mark) {
347  $marks_to_be_deleted[] = $this->ui_factory->modal()->interruptiveItem()->standard(
348  (string) $affected_mark,
349  $mark_steps[$affected_mark]->getOfficialName()
350  );
351  }
352  return $marks_to_be_deleted;
353  }
354 
355  private function getTableActionQueryString(): ?string
356  {
357  $param = $this->action_parameter_token->getName();
358  if (!$this->request_wrapper->has($param)) {
359  return null;
360  }
361  $trafo = $this->refinery->byTrying([
362  $this->refinery->kindlyTo()->null(),
363  $this->refinery->kindlyTo()->string()
364  ]);
365  return $this->request_wrapper->retrieve($param, $trafo);
366  }
367 
368  private function getTableAffectedItemsFromQuery(): ?array
369  {
370  $affected_marks = $this->request_wrapper->retrieve(
371  $this->row_id_token->getName(),
372  $this->refinery->byTrying([
373  $this->refinery->kindlyTo()->int(),
374  $this->refinery->container()->mapValues(
375  $this->refinery->kindlyTo()->int()
376  ),
377  $this->refinery->identity()
378  ])
379  );
380 
381  if (is_int($affected_marks)) {
382  $affected_marks = [$affected_marks];
383  }
384 
385  return $affected_marks;
386  }
387 
388  protected function redirectOnMarkSchemaNotEditable(): void
389  {
390  if ($this->editable) {
391  return;
392  }
393 
394  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('permission_denied'), true);
395  $this->ctrl->redirect($this, 'showMarkSchema');
396  }
397 
398  private function exitOnMarkSchemaNotEditable(): void
399  {
400  if ($this->editable) {
401  return;
402  }
403 
404  $this->response_handler->sendAsync(
405  $this->ui_renderer->renderAsync(
406  $this->ui_factory->modal()->roundtrip(
407  $this->lng->txt('error'),
408  $this->ui_factory->messageBox()->failure($this->lng->txt('permission_denied'))
409  )
410  )
411  );
412  exit;
413  }
414 
415  private function removeMarksAndCheckNewSchema(array $marks_to_delete): MarkSchema|String
416  {
417  $new_marks = $this->mark_schema->getMarkSteps();
418  foreach ($marks_to_delete as $mark) {
419  unset($new_marks[$mark]);
420  }
421 
422  return $this->checkSchemaForErrors(
423  $this->mark_schema->withMarkSteps(array_values($new_marks))
424  );
425  }
426 
427  private function exitOnSchemaError(MarkSchema|string $checked_value): MarkSchema
428  {
429  if (!is_string($checked_value)) {
430  return $checked_value;
431  }
432 
433  $this->response_handler->sendAsync(
434  $this->ui_renderer->render(
435  $this->ui_factory->modal()->roundtrip(
436  $this->lng->txt('error'),
437  $this->ui_factory->messageBox()->failure($checked_value)
438  )
439  )
440  );
441  }
442 
443  private function checkSchemaForErrors(MarkSchema $new_schema): MarkSchema|string
444  {
445  $messages = [];
446  if ($new_schema->checkForMissingPassed()) {
447  $messages[] = $this->lng->txt('no_passed_mark');
448  }
449  if ($new_schema->checkForMissingZeroPercentage()) {
450  $messages[] = $this->lng->txt('min_percentage_ne_0');
451  }
452  if ($new_schema->checkForFailedAfterPassed()) {
453  $messages[] = $this->lng->txt('no_passed_after_failed');
454  }
455 
456  if (isset($messages[1])) {
457  $messages[0] .= '<br>' . $messages[1];
458  }
459 
460  if ($messages === []) {
461  return $new_schema;
462  }
463 
464  return $messages[0];
465  }
466 }
A class defining mark schemas for assessment test objects.
Definition: MarkSchema.php:35
showMarkSchema(?RoundTripModal $add_mark_modal=null)
A class defining marks for assessment test objects.
Definition: Mark.php:35
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
acquireParameters(array $namespace, string ... $names)
Definition: URLBuilder.php:138
removeMarksAndCheckNewSchema(array $marks_to_delete)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
$messages
Definition: xapiexit.php:21
populateToolbar(InterruptiveModal $confirmation_modal, RoundTripModal $add_mark_modal)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$param
Definition: xapitoken.php:46
exit
global $lng
Definition: privfeed.php:31
__construct(private \ilObjTest $test, private \ilObjUser $active_user, private \ilLanguage $lng, private \ilCtrlInterface $ctrl, private \ilGlobalTemplateInterface $tpl, private \ilToolbarGUI $toolbar, private TestLogger $logger, private RequestWrapper $post_wrapper, private RequestWrapper $request_wrapper, private ResponseHandler $response_handler, private Request $request, private Refinery $refinery, private UIFactory $ui_factory, private UIRenderer $ui_renderer)
exitOnSchemaError(MarkSchema|string $checked_value)
URLBuilder.
Definition: URLBuilder.php:40
buildMarkModal(?Mark $mark=null, int $mark_index=-1)