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