19declare(strict_types=1);
23use ILIAS\User\RedirectOnMissingWrite;
46use Psr\Http\Message\ServerRequestInterface;
50 use RedirectOnMissingWrite;
72 private readonly \
ilCtrl $ctrl,
77 private readonly UIFactory $ui_factory,
78 private readonly UIRenderer $ui_renderer,
80 private readonly ServerRequestInterface $request,
83 private readonly HttpService
$http,
84 private readonly array $available_change_listeners,
87 $this->available_fields = $this->
repository->get();
91 ILIAS_HTTP_PATH .
'/' . $this->
ctrl->getLinkTargetByClass(
92 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
93 self::CMD_PERFORM_TABLE_ACTION
102 [
'profile',
'fields'],
110 $this->redirectOnMissingWrite($this->
access, $this->
ctrl, $this->tpl, $this->
lng);
111 $cmd = $this->
ctrl->getCmd() .
'Cmd';
115 public function showCmd(?RoundTripModal $modal =
null): void
117 if (!$this->
repository->hasMigrationBeenRun()) {
118 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'missing_migration'));
124 $this->ui_factory->button()->standard(
125 $this->lng->txt(
'add_user_defined_field'),
126 $create_modal->getShowSignal()
134 if ($modal !==
null) {
138 $this->tpl->setContent(
139 $this->ui_renderer->render($content)
145 $action = $this->request_wrapper->retrieve(
146 $this->action_token->getName(),
147 $this->refinery->kindlyTo()->string()
149 $this->
http->saveResponse(
150 $this->
http->response()->withBody(
152 $this->ui_renderer->renderAsync(
153 $this->buildActionModal($action)
158 $this->
http->sendResponse();
159 $this->
http->close();
167 $modal = $this->
buildEditModal($field)->withRequest($this->request);
168 $data = $modal->getData();
169 if (
$data ===
null) {
170 $this->
showCmd($modal->withOnLoad($modal->getShowSignal()));
175 if ($listeners_to_notify !== []) {
181 $this->
ctrl->redirectByClass(
182 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
190 $data = $modal->getData();
191 if (
$data ===
null) {
192 $this->
showCmd($modal->withOnLoad($modal->getShowSignal()));
197 $this->
repository->getUnspecifiedCustomField(),
201 if ($listeners_to_notify !== []) {
207 $this->
ctrl->redirectByClass(
208 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
225 )->withRequest($this->request)->getData();
227 if (
$data ===
null ||
$data[
'field']->isRequired() && !
$data[
'field']->isVisibleInRegistration()) {
234 'components/ILIAS/User',
235 'onUserFieldAttributesChanged',
236 $field->getChangedAttributes(
$data[
'field'])
243 $identifier = $this->post_wrapper->retrieve(
244 'interruptive_items',
246 $this->refinery->kindlyTo()->listOf(
247 $this->refinery->kindlyTo()->string()
249 $this->refinery->always(
null)
252 if ($identifier ===
null) {
256 $this->
repository->getByIdentifier($identifier[0])
258 $this->available_fields = $this->
repository->get();
259 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'udf_field_deleted'),
true);
260 $this->
ctrl->redirectByClass(
261 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
268 array $visible_column_ids,
271 mixed $additional_viewcontrol_data,
273 mixed $additional_parameters
276 foreach ($this->available_fields as $field) {
277 yield $field->getTableRow(
287 mixed $additional_viewcontrol_data,
289 mixed $additional_parameters
291 return count($this->available_fields);
296 return $this->ui_factory->table()->data(
298 $this->
lng->txt(
'profile_fields'),
302 )->withRequest($this->request);
307 $cf = $this->ui_factory->table()->column();
308 $icon_checked = $this->ui_factory->symbol()->icon()
309 ->custom(
'assets/images/standard/icon_checked.svg',
'',
'small');
310 $icon_unchecked = $this->ui_factory->symbol()->icon()
311 ->custom(
'assets/images/standard/icon_unchecked.svg',
'',
'small');
313 'field' => $cf->text($this->
lng->txt(
'user_field'))->withIsSortable(
true),
314 'type' => $cf->text($this->
lng->txt(
'type'))
315 ->withIsOptional(
true,
true)
316 ->withIsSortable(
true),
317 'section' => $cf->text($this->
lng->txt(
'profile_section'))
318 ->withIsOptional(
true,
false)
319 ->withIsSortable(
true),
320 'access' => $cf->text($this->
lng->txt(
'access'))->withIsSortable(
false),
321 'required' => $cf->boolean(
323 PropertyAttributes::Required->value
327 )->withIsSortable(
true),
328 'export' => $cf->boolean(
330 PropertyAttributes::Export->value
334 )->withIsSortable(
true),
335 'searchable' => $cf->boolean(
337 PropertyAttributes::Searchable->value
341 )->withIsSortable(
true),
342 'available_in_certificates' => $cf->boolean(
344 PropertyAttributes::AvailableInCertificates->value
348 )->withIsSortable(
true)
355 self::ACTION_EDIT => $this->ui_factory->table()->action()->single(
356 $this->
lng->txt(
'edit_field'),
357 $this->url_builder->withParameter(
361 $this->field_id_token
363 self::ACTION_DELETE => $this->ui_factory->table()->action()->single(
364 $this->
lng->txt(
'delete'),
365 $this->url_builder->withParameter(
369 $this->field_id_token
376 $order_array = $order->
get();
377 $key = array_key_first($order_array);
378 $factor = array_shift($order_array) ===
'ASC' ? 1 : -1;
379 if ($key ===
'field') {
381 $this->available_fields,
383 $factor * ($this->
lng->txt($v1->
getLabel($this->lng)) <=> $this->lng->txt($v2->
getLabel($this->lng)))
388 if ($key ===
'type') {
390 $this->available_fields,
392 $factor * ($this->
lng->txt($v1->
isCustom() ?
'custom' :
'default') <=> $this->lng->txt($v2->
isCustom() ?
'custom' :
'default'))
397 if ($key ===
'section') {
399 $this->available_fields,
406 if ($key ===
'export') {
408 $this->available_fields,
415 if ($key ===
'required') {
417 $this->available_fields,
424 if ($key ===
'searchable') {
426 $this->available_fields,
433 if ($key ===
'available_in_certificates') {
435 $this->available_fields,
447 $this->retrieveIdentifierFromQuery()
449 return match ($action) {
450 self::ACTION_EDIT => $this->buildEditModal($field),
451 self::ACTION_DELETE => $this->buildDeleteConfirmationModal($field),
452 default => $this->ui_factory->messageBox()->failure(
453 $this->
lng->txt(
'msg_cancel')
461 $identifier = $this->retrieveIdentifierFromQuery();
462 $this->
ctrl->setParameterByClass(self::class, $this->field_id_token->getName(), $identifier);
463 return $this->ui_factory->modal()->roundtrip(
464 "{$this->lng->txt('edit_field')}: {$field->getLabel($this->lng)}",
468 $this->ui_factory->input()->field(),
470 $this->repository->getCustomFieldTypes(),
472 $this->available_fields,
476 $this->ctrl->getFormActionByClass(
477 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
485 return $this->ui_factory->modal()->roundtrip(
486 $this->
lng->txt(
'add_user_defined_field'),
488 $this->repository->getUnspecifiedCustomField()->getCreateCustomFieldForm(
490 $this->ui_factory->input()->field(),
492 $this->repository->getCustomFieldTypes(),
494 $this->available_fields,
498 $this->ctrl->getFormActionByClass(
499 [\ilAdministrationGUI::class, \ilObjUserFolderGUI::class, self::class],
506 array $listeners_to_notify,
509 $this->setChangedAttributesParameter($listeners_to_notify);
510 $modal = $this->buildChangeListenerConfirmationModal(
511 $listeners_to_notify,
514 $this->showCmd($modal->withOnLoad($modal->getShowSignal()));
518 array $listeners_to_notify,
522 $this->
lng->txt(
'usr_field_change_components_listening'),
524 $this->ui_renderer->render(
525 $this->buildListingOfListeners($listeners_to_notify, $field->
getLabel($this->
lng))
528 $field->getHiddenForm(
530 $this->ui_factory->input()->field(),
534 $this->available_fields,
535 static fn(
Field $v): bool => $v->isCustom()
538 $this->
ctrl->getFormActionByClass(
540 self::CMD_SAVE_AFTER_LISTENER_CONFIRMATION
547 ): InterruptiveModal {
549 $this->
lng->txt(
'confirm'),
550 $this->
lng->txt(
'udf_delete_sure'),
551 $this->
ctrl->getFormActionByClass(
555 )->withAffectedItems([
557 $field->getIdentifier(),
565 $identifier = $this->request_wrapper->retrieve(
566 $this->field_id_token->getName(),
567 $this->refinery->byTrying([
568 $this->refinery->kindlyTo()->string(),
569 $this->refinery->kindlyTo()->listOf(
570 $this->refinery->kindlyTo()->string()
575 if (is_array($identifier)) {
576 return $identifier[0];
582 array $listeners_to_notify,
584 ): DescriptiveListing {
587 $listeners_to_notify,
589 $c[$v->getComponentName()] = $v->getDescriptionForField(
592 $this->
lng->txt($v->isInterestedInAttribute()->value)
606 $this->available_change_listeners,
609 string $listener_class
610 ) use ($old_field, $new_field): array {
611 $listener = new $listener_class();
612 $field_definition_class = $listener->isInterestedInField();
614 if ($old_field->
getIdentifier() === (
new $field_definition_class())->getIdentifier()
635 $this->available_change_listeners,
638 string $listener_class
639 ) use ($field, $attributes): array {
640 $listener = new $listener_class();
641 if ($field->
getIdentifier() === $this->repository->getByClass(
642 $listener->isInterestedInField()
644 && in_array($listener->isInterestedInAttribute(), $attributes)) {
656 $this->
ctrl->setParameterByClass(
658 self::CHANGED_ATTRIBUTES_PARAMETER,
671 if (!$this->request_wrapper->has(self::CHANGED_ATTRIBUTES_PARAMETER)) {
675 return $this->request_wrapper->retrieve(
676 self::CHANGED_ATTRIBUTES_PARAMETER,
677 $this->
refinery->custom()->transformation(
678 fn(
string $v): array => array_reduce(
680 static function (array
$c,
string $v): array {
681 $a = PropertyAttributes::tryFrom($v);
695 $this->
repository->storeConfiguration($field);
696 $this->available_fields = $this->
repository->get();
698 $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()
getRows(DataRowBuilder $row_builder, array $visible_column_ids, Range $range, Order $order, mixed $additional_viewcontrol_data, mixed $filter_data, mixed $additional_parameters)
This is called by the table to retrieve rows; map data-records to rows using the $row_builder e....
readonly URLBuilder $url_builder
setChangedAttributesParameter(array $listeners_to_notify)
getListenersToNotifyByChangedValues(Field $old_field, Field $new_field)
buildChangeListenerConfirmationModal(array $listeners_to_notify, Field $field)
const string CMD_PERFORM_TABLE_ACTION
readonly URLBuilderToken $action_token
saveAfterListenerConfirmationCmd()
const string CMD_SAVE_AFTER_LISTENER_CONFIRMATION
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)
__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
getTotalRowCount(mixed $additional_viewcontrol_data, mixed $filter_data, mixed $additional_parameters)
Mainly for the purpose of pagination-support, it is important to know about the total number of recor...
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 ilAdministrationGUI.
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