19declare(strict_types=1);
23use ILIAS\User\RedirectOnMissingWrite;
46use Psr\Http\Message\ServerRequestInterface;
50 use RedirectOnMissingWrite;
65 private readonly \
ilCtrl $ctrl,
70 private readonly UIFactory $ui_factory,
71 private readonly UIRenderer $ui_renderer,
73 private readonly ServerRequestInterface $request,
76 private readonly HttpService
$http,
77 private readonly array $available_change_listeners,
80 $this->available_fields = $this->
repository->get();
84 ILIAS_HTTP_PATH .
'/' . $this->
ctrl->getLinkTargetByClass(
85 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
95 [
'profile',
'fields'],
103 $this->redirectOnMissingWrite($this->
access, $this->
ctrl, $this->tpl, $this->
lng);
104 $cmd = $this->
ctrl->getCmd() .
'Cmd';
108 public function showCmd(?RoundTripModal $modal =
null): void
110 if (!$this->
repository->hasMigrationBeenRun()) {
111 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'missing_migration'));
117 $this->ui_factory->button()->standard(
118 $this->lng->txt(
'add_user_defined_field'),
119 $create_modal->getShowSignal()
127 if ($modal !==
null) {
131 $this->tpl->setContent(
132 $this->ui_renderer->render($content)
138 $action = $this->request_wrapper->retrieve(
139 $this->action_token->getName(),
140 $this->refinery->kindlyTo()->string()
142 $this->
http->saveResponse(
143 $this->
http->response()->withBody(
145 $this->ui_renderer->renderAsync(
146 $this->buildActionModal($action)
151 $this->
http->sendResponse();
152 $this->
http->close();
160 $modal = $this->
buildEditModal($field)->withRequest($this->request);
161 $data = $modal->getData();
162 if (
$data ===
null) {
163 $this->
showCmd($modal->withOnLoad($modal->getShowSignal()));
168 if ($listeners_to_notify !== []) {
174 $this->
ctrl->redirectByClass(
175 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
183 $data = $modal->getData();
184 if (
$data ===
null) {
185 $this->
showCmd($modal->withOnLoad($modal->getShowSignal()));
190 $this->
repository->getUnspecifiedCustomField(),
194 if ($listeners_to_notify !== []) {
215 )->withRequest($this->request)->getData();
217 if (
$data ===
null ||
$data[
'field']->isRequired() && !
$data[
'field']->isVisibleInRegistration()) {
224 'components/ILIAS/User',
225 'onUserFieldAttributesChanged',
226 $field->getChangedAttributes(
$data[
'field'])
233 $identifier = $this->post_wrapper->retrieve(
234 'interruptive_items',
236 $this->refinery->kindlyTo()->listOf(
237 $this->refinery->kindlyTo()->string()
239 $this->refinery->always(
null)
242 if ($identifier ===
null) {
246 $this->
repository->getByIdentifier($identifier[0])
248 $this->available_fields = $this->
repository->get();
249 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'udf_field_deleted'),
true);
255 array $visible_column_ids,
259 ?array $additional_parameters
262 foreach ($this->available_fields as $field) {
263 yield $field->getTableRow(
274 ?array $additional_parameters
276 return count($this->available_fields);
281 return $this->ui_factory->table()->data(
283 $this->
lng->txt(
'profile_fields'),
287 )->withRequest($this->request);
292 $cf = $this->ui_factory->table()->column();
294 'field' => $cf->text($this->
lng->txt(
'user_field'))->withIsSortable(
true),
295 'type' => $cf->text($this->
lng->txt(
'type'))
296 ->withIsOptional(
true,
true)
297 ->withIsSortable(
true),
298 'section' => $cf->text($this->
lng->txt(
'profile_section'))
299 ->withIsOptional(
true,
false)
300 ->withIsSortable(
true),
301 'access' => $cf->text($this->
lng->txt(
'access'))->withIsSortable(
false),
302 'required' => $cf->boolean(
304 PropertyAttributes::Required->value
306 $this->ui_factory->symbol()->glyph()->checked(),
307 $this->ui_factory->symbol()->glyph()->unchecked()
308 )->withIsSortable(
true),
309 'export' => $cf->boolean(
311 PropertyAttributes::Export->value
313 $this->ui_factory->symbol()->glyph()->checked(),
314 $this->ui_factory->symbol()->glyph()->unchecked()
315 )->withIsSortable(
true),
316 'searchable' => $cf->boolean(
318 PropertyAttributes::Searchable->value
320 $this->ui_factory->symbol()->glyph()->checked(),
321 $this->ui_factory->symbol()->glyph()->unchecked()
322 )->withIsSortable(
true),
323 'available_in_certificates' => $cf->boolean(
325 PropertyAttributes::AvailableInCertificates->value
327 $this->ui_factory->symbol()->glyph()->checked(),
328 $this->ui_factory->symbol()->glyph()->unchecked()
329 )->withIsSortable(
true)
336 self::ACTION_EDIT => $this->ui_factory->table()->action()->single(
337 $this->
lng->txt(
'edit_field'),
338 $this->url_builder->withParameter(
342 $this->field_id_token
344 self::ACTION_DELETE => $this->ui_factory->table()->action()->single(
345 $this->
lng->txt(
'delete'),
346 $this->url_builder->withParameter(
350 $this->field_id_token
357 $order_array = $order->
get();
358 $key = array_key_first($order_array);
359 $factor = array_shift($order_array) ===
'ASC' ? 1 : -1;
360 if ($key ===
'field') {
362 $this->available_fields,
364 $factor * ($this->
lng->txt($v1->
getLabel($this->lng)) <=> $this->lng->txt($v2->
getLabel($this->lng)))
369 if ($key ===
'type') {
371 $this->available_fields,
373 $factor * ($this->
lng->txt($v1->
isCustom() ?
'custom' :
'default') <=> $this->lng->txt($v2->
isCustom() ?
'custom' :
'default'))
378 if ($key ===
'section') {
380 $this->available_fields,
387 if ($key ===
'export') {
389 $this->available_fields,
396 if ($key ===
'required') {
398 $this->available_fields,
405 if ($key ===
'searchable') {
407 $this->available_fields,
414 if ($key ===
'available_in_certificates') {
416 $this->available_fields,
428 $this->retrieveIdentifierFromQuery()
430 return match ($action) {
431 self::ACTION_EDIT => $this->buildEditModal($field),
432 self::ACTION_DELETE => $this->buildDeleteConfirmationModal($field),
433 default => $this->ui_factory->messageBox()->failure(
434 $this->
lng->txt(
'msg_cancel')
442 $identifier = $this->retrieveIdentifierFromQuery();
443 $this->
ctrl->setParameterByClass(self::class, $this->field_id_token->getName(), $identifier);
444 return $this->ui_factory->modal()->roundtrip(
445 "{$this->lng->txt('edit_field')}: {$field->getLabel($this->lng)}",
449 $this->ui_factory->input()->field(),
451 $this->repository->getCustomFieldTypes(),
453 $this->available_fields,
457 $this->ctrl->getFormActionByClass(
458 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
466 return $this->ui_factory->modal()->roundtrip(
467 $this->
lng->txt(
'add_user_defined_field'),
469 $this->repository->getUnspecifiedCustomField()->getCreateCustomFieldForm(
471 $this->ui_factory->input()->field(),
473 $this->repository->getCustomFieldTypes(),
475 $this->available_fields,
479 $this->ctrl->getFormActionByClass(
480 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
487 array $listeners_to_notify,
490 $this->setChangedAttributesParameter($listeners_to_notify);
491 $modal = $this->buildChangeListenerConfirmationModal(
492 $listeners_to_notify,
495 $this->showCmd($modal->withOnLoad($modal->getShowSignal()));
499 array $listeners_to_notify,
503 $this->
lng->txt(
'usr_field_change_components_listening'),
505 $this->ui_renderer->render(
506 $this->buildListingOfListeners($listeners_to_notify, $field->
getLabel($this->
lng))
509 $field->getHiddenForm(
511 $this->ui_factory->input()->field(),
515 $this->available_fields,
516 static fn(
Field $v): bool => $v->isCustom()
519 $this->
ctrl->getFormActionByClass(
521 'saveAfterListenerConfirmation'
528 ): InterruptiveModal {
530 $this->
lng->txt(
'confirm'),
531 $this->
lng->txt(
'udf_delete_sure'),
532 $this->
ctrl->getFormActionByClass(
536 )->withAffectedItems([
538 $field->getIdentifier(),
546 $identifier = $this->request_wrapper->retrieve(
547 $this->field_id_token->getName(),
548 $this->refinery->byTrying([
549 $this->refinery->kindlyTo()->string(),
550 $this->refinery->kindlyTo()->listOf(
551 $this->refinery->kindlyTo()->string()
556 if (is_array($identifier)) {
557 return $identifier[0];
563 array $listeners_to_notify,
565 ): DescriptiveListing {
568 $listeners_to_notify,
570 $c[$v->getComponentName()] = $v->getDescriptionForField(
573 $this->
lng->txt($v->isInterestedInAttribute()->value)
587 $this->available_change_listeners,
590 string $listener_class
591 ) use ($old_field, $new_field): array {
592 $listener = new $listener_class();
593 $field_definition_class = $listener->isInterestedInField();
595 if ($old_field->
getIdentifier() === (
new $field_definition_class())->getIdentifier()
616 $this->available_change_listeners,
619 string $listener_class
620 ) use ($field, $attributes): array {
621 $listener = new $listener_class();
622 if ($field->
getIdentifier() === $this->repository->getByClass(
623 $listener->isInterestedInField()
625 && in_array($listener->isInterestedInAttribute(), $attributes)) {
637 $this->
ctrl->setParameterByClass(
639 self::CHANGED_ATTRIBUTES_PARAMETER,
652 if (!$this->request_wrapper->has(self::CHANGED_ATTRIBUTES_PARAMETER)) {
656 return $this->request_wrapper->retrieve(
657 self::CHANGED_ATTRIBUTES_PARAMETER,
658 $this->
refinery->custom()->transformation(
659 fn(
string $v): array => array_reduce(
661 static function (array
$c,
string $v): array {
662 $a = PropertyAttributes::tryFrom($v);
676 $this->
repository->storeConfiguration($field);
677 $this->available_fields = $this->
repository->get();
679 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'usr_settings_saved'),
true);
Builds a Color from either hex- or rgb values.
Both the subject and the direction need to be specified when expressing an order.
A simple class to express a naive range of whole positive numbers.
The scope of this class is split ilias-conform URI's into components.
Stream factory which enables the user to create streams without the knowledge of the concrete class.
static ofString(string $string)
Creates a new stream with an initial value.
acquireParameters(array $namespace, string ... $names)
retrieveChangedAttributesFromQuery()
readonly URLBuilder $url_builder
setChangedAttributesParameter(array $listeners_to_notify)
getListenersToNotifyByChangedValues(Field $old_field, Field $new_field)
getRows(DataRowBuilder $row_builder, array $visible_column_ids, Range $range, Order $order, ?array $filter_data, ?array $additional_parameters)
This is called by the table to retrieve rows; map data-records to rows using the $row_builder e....
buildChangeListenerConfirmationModal(array $listeners_to_notify, Field $field)
readonly URLBuilderToken $action_token
saveAfterListenerConfirmationCmd()
showCmd(?RoundTripModal $modal=null)
getListenersToNotifyByInterests(Field $field, array $attributes)
showChangeListenerConfirmationModal(array $listeners_to_notify, Field $new)
const string ACTION_DELETE
buildDeleteConfirmationModal(Field $field)
buildListingOfListeners(array $listeners_to_notify, string $field_name)
getTotalRowCount(?array $filter_data, ?array $additional_parameters)
Mainly for the purpose of pagination-support, it is important to know about the total number of recor...
__construct(private readonly Language $lng, private readonly \ilCtrl $ctrl, private readonly \ilAppEventHandler $event, private readonly \ilAccess $access, private readonly \ilToolbarGUI $toolbar, private readonly \ilGlobalTemplateInterface $tpl, private readonly UIFactory $ui_factory, private readonly UIRenderer $ui_renderer, private readonly Refinery $refinery, private readonly ServerRequestInterface $request, private readonly RequestWrapper $request_wrapper, private readonly RequestWrapper $post_wrapper, private readonly HttpService $http, private readonly array $available_change_listeners, private readonly ConfigurationRepository $repository)
buildEditModal(Field $field)
readonly URLBuilderToken $field_id_token
retrieveIdentifierFromQuery()
buildActionModal(?string $action)
const string CHANGED_ATTRIBUTES_PARAMETER
retrieveValueByPropertyAttribute(PropertyAttributes $attribute)
getEditForm(Language $lng, FieldFactory $ff, Refinery $refinery, array $custom_field_types, array $available_custom_fields)
isAvailableInCertificates()
Class ilAccessHandler Checks access for ILIAS objects.
Class ilAdministratioGUI.
Class ilCtrl provides processing control methods.
static _reset()
Reset all.
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Interface RequestWrapper.
This describes commonalities between the different modals.
This describes a Data Table.
An entity that renders components to a string output.
isInterestedInAttribute()
static http()
Fetches the global http state from ILIAS.
modal(string $title="", string $cancel_label="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples