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..8080bb324bac --- /dev/null +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/DataRetrieval.php @@ -0,0 +1,127 @@ +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)) { + return $this->raw_data; + } + + $fields = ilAdvancedMDFieldDefinition::getInstancesByRecordId( + $this->record_id, + false, + $this->active_language + ); + + $res = []; + $field_translations = ilAdvancedMDFieldTranslations::getInstanceByRecordId($this->record_id); + foreach ($fields as $definition) { + $id = $definition->getFieldId(); + + $properties = $definition->getFieldDefinitionForTableGUI($this->active_language); + $configuration_items = []; + foreach ($properties as $key => $value) { + $configuration_items[] = (string) $key . ": " . (string) $value; + } + $configuration = $this->ui_factory->listing()->unordered($configuration_items); + + $res[$id] = [ + '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' => $definition->isSearchable(), + ]; + } + + $this->raw_data = $res; + return $this->raw_data; + } + + public function getRows( + OrderingRowBuilder $row_builder, + array $visible_column_ids + ): Generator { + foreach ($this->getRawData() as $id => $datum) { + yield $row_builder->buildOrderingRow( + (string) $id, + $datum + ); + } + } + + public function getTotalRowCount( + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): ?int { + return count($this->getRawData()); + } + + /** + * @return int[] + */ + public function getAllIDs(): array + { + 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 new file mode 100644 index 000000000000..58cb2ebd72c4 --- /dev/null +++ b/components/ILIAS/AdvancedMetaData/classes/Field/Table/TableBuilder.php @@ -0,0 +1,105 @@ +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') + )->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()->listing( + $this->lng->txt('configuration') + ); + $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 = []; + $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 + ); + + $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(); + $table = $this->ui_factory->table()->ordering( + $this->data_retrieval, + $target, + $this->lng->txt('md_adv_field_table'), + $columns + )->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 20b4df7c6d8d..b5c689b095ee 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 as EditFieldsTableBuilder; +use AdvancedMetadata\Field\Table\DataRetrieval as EditFieldsDataRetrieval; +use ILIAS\UI\Component\Table\Ordering as OrderingTable; /** * @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(); @@ -270,7 +278,7 @@ public function executeCommand(): void 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; @@ -794,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(); @@ -816,7 +826,7 @@ public function confirmDeleteFields(): 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()); @@ -841,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(); } } @@ -851,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); @@ -876,13 +886,113 @@ public function editRecord(?ilPropertyFormGUI $form = null): void $this->tpl->setContent($this->form->getHTML()); } + protected function getEditFieldsDataRetrieval(int $record_id): EditFieldsDataRetrieval + { + return new EditFieldsDataRetrieval( + $record_id, + $this->active_language, + $this->getPermissions(), + $this->lng, + $this->ui_factory + ); + } + + protected function getFieldTable(int $record_id): OrderingTable + { + $url_params = $this->getFieldTableActionURLBuilder(); + return new EditFieldsTableBuilder( + $this->getEditFieldsDataRetrieval($record_id), + $this->lng, + $this->ui_factory, + $this->http + )->get( + $url_params[0], + $url_params[1], + $url_params[2] + ); + } + + /** + * @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)); + return $url_builder->acquireParameters(['advmd_field'], 'field_ids', 'field_action'); + } + + protected function handleFieldTableAction(): void + { + $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() + ); + + $record_id = (int) $this->getRecordIdFromQuery(); + $retrieval = $this->getEditFieldsDataRetrieval($record_id); + $ids = $this->getFieldTableIdsFromQuery( + $id_token->getName(), + $retrieval + ); + + switch ($action) { + 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 EditFieldsTableBuilder::SAVE_ACTION: + $this->updateFieldPositions(); + break; + case EditFieldsTableBuilder::DELETE_ACTION: + $this->confirmDeleteFields(...$ids); + break; + } + } + + + /** + * @return array + */ + protected function getFieldTableIdsFromQuery(string $name, EditFieldsDataRetrieval $retrieval): array + { + if (!$this->http->wrapper()->query()->has($name)) { + return []; + } + + $ids = $this->http->wrapper()->query()->retrieve( + $name, + $this->refinery->kindlyTo()->listOf( + $this->refinery->kindlyTo()->string() + ) + ); + + if ($ids === ['ALL_OBJECTS']) { + return array_map('intval', $retrieval->getAllIDs()); + } + return array_map('intval', $ids); + } + protected function editFields(): void { $record_id = $this->getRecordIdFromQuery(); if (!$record_id) { $this->ctrl->redirect($this, 'showRecords'); } - $this->ctrl->saveParameter($this, 'record_id'); $this->initRecordObject(); $this->setRecordSubTabs(); $this->initLanguage($record_id); @@ -934,78 +1044,52 @@ 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() + $this->ctrl->saveParameter($this, 'record_id'); + $this->tpl->setContent( + $this->ui_renderer->render([ + $table + ]) ); - $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()); } /** * Update fields * @access public */ - public function updateFields(): void + public function updateFieldPositions(): 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); + $i = 0; 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(); + 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(); + } } } - $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"); @@ -1030,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; }