ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
TextFeedbackOverviewTable.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
31use ILIAS\Data\Text\Factory as TextFactory;
33use ILIAS\Data\UUID\Factory as UuidFactory;
36use ILIAS\Refinery\Custom\Transformation as CustomTransformation;
37use ILIAS\Refinery\Factory as Refinery;
39use ILIAS\UI\Component\Modal\RoundTrip as RoundTripModal;
41use ILIAS\UI\Component\Table\Data as DataTable;
42use ILIAS\UI\Factory as UIFactory;
43
45{
46 private const string SUB_ACTION_ENTER_FEEDBACK = 'ef';
47 private const string SUB_ACTION_EDIT_FEEDBACK = 'edf';
48 private const string SUB_ACTION_CONFIRM_DELETE_FEEDBACK = 'cdf';
49 private const string SUB_ACTION_DELETE_FEEDBACK = 'df';
50 private const string SUB_ACTION_SAVE_FEEDBACK = 'sf';
51 private const string SUB_ACTION_ADD_LEGACY_TEXT = 'alt';
52
53 public function __construct(
54 private readonly UuidFactory $uuid_factory,
55 private readonly TextFactory $text_factory,
56 private readonly TextFeedbackOverviewDataRetrieval $data_retrieval
57 ) {
58
59 }
60
61 #[\Override]
62 public function getCreateModal(
63 Environment $environment
64 ): RoundTripModal {
65 $ui_factory = $environment->getUIFactory();
66 $lng = $environment->getLanguage();
67
68 return $ui_factory->modal()->roundtrip(
69 $lng->txt('create_feedback'),
70 null,
71 [
72 'gap' => $environment->getAnswerFormProperties()->getGaps()
73 ->buildGapsSelect(
74 $lng->txt('select_gap'),
75 $ui_factory->input()->field()
76 )->withAdditionalTransformation(
77 $environment->getRefinery()->custom()->transformation(
78 fn(string $v): Uuid => $this->uuid_factory->fromString($v)
79 )
80 )->withRequired(true)
81 ],
82 $environment->withSubActionParameter(
83 self::SUB_ACTION_ENTER_FEEDBACK
84 )->getUrlBuilder()->buildURI()->__toString()
85 )->withSubmitLabel($lng->txt('next'));
86 }
87
88 #[\Override]
89 public function getTable(
90 Environment $environment,
91 TextFeedback $feedback
92 ): DataTable {
93 return $environment->getUIFactory()->table()->data(
94 $this->data_retrieval,
95 '',
96 $this->getColumns(
97 $environment->getUIFactory()->table()->column(),
98 $environment->getLanguage()
99 )
100 )->withActions(
101 $this->getActions(
102 $environment
103 )
104 )->withRequest($environment->getHttpServices()->request());
105 }
106
107 #[\Override]
108 public function doAction(
109 Environment $environment,
110 TextFeedback $feedback,
111 string $action
112 ): Async|RoundTripModal|TextFeedback {
113 return match($action) {
114 self::SUB_ACTION_ENTER_FEEDBACK => $this->processSelectGapModal(
115 $environment,
116 $feedback
117 ),
118 self::SUB_ACTION_EDIT_FEEDBACK => $this->editFeedback(
119 $environment->withPreservedTableRowIdsParameter(),
120 $feedback
121 ),
122 self::SUB_ACTION_SAVE_FEEDBACK => $this->processEnterFeedbackModal(
123 $environment,
124 $feedback
125 ),
126 self::SUB_ACTION_CONFIRM_DELETE_FEEDBACK => $this->confirmDeleteFeedback(
127 $environment
128 ),
129 self::SUB_ACTION_DELETE_FEEDBACK => $this->deleteFeedback(
130 $environment,
131 $feedback
132 ),
133 self::SUB_ACTION_ADD_LEGACY_TEXT => $this->addLegacyFeedback(
134 $environment->withPreservedTableRowIdsParameter(),
135 $feedback
136 )
137 };
138 }
139
140 private function processSelectGapModal(
141 Environment $environment,
142 TextFeedback $feedback
143 ): RoundTripModal {
144 $create_modal = $this->getCreateModal($environment)
145 ->withRequest($environment->getHttpServices()->request());
146 $data = $create_modal->getData();
147 if ($data === null) {
148 return $create_modal;
149 }
150
151 $inputs_builder = $this->buildEnterFeedbackInputBuilder(
152 $environment,
153 $feedback,
154 $data['gap']
155 );
156
157 $enter_feedback_modal = $this->buildEnterFeedbackModal(
158 $environment,
159 $inputs_builder,
160 false
161 );
162
163 $inputs_builder
164 ->withCarry(
165 $data['gap']->toString()
166 )->persistCarry();
167
168 return $enter_feedback_modal;
169 }
170
171 private function buildEnterFeedbackModal(
172 Environment $environment,
173 InputsBuilderSession $inputs_builder,
174 bool $needs_legacy_text_info
175 ): RoundTripModal {
176 return $environment->getUIFactory()->modal()->roundtrip(
177 $environment->getLanguage()->txt('edit_feedback'),
178 $needs_legacy_text_info
179 ? [
180 $environment->getUIFactory()->messageBox()->info(
181 $environment->getLanguage()->txt('insert_legacy_texts_info')
182 )->withButtons([
183 $environment->getUIFactory()->button()->standard(
184 $environment->getLanguage()->txt('insert_legacy_texts'),
185 $environment->withSubActionParameter(
186 self::SUB_ACTION_ADD_LEGACY_TEXT
187 )->getUrlBuilder()->buildURI()->__toString()
188 )
189 ])
190 ]
191 : null,
192 [
193 'feedback' => $inputs_builder->getInputs()
194 ],
195 $environment->withSubActionParameter(
196 self::SUB_ACTION_SAVE_FEEDBACK
197 )->getUrlBuilder()->buildURI()->__toString()
198 );
199 }
200
202 Environment $environment,
203 TextFeedback $feedback
204 ): RoundTripModal|TextFeedback {
205 $specific_feedbacks = $this->getSpecifcFeedbacksFromQuery(
206 $environment
207 );
208
209 $gap_id = null;
210 if (isset($specific_feedbacks[0])) {
211 $gap_id = $specific_feedbacks[0]->getParentId();
212 $environment = $environment->withPreservedTableRowIdsParameter();
213 }
214
215 $inputs_builder = $this->buildEnterFeedbackInputBuilder(
216 $environment,
217 $feedback,
218 $gap_id,
219 array_map(
220 fn(SpecificTextFeedback $v): string => $v->getCondition(),
221 $specific_feedbacks
222 )
223 );
224
225 $modal = $this->buildEnterFeedbackModal(
226 $environment,
227 $inputs_builder,
228 isset($specific_feedbacks[0])
229 ? $specific_feedbacks[0]->displaysLegacyText()
230 : false
231 )->withRequest($environment->getHttpServices()->request());
232
233 $data = $modal->getData();
234 if ($data === null) {
235 $inputs_builder->persistCarry();
236 return $modal;
237 }
238
239 return $data['feedback'];
240 }
241
242 private function addLegacyFeedback(
243 Environment $environment,
244 TextFeedback $feedback
245 ): RoundTripModal {
246 $specific_feedbacks = $this->getSpecifcFeedbacksFromQuery(
247 $environment
248 );
249
250 return $this->buildEnterFeedbackModal(
251 $environment,
252 $this->buildEnterFeedbackInputBuilder(
253 $environment,
254 $feedback,
255 $specific_feedbacks[0]->getParentId(),
256 array_map(
257 fn(SpecificTextFeedback $v): string => $v->getCondition(),
258 $specific_feedbacks
259 ),
260 (new HtmlPurifier())->prepareAndPurify(
261 $specific_feedbacks[0]->getLegacyFeedbackText()
262 )
263 ),
264 false
265 );
266 }
267
268 private function editFeedback(
269 Environment $environment,
270 TextFeedback $feedback
271 ): Async {
272 $specific_feedbacks = $this->getSpecifcFeedbacksFromQuery(
273 $environment
274 );
275
276 return $environment->getPresentationFactory()->getAsync(
277 $this->buildEnterFeedbackModal(
278 $environment,
279 $this->buildEnterFeedbackInputBuilder(
280 $environment,
281 $feedback,
282 $specific_feedbacks[0]->getParentId(),
283 array_map(
284 fn(SpecificTextFeedback $v): string => $v->getCondition(),
285 $specific_feedbacks
286 ),
287 $specific_feedbacks[0]->getFeedbackText()?->getRawRepresentation() ?? ''
288 ),
289 $specific_feedbacks[0]->displaysLegacyText()
290 )
291 );
292 }
293
294 private function confirmDeleteFeedback(
295 Environment $environment
296 ): Async {
297 $pf = $environment->getPresentationFactory();
298 $uf = $environment->getUIFactory();
299 $lng = $environment->getLanguage();
300 $selected_feedbacks = $this->data_retrieval->getSpecificFeedbacksForRowId(
301 $environment->getTableRowIds()[0]
302 );
303
304 if ($selected_feedbacks === []) {
305 return $pf->getAsync(
306 $uf->messageBox()->failure(
307 $lng->txt('ui_field_option_filter_no_selection')
308 )
309 );
310 }
311
312 return $pf->getAsync(
313 $uf->modal()->interruptive(
314 $lng->txt('confirm'),
315 $lng->txt('confirm_delete_feedback'),
316 $environment
317 ->withSubActionParameter(self::SUB_ACTION_DELETE_FEEDBACK)
318 ->getUrlBuilder()
319 ->buildURI()
320 ->__toString()
321 )->withAffectedItems([
322 $uf->modal()->interruptiveItem()->standard(
323 $environment->getTableRowIds()[0],
324 $selected_feedbacks[0]->getFeedbackText()
325 ?->getRawRepresentation() ?? ''
326 )
327 ])
328 );
329 }
330
331 private function deleteFeedback(
332 Environment $environment,
333 TextFeedback $feedback
334 ): RoundTripModal|TextFeedback {
335 $uf = $environment->getUIFactory();
336 $lng = $environment->getLanguage();
337 $selected_feedbacks = $environment->getHttpServices()->wrapper()->post()
338 ->retrieve(
339 'interruptive_items',
340 $environment->getRefinery()->custom()->transformation(
341 fn(array $vs): array => $this->data_retrieval
342 ->getSpecificFeedbacksForRowId($vs[0])
343 )
344 );
345
346 if ($selected_feedbacks === []) {
347 return $uf->modal()->roundtrip(
348 $lng->txt('error'),
349 $uf->messageBox()->failure(
350 $lng->txt('ui_field_option_filter_no_selection')
351 )
352 );
353 }
354
355 return array_reduce(
356 $selected_feedbacks,
357 fn(TextFeedback $c, SpecificTextFeedback $v): TextFeedback => $c->withoutSpecificFeedback($v),
358 $feedback
359 );
360 }
361
363 Environment $environment,
364 TextFeedback $feedback,
365 ?Uuid $selected_gap = null,
366 array $selected_conditions = [],
367 string $feedback_text = ''
369 return $environment->getPresentationFactory()->getSessionBasedInputsBuilder(
370 $environment->getRefinery()->custom()->transformation(
371 function (
372 ?string $v
373 ) use (
374 $environment,
375 $feedback,
376 $selected_gap,
377 $selected_conditions,
378 $feedback_text
379 ): Section {
380 $gap_id = $selected_gap
381 ?? $this->uuid_factory->fromString($v);
382
383 return $this->buildSpecificFeedbackSection(
384 $environment->getUIFactory(),
385 $environment->getRefinery(),
386 $environment->getLanguage(),
387 $environment->getAnswerFormProperties()
388 ->getGaps()
389 ->getGapById($gap_id),
390 $environment->isMarkingRequired(),
391 $feedback->getSpecificFeedbacks(),
392 $selected_conditions,
393 $feedback_text
395 $this->buildSpecificFeedbackTransformation(
396 $environment->getRefinery(),
397 $feedback,
398 $environment->getAnswerFormId(),
399 $gap_id,
400 $selected_conditions
401 )
402 );
403 }
404 )
405 );
406 }
407
409 UIFactory $ui_factory,
412 Gap $gap,
413 bool $is_marking_required,
414 array $existing_specific_feedbacks,
415 array $selected_conditions,
416 string $feedback_text
417 ): Section {
418 $answer_options = $gap->getType()->getFeedbackSelectValues(
419 $gap,
420 $is_marking_required
421 );
422
423 foreach ($existing_specific_feedbacks as $feedback) {
424 if (!in_array($feedback->getCondition(), $selected_conditions)) {
425 unset($answer_options[$feedback->getCondition()]);
426 }
427 }
428
429 return $ui_factory->input()->field()->section(
430 [
431 'answer_options' => $ui_factory->input()->field()->multiSelect(
432 $lng->txt('answer_options'),
433 $answer_options
434 )->withHasOptionFilter(true)
435 ->withRequired(true)
436 ->withValue($selected_conditions),
437 'feedback' => $ui_factory->input()->field()->markdown(
439 $lng->txt('feedback')
440 )->withAdditionalTransformation(
441 $refinery->custom()->transformation(
442 fn(string $v): Markdown => $this->text_factory->markdown($v)
443 )
444 )->withRequired(true)
445 ->withValue($feedback_text)
446 ],
447 $lng->txt('feedback')
448 );
449 }
450
453 TextFeedback $feedback,
454 Uuid $answer_form_id,
455 Uuid $gap_id,
456 array $selected_conditions
457 ): CustomTransformation {
458 return $refinery->custom()->transformation(
459 function (
460 array $vs
461 ) use (
462 $feedback,
463 $answer_form_id,
464 $gap_id,
465 $selected_conditions
466 ): TextFeedback {
467 $feedback_with_removed_specific_feedbacks = array_reduce(
468 array_diff($selected_conditions, $vs['answer_options']),
469 fn(TextFeedback $c, string $v): TextFeedback => $c->withoutSpecificFeedback(
470 $c->getSpecificFeedbackForConditionOrNew(
471 $this->uuid_factory,
472 $answer_form_id,
473 $gap_id,
474 $v
475 )
476 ),
477 $feedback
478 );
479
480 return array_reduce(
481 $vs['answer_options'],
482 fn(TextFeedback $c, string $v): TextFeedback => $c->withSpecificFeedback(
483 $c->getSpecificFeedbackForConditionOrNew(
484 $this->uuid_factory,
485 $answer_form_id,
486 $gap_id,
487 $v
488 )->withFeedbackText($vs['feedback'])
489 ),
490 $feedback_with_removed_specific_feedbacks
491 );
492 }
493 );
494 }
495
497 Environment $environment
498 ): array {
499 $selected_table_row_ids = $environment->getTableRowIds();
500
501 if ($selected_table_row_ids === []) {
502 return [];
503 }
504
505 return $this->data_retrieval->getSpecificFeedbacksForRowId(
506 $selected_table_row_ids[0]
507 );
508 }
509
510 private function getColumns(
511 ColumnFactory $column_factory,
513 ): array {
514 return [
515 'gap' => $column_factory->text(
516 $lng->txt('gap')
517 )->withIsSortable(false),
518 'answer_options' => $column_factory->text(
519 $lng->txt('answer_options')
520 )->withIsSortable(false),
521 'feedback' => $column_factory->text(
522 $lng->txt('feedback')
523 )->withIsSortable(false)
524 ];
525 }
526
527 private function getActions(
528 Environment $environment
529 ): array {
530 $af = $environment->getUIFactory()->table()->action();
531 $lng = $environment->getLanguage();
532
533 return [
534 'edit' => $af->single(
535 $lng->txt('edit'),
536 $environment->withSubActionParameter(
537 self::SUB_ACTION_EDIT_FEEDBACK
538 )->getUrlBuilder(),
539 $environment->getTableRowIdToken()
540 )->withAsync(true),
541 'delete' => $af->single(
542 $lng->txt('delete'),
543 $environment->withSubActionParameter(
544 self::SUB_ACTION_CONFIRM_DELETE_FEEDBACK
545 )->getUrlBuilder(),
546 $environment->getTableRowIdToken()
547 )->withAsync(true),
548 ];
549 }
550}
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Builds data types.
Definition: Factory.php:36
buildEnterFeedbackInputBuilder(Environment $environment, TextFeedback $feedback, ?Uuid $selected_gap=null, array $selected_conditions=[], string $feedback_text='')
buildEnterFeedbackModal(Environment $environment, InputsBuilderSession $inputs_builder, bool $needs_legacy_text_info)
buildSpecificFeedbackTransformation(Refinery $refinery, TextFeedback $feedback, Uuid $answer_form_id, Uuid $gap_id, array $selected_conditions)
buildSpecificFeedbackSection(UIFactory $ui_factory, Refinery $refinery, Language $lng, Gap $gap, bool $is_marking_required, array $existing_specific_feedbacks, array $selected_conditions, string $feedback_text)
doAction(Environment $environment, TextFeedback $feedback, string $action)
__construct(private readonly UuidFactory $uuid_factory, private readonly TextFactory $text_factory, private readonly TextFeedbackOverviewDataRetrieval $data_retrieval)
Transform values according to custom configuration.
return['3gp', '7z', 'ai', 'aif', 'aifc', 'aiff', 'au', 'arw', 'avi', 'backup', 'bak', 'bas', 'bpmn', 'bpmn2', 'bmp', 'bib', 'bibtex', 'bz', 'bz2', 'c', 'c++', 'cc', 'cct', 'cdf', 'cer', 'class', 'cls', 'conf', 'cpp', 'crt', 'crs', 'crw', 'cr2', 'css', 'cst', 'csv', 'cur', 'db', 'dcr', 'des', 'dng', 'doc', 'docx', 'dot', 'dotx', 'dtd', 'dvi', 'el', 'eps', 'epub', 'f', 'f77', 'f90', 'flv', 'for', 'g3', 'gif', 'gl', 'gan', 'ggb', 'gsd', 'gsm', 'gtar', 'gz', 'gzip', 'h', 'hpp', 'htm', 'html', 'htmls', 'ibooks', 'ico', 'ics', 'ini', 'ipynb', 'java', 'jbf', 'jpeg', 'jpg', 'js', 'jsf', 'jso', 'json', 'latex', 'lang', 'less', 'log', 'lsp', 'ltx', 'm1v', 'm2a', 'm2v', 'm3u', 'm4a', 'm4v', 'markdown', 'm', 'mat', 'md', 'mdl', 'mdown', 'mid', 'min', 'midi', 'mobi', 'mod', 'mov', 'movie', 'mp2', 'mp3', 'mp4', 'mpa', 'mpeg', 'mpg', 'mph', 'mpga', 'mpp', 'mpt', 'mpv', 'mpx', 'mv', 'mw', 'mv4', 'nb', 'nbp', 'nef', 'nif', 'niff', 'obj', 'obm', 'odt', 'ods', 'odp', 'odg', 'odf', 'oga', 'ogg', 'ogv', 'old', 'p', 'pas', 'pbm', 'pcl', 'pct', 'pcx', 'pdf', 'pgm', 'pic', 'pict', 'png', 'por', 'pov', 'project', 'properties', 'ppa', 'ppm', 'pps', 'ppsx', 'ppt', 'pptx', 'ppz', 'ps', 'psd', 'pwz', 'qt', 'qtc', 'qti', 'qtif', 'r', 'ra', 'ram', 'rar', 'rast', 'rda', 'rev', 'rexx', 'ris', 'rf', 'rgb', 'rm', 'rmd', 'rmi', 'rmm', 'rmp', 'rt', 'rtf', 'rtx', 'rv', 's', 's3m', 'sav', 'sbs', 'sec', 'sdml', 'sgm', 'sgml', 'smi', 'smil', 'srt', 'sps', 'spv', 'stl', 'svg', 'swa', 'swf', 'swz', 'tar', 'tex', 'texi', 'texinfo', 'text', 'tgz', 'tif', 'tiff', 'ttf', 'txt', 'tmp', 'uvproj', 'vdf', 'vimeo', 'viv', 'vivo', 'vrml', 'vsdx', 'vtt', 'wav', 'webm', 'wmv', 'wmx', 'wmz', 'woff', 'wwd', 'xhtml', 'xif', 'xls', 'xlsx', 'xmind', 'xml', 'xsl', 'xsd', 'zip']
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAnswerFormId()
Returns the answer form id of the current context either from the answer form properties,...
This describes section inputs.
Definition: Section.php:29
withAdditionalTransformation(Transformation $trafo)
Apply a transformation to the content of the input.
This describes a Data Table.
Definition: Data.php:33
modal(string $title="", string $cancel_label="")
button(string $caption, string $cmd)
global $lng
Definition: privfeed.php:26
$data
Definition: storeScorm.php:45
getLanguage()