ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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 ) {
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);
70 (new DataFactory())->uri($uri)
71 );
72
73 list(
74 $this->url_builder,
75 $this->action_parameter_token,
76 $this->row_id_token
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
231 private function buildResetConfirmationModal(): InterruptiveModal
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(),
254 $this->refinery,
255 $this->mark_schema
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}
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)
showMarkSchema(?RoundTripModal $add_mark_modal=null)
exitOnSchemaError(MarkSchema|string $checked_value)
__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)
A class defining mark schemas for assessment test objects.
Definition: MarkSchema.php:36
A class defining marks for assessment test objects.
Definition: Mark.php:36
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
$messages
Definition: xapiexit.php:21
$param
Definition: xapitoken.php:46