From 53d1aa8f3d1532d6e9757701c923005e97a64c9e Mon Sep 17 00:00:00 2001 From: Aleksandr Litvin Date: Mon, 2 Nov 2026 09:05:40 +0100 Subject: [PATCH 1/3] refactor edit fields table in metadata to KS --- .../classes/Field/Table/DataRetrieval.php | 131 ++++++++++ .../classes/Field/Table/TableBuilder.php | 79 ++++++ .../classes/class.ilAdvancedMDSettingsGUI.php | 236 ++++++++++++++---- 3 files changed, 394 insertions(+), 52 deletions(-) create mode 100644 components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php create mode 100644 components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php diff --git a/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php b/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php new file mode 100644 index 000000000000..5bef63981839 --- /dev/null +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php @@ -0,0 +1,131 @@ +record_id, + false, + $this->active_language + ); + + $res = []; + $counter = 0; + $ok_icon = $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_ok.svg', '', 'small'); + $not_ok_icon = $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_not_ok.svg', '', 'small'); + + foreach ($fields as $definition) { + $field_translations = ilAdvancedMDFieldTranslations::getInstanceByRecordId($definition->getRecordId()); + $id = $definition->getFieldId(); + $counter += 10; + + $properties = $definition->getFieldDefinitionForTableGUI($this->active_language); + $configuration = implode("\n", array_map( + static fn($key, $value): string => (string) $key . ": " . (string) $value . ";", + array_keys($properties), + $properties + )); + + $searchable_icon = $definition->isSearchable() ? $ok_icon : $not_ok_icon; + + $res[$id] = [ + 'id' => $id, + 'position' => $counter, + 'title' => $field_translations->getTitleForLanguage($id, $this->active_language), + 'description' => $field_translations->getDescriptionForLanguage($id, $this->active_language), + 'type' => $this->lng->txt($definition->getTypeTitle()), + 'configuration' => $configuration, + 'searchable' => $searchable_icon, + 'perm' => $this->permissions->hasPermissions( + ilAdvancedMDPermissionHelper::CONTEXT_FIELD, + (int) $id, + [ + ilAdvancedMDPermissionHelper::ACTION_FIELD_EDIT, + [ + ilAdvancedMDPermissionHelper::ACTION_FIELD_EDIT_PROPERTY, + ilAdvancedMDPermissionHelper::SUBACTION_FIELD_SEARCHABLE + ] + ] + ) + ]; + } + + return $res; + } + + public function getRows( + $row_builder, + array $visible_column_ids, + Range $range = null, + Order $order = null, + mixed $additional_viewcontrol_data = null, + mixed $filter_data = null, + mixed $additional_parameters = null + ): Generator { + $data = $this->getRawData(); + uasort($data, fn($a, $b) => $a['position'] <=> $b['position']); + + foreach ($data as $id => $datum) { + yield $row_builder->buildOrderingRow( + (string) $id, + $datum + )->withPosition((int) ($datum['position'] / 10)); + } + } + + public function getTotalRowCount( + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): ?int { + return count($this->getRawData()); + } + + public function getAllIDs(): array + { + return array_map('strval', array_keys($this->getRawData())); + } + + /** + * @return string[] + */ + public function resolveIDs(array|string $ids): array + { + if ($ids === ['ALL_OBJECTS'] || $ids === 'ALL_OBJECTS') { + return $this->getAllIDs(); + } + if (is_array($ids)) { + return array_values(array_filter($ids, 'is_string')); + } + if (is_string($ids)) { + return [$ids]; + } + return []; + } +} diff --git a/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php b/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php new file mode 100644 index 000000000000..3b97cdad4cf2 --- /dev/null +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php @@ -0,0 +1,79 @@ +ui_factory->table()->column()->text( + $this->lng->txt('title') + )->withIsSortable(true); + $columns[self::TYPE_COLUMN] = $this->ui_factory->table()->column()->text( + $this->lng->txt('type') + ); + $columns[self::CONFIGURATION_COLUMN] = $this->ui_factory->table()->column()->text( + $this->lng->txt('configuration') + ); + $columns[self::SEARCHABLE_COLUMN] = $this->ui_factory->table()->column()->statusIcon( + $this->lng->txt('md_adv_searchable') + ); + + $actions = []; + $actions[self::EDIT_FIELD_ACTION] = $this->ui_factory->table()->action()->single( + $this->lng->txt('edit'), + $url_builder->withParameter($action_token, self::EDIT_FIELD_ACTION), + $id_token + ); + + if ($has_write_access) { + $actions[self::DELETE_ACTION] = $this->ui_factory->table()->action()->multi( + $this->lng->txt('delete'), + $url_builder->withParameter($action_token, self::DELETE_ACTION), + $id_token + ); + } + + $target = $url_builder->withParameter($action_token, self::SAVE_ACTION)->buildURI(); + return $this->ui_factory->table()->ordering( + $this->data_retrieval, + $target, + $this->lng->txt('md_adv_field_table'), + $columns + )->withActions($actions) + ->withRequest($this->http->request()); + } +} diff --git a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php index 20b4df7c6d8d..9f77510a3e50 100755 --- a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php +++ b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php @@ -24,6 +24,12 @@ use ILIAS\UI\Renderer; use Psr\Http\Message\RequestInterface; use ILIAS\HTTP\GlobalHttpState; +use ILIAS\UI\URLBuilder; +use ILIAS\UI\URLBuilderToken; +use ILIAS\Data\Factory as DataFactory; +use AdvancedMetadata\Field\Table\TableBuilder; +use AdvancedMetadata\Field\Table\DataRetrieval; +use ILIAS\UI\Component\Table\Ordering; /** * @author Stefan Meyer @@ -57,6 +63,7 @@ class ilAdvancedMDSettingsGUI protected ilTabsGUI $tabs_gui; protected UIFactory $ui_factory; protected Renderer $ui_renderer; + protected DataFactory $data_factory; protected ilToolbarGUI $toolbar; protected ilLogger $logger; protected ilObjUser $user; @@ -92,6 +99,7 @@ public function __construct(int $a_context, int $a_ref_id, ?string $a_obj_type = $this->toolbar = $DIC->toolbar(); $this->ui_factory = $DIC->ui()->factory(); $this->ui_renderer = $DIC->ui()->renderer(); + $this->data_factory = new DataFactory(); $this->request = $DIC->http()->request(); $this->http = $DIC->http(); $this->db = $DIC->database(); @@ -113,8 +121,15 @@ public function __construct(int $a_context, int $a_ref_id, ?string $a_obj_type = $this->permissions = ilAdvancedMDPermissionHelper::getInstance($DIC->user()->getId(), $this->ref_id); } + protected array $requested_record_ids = []; + protected array $requested_field_ids = []; + protected function getRecordIdFromQuery(): ?int { + if (count($this->requested_record_ids) === 1) { + return (int) $this->requested_record_ids[0]; + } + if ($this->http->wrapper()->query()->has('record_id')) { return $this->http->wrapper()->query()->retrieve( 'record_id', @@ -126,6 +141,10 @@ protected function getRecordIdFromQuery(): ?int protected function getRecordIdsFromPost(): SplFixedArray { + if (count($this->requested_record_ids) > 0) { + return SplFixedArray::fromArray($this->requested_record_ids); + } + if ($this->http->wrapper()->post()->has('record_id')) { return SplFixedArray::fromArray( $this->http->wrapper()->post()->retrieve( @@ -141,6 +160,10 @@ protected function getRecordIdsFromPost(): SplFixedArray protected function getFieldIdFromQuery(): ?int { + if (count($this->requested_field_ids) === 1) { + return (int) $this->requested_field_ids[0]; + } + if ($this->http->wrapper()->query()->has('field_id')) { return $this->http->wrapper()->query()->retrieve( 'field_id', @@ -152,6 +175,10 @@ protected function getFieldIdFromQuery(): ?int protected function getFieldIdsFromPost(): SplFixedArray { + if (count($this->requested_field_ids) > 0) { + return SplFixedArray::fromArray($this->requested_field_ids); + } + if ($this->http->wrapper()->post()->has('field_id')) { return SplFixedArray::fromArray( $this->http->wrapper()->post()->retrieve( @@ -267,7 +294,7 @@ public function executeCommand(): void $next_class = $this->ctrl->getNextClass($this); $cmd = $this->ctrl->getCmd(); switch ($next_class) { - case strtolower(ilAdvancedMDRecordTranslationGUI::class): + case "iladvancedmdrecordtranslationgui": $record = $this->initRecordObject(); $this->setRecordSubTabs(1, true); $int_gui = new \ilAdvancedMDRecordTranslationGUI($record); @@ -282,6 +309,12 @@ public function executeCommand(): void $GLOBALS['DIC']->ctrl()->forwardCommand($this->form); break; + case "iladvancedmdsettingsgui": + if ($cmd === 'handleFieldTableAction') { + $this->handleFieldTableAction(); + break; + } + // no break default: if (!$cmd) { $cmd = 'showRecords'; @@ -306,7 +339,7 @@ public function showRecords(): void if ($perm[ilAdvancedMDPermissionHelper::ACTION_MD_CREATE_RECORD]) { $button = $this->ui_factory->button()->standard( $this->lng->txt('add'), - $this->ctrl->getLinkTargetByClass(strtolower(self::class), "createRecord") + $this->ctrl->getLinkTargetByClass("iladvancedmdsettingsgui", "createRecord") ); $this->toolbar->addComponent($button); @@ -318,7 +351,7 @@ public function showRecords(): void if ($perm[ilAdvancedMDPermissionHelper::ACTION_MD_IMPORT_RECORDS]) { $button = $this->ui_factory->button()->standard( $this->lng->txt('import'), - $this->ctrl->getLinkTargetByClass(strtolower(self::class), "importRecords") + $this->ctrl->getLinkTargetByClass("iladvancedmdsettingsgui", "importRecords") ); $this->toolbar->addComponent($button); } @@ -876,6 +909,123 @@ public function editRecord(?ilPropertyFormGUI $form = null): void $this->tpl->setContent($this->form->getHTML()); } + protected function getDataRetrieval(int $record_id): DataRetrieval + { + return new DataRetrieval( + $record_id, + $this->active_language, + $this->getPermissions(), + $this->lng, + $this->ui_factory, + $this->data_factory, + $this->refinery + ); + } + + protected function getFieldTable(int $record_id): Ordering + { + $url_params = $this->getFieldTableActionURLBuilder(); + return new TableBuilder( + $this->getDataRetrieval($record_id), + $this->lng, + $this->ui_factory, + $this->http, + $this->data_factory + )->get( + $url_params[0], + $url_params[1], + $url_params[2], + has_write_access: $this->access->checkAccess('write', '', $this->ref_id) + ); + } + + /** + * @return array{0: URLBuilder, 1: URLBuilderToken, 2: URLBuilderToken} + */ + protected function getFieldTableActionURLBuilder(): array + { + $link = ILIAS_HTTP_PATH . '/' . $this->ctrl->getLinkTarget( + $this, + 'handleFieldTableAction' + ); + $url_builder = new URLBuilder($this->data_factory->uri($link)); + $record_id = (int) $this->getRecordIdFromQuery(); + if ($record_id) { + list($url_builder, $record_id_token) = $url_builder->acquireParameter(['advmd_field'], 'record_id', (string) $record_id); + } + return $url_builder->acquireParameters(['advmd_field'], 'field_ids', 'field_action'); + } + + protected function handleFieldTableAction(): void + { + $record_id = (int) $this->getRecordIdFromQuery(); + if ($record_id) { + $this->ctrl->saveParameter($this, 'record_id'); + } + + list($url_builder, $id_token, $action_token) = $this->getFieldTableActionURLBuilder(); + + if (!$this->http->wrapper()->query()->has($action_token->getName())) { + $this->ctrl->redirect($this, 'editFields'); + return; + } + + $action = $this->http->wrapper()->query()->retrieve( + $action_token->getName(), + $this->refinery->kindlyTo()->string() + ); + + $retrieval = $this->getDataRetrieval($record_id); + $ids = $this->getIdsFromQuery( + $id_token->getName(), + $retrieval + ); + + $this->requested_field_ids = $ids; + switch ($action) { + case 'editField': + if (count($ids) === 1) { + $this->requested_field_ids = []; + $this->ctrl->setParameter($this, 'field_id', $ids[0]); + $this->ctrl->redirect($this, 'editField'); + } + $this->ctrl->redirect($this, 'editFields'); + break; + case 'updateFields': + $this->updateFields(); + break; + case 'confirmDeleteFields': + $this->confirmDeleteFields(); + break; + } + } + + protected function getIdsFromQuery(string $name, DataRetrieval $retrieval): array + { + if (!$this->http->wrapper()->query()->has($name)) { + return []; + } + + $raw_ids = $this->http->wrapper()->query()->retrieve( + $name, + $this->refinery->identity() + ); + + if ($raw_ids === 'ALL_OBJECTS' || $raw_ids === ['ALL_OBJECTS']) { + return array_map('intval', $retrieval->getAllIDs()); + } + + if (is_array($raw_ids)) { + return array_map('intval', array_filter($raw_ids, fn($id) => is_string($id) && $id !== '')); + } + + if (is_string($raw_ids) && $raw_ids !== '') { + return [(int) $raw_ids]; + } + + return []; + } + protected function editFields(): void { $record_id = $this->getRecordIdFromQuery(); @@ -907,7 +1057,7 @@ protected function editFields(): void $this->ctrl->setParameter($this, 'ftype', $type); $create_link = $this->ctrl->getLinkTarget($this, 'createField'); - $this->ctrl->clearParameterByClass(strtolower(self::class), 'ftype'); + $this->ctrl->clearParameterByClass("iladvancedmdsettingsgui", 'ftype'); $field_buttons[] = $this->ui_factory->button()->shy( $this->lng->txt($field->getTypeTitle()), @@ -934,30 +1084,20 @@ protected function editFields(): void $this->tpl->setOnScreenMessage('info', sprintf($this->lng->txt("md_adv_field_filter_warning"), implode(", ", $filter_warn))); } - // show field table - $fields = ilAdvancedMDFieldDefinition::getInstancesByRecordId( - $this->record->getRecordId(), - false, - $this->active_language - ); + $table = $this->getFieldTable((int) $this->record->getRecordId()); - $table_gui = new ilAdvancedMDFieldTableGUI( - $this, - 'editFields', - $this->getPermissions(), - $perm[ilAdvancedMDPermissionHelper::ACTION_RECORD_FIELD_POSITIONS], - $this->record->getDefaultLanguage() + $cancel_button = $this->ui_factory->button()->standard( + $this->lng->txt('cancel'), + $this->ctrl->getLinkTarget($this, "showRecords") ); - $table_gui->setTitle($this->lng->txt("md_adv_field_table")); - $table_gui->parseDefinitions($fields); - if (sizeof($fields)) { - $table_gui->addCommandButton("updateFields", $this->lng->txt("save")); - } - $table_gui->addCommandButton("showRecords", $this->lng->txt('cancel')); - $table_gui->addMultiCommand("confirmDeleteFields", $this->lng->txt("delete")); - $table_gui->setSelectAllCheckbox("field_id"); - $this->tpl->setContent($table_gui->getHTML()); + $this->tpl->setContent( + $this->ui_renderer->render([ + $table, + $this->ui_factory->divider()->horizontal(), + $cancel_button + ]) + ); } /** @@ -967,45 +1107,37 @@ protected function editFields(): void public function updateFields(): void { $this->ctrl->saveParameter($this, 'record_id'); - $positions = $this->getPositionsFromPost(); - asort($positions, SORT_NUMERIC); - $record_id = $this->getRecordIdFromQuery(); + $record_id = (int) $this->getRecordIdFromQuery(); if (!$record_id) { $this->tpl->setOnScreenMessage('failure', $this->lng->txt('select_one')); $this->editFields(); return; } + $table = $this->getFieldTable($record_id); + $ordered_ids = $table->getData(); $fields = ilAdvancedMDFieldDefinition::getInstancesByRecordId($record_id); - if ($this->getPermissions()->hasPermission( - ilAdvancedMDPermissionHelper::CONTEXT_RECORD, - $record_id, - ilAdvancedMDPermissionHelper::ACTION_RECORD_FIELD_POSITIONS - )) { - $positions_flipped = array_flip(array_keys($positions)); - foreach ($fields as $field) { - $field->setPosition((int) $positions_flipped[$field->getFieldId()]); - $field->update(); - } - } - - foreach ($fields as $field) { - if ($this->getPermissions()->hasPermission( - ilAdvancedMDPermissionHelper::CONTEXT_FIELD, - (int) $field->getFieldId(), - ilAdvancedMDPermissionHelper::ACTION_FIELD_EDIT_PROPERTY, - ilAdvancedMDPermissionHelper::SUBACTION_FIELD_SEARCHABLE - )) { - $post_searchable = (array) ($this->http->request()->getParsedBody()['searchable'] ?? []); - $field->setSearchable((bool) ($post_searchable[$field->getFieldId()] ?? false)); - $field->update(); + $i = 1; + foreach ($ordered_ids as $field_id) { + $field_id = (int) $field_id; + if (isset($fields[$field_id])) { + $field = $fields[$field_id]; + + if ($this->getPermissions()->hasPermission( + ilAdvancedMDPermissionHelper::CONTEXT_RECORD, + $record_id, + ilAdvancedMDPermissionHelper::ACTION_RECORD_FIELD_POSITIONS + )) { + $field->setPosition($i++); + $field->update(); + } } } - $language = $this->request->getQueryParams()['mdlang'] ?? false; + $language = $this->http->request()->getQueryParams()['mdlang'] ?? false; if ($language) { - $this->ctrl->setParameter($this, 'mdlang', $this->request->getQueryParams()['mdlang']); + $this->ctrl->setParameter($this, 'mdlang', $language); } $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true); $this->ctrl->redirect($this, "editFields"); From e53b8b092af9f5678dda77800eaeb796f3e27cf3 Mon Sep 17 00:00:00 2001 From: Aleksandr Litvin Date: Fri, 6 Nov 2026 19:34:22 +0100 Subject: [PATCH 2/3] adjust refactoring of edit fields table in metadata --- .../classes/Field/Table/DataRetrieval.php | 88 ++++++++---------- .../classes/Field/Table/TableBuilder.php | 21 ++++- .../classes/class.ilAdvancedMDSettingsGUI.php | 93 ++++++------------- 3 files changed, 88 insertions(+), 114 deletions(-) diff --git a/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php b/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php index 5bef63981839..ce5931041b12 100644 --- a/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php @@ -1,34 +1,53 @@ raw_data)) { + return $this->raw_data; + } + $fields = ilAdvancedMDFieldDefinition::getInstancesByRecordId( $this->record_id, false, @@ -36,27 +55,24 @@ public function getRawData(): array ); $res = []; - $counter = 0; $ok_icon = $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_ok.svg', '', 'small'); $not_ok_icon = $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_not_ok.svg', '', 'small'); foreach ($fields as $definition) { $field_translations = ilAdvancedMDFieldTranslations::getInstanceByRecordId($definition->getRecordId()); $id = $definition->getFieldId(); - $counter += 10; $properties = $definition->getFieldDefinitionForTableGUI($this->active_language); - $configuration = implode("\n", array_map( - static fn($key, $value): string => (string) $key . ": " . (string) $value . ";", - array_keys($properties), - $properties - )); + $configuration_items = []; + foreach ($properties as $key => $value) { + $configuration_items[] = (string) $key . ": " . (string) $value; + } + $configuration = $this->ui_factory->listing()->unordered($configuration_items); $searchable_icon = $definition->isSearchable() ? $ok_icon : $not_ok_icon; $res[$id] = [ - 'id' => $id, - 'position' => $counter, + 'position' => $definition->getPosition(), 'title' => $field_translations->getTitleForLanguage($id, $this->active_language), 'description' => $field_translations->getDescriptionForLanguage($id, $this->active_language), 'type' => $this->lng->txt($definition->getTypeTitle()), @@ -76,26 +92,19 @@ public function getRawData(): array ]; } - return $res; + $this->raw_data = $res; + return $this->raw_data; } public function getRows( - $row_builder, - array $visible_column_ids, - Range $range = null, - Order $order = null, - mixed $additional_viewcontrol_data = null, - mixed $filter_data = null, - mixed $additional_parameters = null + OrderingRowBuilder $row_builder, + array $visible_column_ids ): Generator { - $data = $this->getRawData(); - uasort($data, fn($a, $b) => $a['position'] <=> $b['position']); - - foreach ($data as $id => $datum) { + foreach ($this->getRawData() as $id => $datum) { yield $row_builder->buildOrderingRow( (string) $id, $datum - )->withPosition((int) ($datum['position'] / 10)); + ); } } @@ -109,23 +118,6 @@ public function getTotalRowCount( public function getAllIDs(): array { - return array_map('strval', array_keys($this->getRawData())); - } - - /** - * @return string[] - */ - public function resolveIDs(array|string $ids): array - { - if ($ids === ['ALL_OBJECTS'] || $ids === 'ALL_OBJECTS') { - return $this->getAllIDs(); - } - if (is_array($ids)) { - return array_values(array_filter($ids, 'is_string')); - } - if (is_string($ids)) { - return [$ids]; - } - return []; + return array_keys($this->getRawData()); } } diff --git a/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php b/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php index 3b97cdad4cf2..03e4f6f355de 100644 --- a/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php @@ -1,5 +1,21 @@ ui_factory->table()->column()->text( $this->lng->txt('type') ); - $columns[self::CONFIGURATION_COLUMN] = $this->ui_factory->table()->column()->text( + $columns[self::CONFIGURATION_COLUMN] = $this->ui_factory->table()->column()->listing( $this->lng->txt('configuration') ); $columns[self::SEARCHABLE_COLUMN] = $this->ui_factory->table()->column()->statusIcon( diff --git a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php index 9f77510a3e50..47cafd84c254 100755 --- a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php +++ b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php @@ -27,9 +27,9 @@ use ILIAS\UI\URLBuilder; use ILIAS\UI\URLBuilderToken; use ILIAS\Data\Factory as DataFactory; -use AdvancedMetadata\Field\Table\TableBuilder; -use AdvancedMetadata\Field\Table\DataRetrieval; -use ILIAS\UI\Component\Table\Ordering; +use AdvancedMetadata\Field\Table\TableBuilder as EditFieldsTableBuilder; +use AdvancedMetadata\Field\Table\DataRetrieval as EditFieldsDataRetrieval; +use ILIAS\UI\Component\Table\Ordering as OrderingTable; /** * @author Stefan Meyer @@ -121,15 +121,8 @@ public function __construct(int $a_context, int $a_ref_id, ?string $a_obj_type = $this->permissions = ilAdvancedMDPermissionHelper::getInstance($DIC->user()->getId(), $this->ref_id); } - protected array $requested_record_ids = []; - protected array $requested_field_ids = []; - protected function getRecordIdFromQuery(): ?int { - if (count($this->requested_record_ids) === 1) { - return (int) $this->requested_record_ids[0]; - } - if ($this->http->wrapper()->query()->has('record_id')) { return $this->http->wrapper()->query()->retrieve( 'record_id', @@ -141,10 +134,6 @@ protected function getRecordIdFromQuery(): ?int protected function getRecordIdsFromPost(): SplFixedArray { - if (count($this->requested_record_ids) > 0) { - return SplFixedArray::fromArray($this->requested_record_ids); - } - if ($this->http->wrapper()->post()->has('record_id')) { return SplFixedArray::fromArray( $this->http->wrapper()->post()->retrieve( @@ -160,10 +149,6 @@ protected function getRecordIdsFromPost(): SplFixedArray protected function getFieldIdFromQuery(): ?int { - if (count($this->requested_field_ids) === 1) { - return (int) $this->requested_field_ids[0]; - } - if ($this->http->wrapper()->query()->has('field_id')) { return $this->http->wrapper()->query()->retrieve( 'field_id', @@ -175,10 +160,6 @@ protected function getFieldIdFromQuery(): ?int protected function getFieldIdsFromPost(): SplFixedArray { - if (count($this->requested_field_ids) > 0) { - return SplFixedArray::fromArray($this->requested_field_ids); - } - if ($this->http->wrapper()->post()->has('field_id')) { return SplFixedArray::fromArray( $this->http->wrapper()->post()->retrieve( @@ -294,7 +275,7 @@ public function executeCommand(): void $next_class = $this->ctrl->getNextClass($this); $cmd = $this->ctrl->getCmd(); switch ($next_class) { - case "iladvancedmdrecordtranslationgui": + case strtolower(\ilAdvancedMDRecordTranslationGUI::class): $record = $this->initRecordObject(); $this->setRecordSubTabs(1, true); $int_gui = new \ilAdvancedMDRecordTranslationGUI($record); @@ -309,12 +290,6 @@ public function executeCommand(): void $GLOBALS['DIC']->ctrl()->forwardCommand($this->form); break; - case "iladvancedmdsettingsgui": - if ($cmd === 'handleFieldTableAction') { - $this->handleFieldTableAction(); - break; - } - // no break default: if (!$cmd) { $cmd = 'showRecords'; @@ -827,9 +802,11 @@ public function updateRecords(): void $this->ctrl->redirect($this, "showRecords"); } - public function confirmDeleteFields(): void + /** + * @param array $field_ids + */ + public function confirmDeleteFields(int ...$field_ids): void { - $field_ids = $this->getFieldIdsFromPost(); if (!count($field_ids)) { $this->tpl->setOnScreenMessage('failure', $this->lng->txt('select_one')); $this->editFields(); @@ -909,28 +886,25 @@ public function editRecord(?ilPropertyFormGUI $form = null): void $this->tpl->setContent($this->form->getHTML()); } - protected function getDataRetrieval(int $record_id): DataRetrieval + protected function getEditFieldsDataRetrieval(int $record_id): EditFieldsDataRetrieval { - return new DataRetrieval( + return new EditFieldsDataRetrieval( $record_id, $this->active_language, $this->getPermissions(), $this->lng, - $this->ui_factory, - $this->data_factory, - $this->refinery + $this->ui_factory ); } - protected function getFieldTable(int $record_id): Ordering + protected function getFieldTable(int $record_id): OrderingTable { $url_params = $this->getFieldTableActionURLBuilder(); - return new TableBuilder( - $this->getDataRetrieval($record_id), + return new EditFieldsTableBuilder( + $this->getEditFieldsDataRetrieval($record_id), $this->lng, $this->ui_factory, - $this->http, - $this->data_factory + $this->http )->get( $url_params[0], $url_params[1], @@ -975,17 +949,15 @@ protected function handleFieldTableAction(): void $this->refinery->kindlyTo()->string() ); - $retrieval = $this->getDataRetrieval($record_id); - $ids = $this->getIdsFromQuery( + $retrieval = $this->getEditFieldsDataRetrieval($record_id); + $ids = $this->getFieldTableIdsFromQuery( $id_token->getName(), $retrieval ); - $this->requested_field_ids = $ids; switch ($action) { case 'editField': if (count($ids) === 1) { - $this->requested_field_ids = []; $this->ctrl->setParameter($this, 'field_id', $ids[0]); $this->ctrl->redirect($this, 'editField'); } @@ -995,35 +967,32 @@ protected function handleFieldTableAction(): void $this->updateFields(); break; case 'confirmDeleteFields': - $this->confirmDeleteFields(); + $this->confirmDeleteFields(...$ids); break; } } - protected function getIdsFromQuery(string $name, DataRetrieval $retrieval): array + + /** + * @return array + */ + protected function getFieldTableIdsFromQuery(string $name, EditFieldsDataRetrieval $retrieval): array { if (!$this->http->wrapper()->query()->has($name)) { return []; } - $raw_ids = $this->http->wrapper()->query()->retrieve( + $ids = $this->http->wrapper()->query()->retrieve( $name, - $this->refinery->identity() + $this->refinery->kindlyTo()->listOf( + $this->refinery->kindlyTo()->string() + ) ); - if ($raw_ids === 'ALL_OBJECTS' || $raw_ids === ['ALL_OBJECTS']) { + if ($ids === ['ALL_OBJECTS']) { return array_map('intval', $retrieval->getAllIDs()); } - - if (is_array($raw_ids)) { - return array_map('intval', array_filter($raw_ids, fn($id) => is_string($id) && $id !== '')); - } - - if (is_string($raw_ids) && $raw_ids !== '') { - return [(int) $raw_ids]; - } - - return []; + return array_map('intval', $ids); } protected function editFields(): void @@ -1093,9 +1062,7 @@ protected function editFields(): void $this->tpl->setContent( $this->ui_renderer->render([ - $table, - $this->ui_factory->divider()->horizontal(), - $cancel_button + $table ]) ); } From bc39ebb0c30c3c903bd326a725be7aed9ca9354d Mon Sep 17 00:00:00 2001 From: Aleksandr Litvin Date: Tue, 10 Nov 2026 18:30:24 +0100 Subject: [PATCH 3/3] small refactoring for edit fields table in metadata --- .../classes/Field/Table/DataRetrieval.php | 44 ++++++------ .../classes/Field/Table/TableBuilder.php | 41 +++++++---- .../classes/class.ilAdvancedMDSettingsGUI.php | 70 ++++++++----------- 3 files changed, 78 insertions(+), 77 deletions(-) diff --git a/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php b/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php index ce5931041b12..8080bb324bac 100644 --- a/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php @@ -42,6 +42,24 @@ public function __construct( ) { } + public function hasWriteAccess(): bool + { + return $this->permissions->hasPermission( + ilAdvancedMDPermissionHelper::CONTEXT_RECORD, + $this->record_id, + ilAdvancedMDPermissionHelper::ACTION_RECORD_EDIT_FIELDS + ); + } + + public function hasPositionAccess(): bool + { + return $this->permissions->hasPermission( + ilAdvancedMDPermissionHelper::CONTEXT_RECORD, + $this->record_id, + ilAdvancedMDPermissionHelper::ACTION_RECORD_FIELD_POSITIONS + ); + } + protected function getRawData(): array { if (isset($this->raw_data)) { @@ -55,11 +73,8 @@ protected function getRawData(): array ); $res = []; - $ok_icon = $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_ok.svg', '', 'small'); - $not_ok_icon = $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_not_ok.svg', '', 'small'); - + $field_translations = ilAdvancedMDFieldTranslations::getInstanceByRecordId($this->record_id); foreach ($fields as $definition) { - $field_translations = ilAdvancedMDFieldTranslations::getInstanceByRecordId($definition->getRecordId()); $id = $definition->getFieldId(); $properties = $definition->getFieldDefinitionForTableGUI($this->active_language); @@ -69,26 +84,12 @@ protected function getRawData(): array } $configuration = $this->ui_factory->listing()->unordered($configuration_items); - $searchable_icon = $definition->isSearchable() ? $ok_icon : $not_ok_icon; - $res[$id] = [ - 'position' => $definition->getPosition(), 'title' => $field_translations->getTitleForLanguage($id, $this->active_language), 'description' => $field_translations->getDescriptionForLanguage($id, $this->active_language), 'type' => $this->lng->txt($definition->getTypeTitle()), 'configuration' => $configuration, - 'searchable' => $searchable_icon, - 'perm' => $this->permissions->hasPermissions( - ilAdvancedMDPermissionHelper::CONTEXT_FIELD, - (int) $id, - [ - ilAdvancedMDPermissionHelper::ACTION_FIELD_EDIT, - [ - ilAdvancedMDPermissionHelper::ACTION_FIELD_EDIT_PROPERTY, - ilAdvancedMDPermissionHelper::SUBACTION_FIELD_SEARCHABLE - ] - ] - ) + 'searchable' => $definition->isSearchable(), ]; } @@ -116,8 +117,11 @@ public function getTotalRowCount( return count($this->getRawData()); } + /** + * @return int[] + */ public function getAllIDs(): array { - return array_keys($this->getRawData()); + return array_map('intval', array_keys($this->getRawData())); } } diff --git a/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php b/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php index 03e4f6f355de..58cb2ebd72c4 100644 --- a/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php @@ -37,7 +37,7 @@ class TableBuilder public const string EDIT_FIELD_ACTION = 'editField'; public const string DELETE_ACTION = 'confirmDeleteFields'; - public const string SAVE_ACTION = 'updateFields'; + public const string SAVE_ACTION = 'updateFieldPositions'; // action for reordering public function __construct( protected DataRetrieval $data_retrieval, @@ -50,9 +50,11 @@ public function __construct( public function get( URLBuilder $url_builder, URLBuilderToken $id_token, - URLBuilderToken $action_token, - bool $has_write_access + URLBuilderToken $action_token ): OrderingTable { + $has_write_access = $this->data_retrieval->hasWriteAccess(); + $has_position_access = $this->data_retrieval->hasPositionAccess(); + $columns = []; $columns[self::TITLE_COLUMN] = $this->ui_factory->table()->column()->text( $this->lng->txt('title') @@ -63,8 +65,10 @@ public function get( $columns[self::CONFIGURATION_COLUMN] = $this->ui_factory->table()->column()->listing( $this->lng->txt('configuration') ); - $columns[self::SEARCHABLE_COLUMN] = $this->ui_factory->table()->column()->statusIcon( - $this->lng->txt('md_adv_searchable') + $columns[self::SEARCHABLE_COLUMN] = $this->ui_factory->table()->column()->boolean( + $this->lng->txt('md_adv_searchable'), + $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_ok.svg', '', 'small'), + $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_not_ok.svg', '', 'small') ); $actions = []; @@ -74,21 +78,28 @@ public function get( $id_token ); - if ($has_write_access) { - $actions[self::DELETE_ACTION] = $this->ui_factory->table()->action()->multi( - $this->lng->txt('delete'), - $url_builder->withParameter($action_token, self::DELETE_ACTION), - $id_token - ); - } + $actions[self::DELETE_ACTION] = $this->ui_factory->table()->action()->multi( + $this->lng->txt('delete'), + $url_builder->withParameter($action_token, self::DELETE_ACTION), + $id_token + ); $target = $url_builder->withParameter($action_token, self::SAVE_ACTION)->buildURI(); - return $this->ui_factory->table()->ordering( + $table = $this->ui_factory->table()->ordering( $this->data_retrieval, $target, $this->lng->txt('md_adv_field_table'), $columns - )->withActions($actions) - ->withRequest($this->http->request()); + )->withRequest($this->http->request()); + + if (count($actions) > 0 && $has_write_access) { + $table = $table->withActions($actions); + } + + if (!$has_position_access) { + $table = $table->withOrderingDisabled(true); + } + + return $table; } } diff --git a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php index 47cafd84c254..b5c689b095ee 100755 --- a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php +++ b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php @@ -275,10 +275,10 @@ public function executeCommand(): void $next_class = $this->ctrl->getNextClass($this); $cmd = $this->ctrl->getCmd(); switch ($next_class) { - case strtolower(\ilAdvancedMDRecordTranslationGUI::class): + case strtolower(ilAdvancedMDRecordTranslationGUI::class): $record = $this->initRecordObject(); $this->setRecordSubTabs(1, true); - $int_gui = new \ilAdvancedMDRecordTranslationGUI($record); + $int_gui = new ilAdvancedMDRecordTranslationGUI($record); $this->ctrl->forwardCommand($int_gui); break; @@ -314,7 +314,7 @@ public function showRecords(): void if ($perm[ilAdvancedMDPermissionHelper::ACTION_MD_CREATE_RECORD]) { $button = $this->ui_factory->button()->standard( $this->lng->txt('add'), - $this->ctrl->getLinkTargetByClass("iladvancedmdsettingsgui", "createRecord") + $this->ctrl->getLinkTargetByClass(strtolower(self::class), "createRecord") ); $this->toolbar->addComponent($button); @@ -326,7 +326,7 @@ public function showRecords(): void if ($perm[ilAdvancedMDPermissionHelper::ACTION_MD_IMPORT_RECORDS]) { $button = $this->ui_factory->button()->standard( $this->lng->txt('import'), - $this->ctrl->getLinkTargetByClass("iladvancedmdsettingsgui", "importRecords") + $this->ctrl->getLinkTargetByClass(strtolower(self::class), "importRecords") ); $this->toolbar->addComponent($button); } @@ -826,7 +826,7 @@ public function confirmDeleteFields(int ...$field_ids): void // add items to delete foreach ($field_ids as $field_id) { - $field = ilAdvancedMDFieldDefinition::getInstance($field_id); + $field = ilAdvancedMDFieldDefinition::getInstance((int) $field_id); $c_gui->addItem("field_id[]", (string) $field_id, $field->getTitle() ?: 'No Title'); } $this->tpl->setContent($c_gui->getHTML()); @@ -851,7 +851,7 @@ public function deleteFields(): void (int) $field_id, ilAdvancedMDPermissionHelper::ACTION_FIELD_DELETE )) { - $field = ilAdvancedMDFieldDefinition::getInstance($field_id); + $field = ilAdvancedMDFieldDefinition::getInstance((int) $field_id); $fail[] = $field->getTitle(); } } @@ -861,7 +861,7 @@ public function deleteFields(): void } foreach ($field_ids as $field_id) { - $field = ilAdvancedMDFieldDefinition::getInstance($field_id); + $field = ilAdvancedMDFieldDefinition::getInstance((int) $field_id); $field->delete(); } $this->tpl->setOnScreenMessage('success', $this->lng->txt('md_adv_deleted_fields'), true); @@ -908,8 +908,7 @@ protected function getFieldTable(int $record_id): OrderingTable )->get( $url_params[0], $url_params[1], - $url_params[2], - has_write_access: $this->access->checkAccess('write', '', $this->ref_id) + $url_params[2] ); } @@ -923,20 +922,12 @@ protected function getFieldTableActionURLBuilder(): array 'handleFieldTableAction' ); $url_builder = new URLBuilder($this->data_factory->uri($link)); - $record_id = (int) $this->getRecordIdFromQuery(); - if ($record_id) { - list($url_builder, $record_id_token) = $url_builder->acquireParameter(['advmd_field'], 'record_id', (string) $record_id); - } return $url_builder->acquireParameters(['advmd_field'], 'field_ids', 'field_action'); } protected function handleFieldTableAction(): void { - $record_id = (int) $this->getRecordIdFromQuery(); - if ($record_id) { - $this->ctrl->saveParameter($this, 'record_id'); - } - + $this->ctrl->saveParameter($this, 'record_id'); list($url_builder, $id_token, $action_token) = $this->getFieldTableActionURLBuilder(); if (!$this->http->wrapper()->query()->has($action_token->getName())) { @@ -949,6 +940,7 @@ protected function handleFieldTableAction(): void $this->refinery->kindlyTo()->string() ); + $record_id = (int) $this->getRecordIdFromQuery(); $retrieval = $this->getEditFieldsDataRetrieval($record_id); $ids = $this->getFieldTableIdsFromQuery( $id_token->getName(), @@ -956,17 +948,17 @@ protected function handleFieldTableAction(): void ); switch ($action) { - case 'editField': + case EditFieldsTableBuilder::EDIT_FIELD_ACTION: if (count($ids) === 1) { $this->ctrl->setParameter($this, 'field_id', $ids[0]); $this->ctrl->redirect($this, 'editField'); } $this->ctrl->redirect($this, 'editFields'); break; - case 'updateFields': - $this->updateFields(); + case EditFieldsTableBuilder::SAVE_ACTION: + $this->updateFieldPositions(); break; - case 'confirmDeleteFields': + case EditFieldsTableBuilder::DELETE_ACTION: $this->confirmDeleteFields(...$ids); break; } @@ -1001,7 +993,6 @@ protected function editFields(): void if (!$record_id) { $this->ctrl->redirect($this, 'showRecords'); } - $this->ctrl->saveParameter($this, 'record_id'); $this->initRecordObject(); $this->setRecordSubTabs(); $this->initLanguage($record_id); @@ -1026,7 +1017,7 @@ protected function editFields(): void $this->ctrl->setParameter($this, 'ftype', $type); $create_link = $this->ctrl->getLinkTarget($this, 'createField'); - $this->ctrl->clearParameterByClass("iladvancedmdsettingsgui", 'ftype'); + $this->ctrl->clearParameterByClass(strtolower(self::class), 'ftype'); $field_buttons[] = $this->ui_factory->button()->shy( $this->lng->txt($field->getTypeTitle()), @@ -1055,11 +1046,7 @@ protected function editFields(): void $table = $this->getFieldTable((int) $this->record->getRecordId()); - $cancel_button = $this->ui_factory->button()->standard( - $this->lng->txt('cancel'), - $this->ctrl->getLinkTarget($this, "showRecords") - ); - + $this->ctrl->saveParameter($this, 'record_id'); $this->tpl->setContent( $this->ui_renderer->render([ $table @@ -1071,9 +1058,8 @@ protected function editFields(): void * Update fields * @access public */ - public function updateFields(): void + public function updateFieldPositions(): void { - $this->ctrl->saveParameter($this, 'record_id'); $record_id = (int) $this->getRecordIdFromQuery(); if (!$record_id) { $this->tpl->setOnScreenMessage('failure', $this->lng->txt('select_one')); @@ -1085,17 +1071,16 @@ public function updateFields(): void $ordered_ids = $table->getData(); $fields = ilAdvancedMDFieldDefinition::getInstancesByRecordId($record_id); - $i = 1; - foreach ($ordered_ids as $field_id) { - $field_id = (int) $field_id; - if (isset($fields[$field_id])) { - $field = $fields[$field_id]; - - if ($this->getPermissions()->hasPermission( - ilAdvancedMDPermissionHelper::CONTEXT_RECORD, - $record_id, - ilAdvancedMDPermissionHelper::ACTION_RECORD_FIELD_POSITIONS - )) { + $i = 0; + if ($this->getPermissions()->hasPermission( + ilAdvancedMDPermissionHelper::CONTEXT_RECORD, + $record_id, + ilAdvancedMDPermissionHelper::ACTION_RECORD_FIELD_POSITIONS + )) { + foreach ($ordered_ids as $field_id) { + $field_id = (int) $field_id; + if (isset($fields[$field_id])) { + $field = $fields[$field_id]; $field->setPosition($i++); $field->update(); } @@ -1129,6 +1114,7 @@ public function updateRecord(): void if (!$this->form->checkInput()) { $this->tpl->setOnScreenMessage('failure', $this->lng->txt('err_check_input')); $this->form->setValuesByPost(); + $this->ctrl->saveParameter($this, 'record_id'); $this->editRecord($this->form); return; }