diff --git a/composer.json b/composer.json index 732fe2ab4..fc77457e7 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "php": "~8.3.0 || ~8.4.0", "league/csv": "^9.22", "nesbot/carbon": "^3.8.4", - "pimcore/static-resolver-bundle": "^3.4.0 || ^2026.1", + "pimcore/static-resolver-bundle": "^3.5.0 || ^2026.1", "pimcore/generic-data-index-bundle": "^2.4.0 || ^2026.1", "pimcore/pimcore": "^12.3 || ^2026.1", "zircote/swagger-php": "^4.8 || ^5.0", diff --git a/config/class.yaml b/config/class.yaml index aa4cc4307..54f3b97dc 100644 --- a/config/class.yaml +++ b/config/class.yaml @@ -41,8 +41,11 @@ services: Pimcore\Bundle\StudioBackendBundle\Class\Service\IdentifierServiceInterface: class: Pimcore\Bundle\StudioBackendBundle\Class\Service\IdentifierService - Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptionServiceInterface: - class: Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptionService + Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptions\TreeServiceInterface: + class: Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptions\TreeService + + Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptions\SelectOptionServiceInterface: + class: Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptions\SelectOptionService Pimcore\Bundle\StudioBackendBundle\Class\Service\ClassDefinitionTreeServiceInterface: class: Pimcore\Bundle\StudioBackendBundle\Class\Service\ClassDefinitionTreeService @@ -72,6 +75,9 @@ services: Pimcore\Bundle\StudioBackendBundle\Class\Repository\CustomLayoutRepositoryInterface: class: Pimcore\Bundle\StudioBackendBundle\Class\Repository\CustomLayoutRepository + Pimcore\Bundle\StudioBackendBundle\Class\Repository\SelectOptionRepositoryInterface: + class: Pimcore\Bundle\StudioBackendBundle\Class\Repository\SelectOptionRepository + # # Hydrators # @@ -146,3 +152,6 @@ services: Pimcore\Bundle\StudioBackendBundle\Class\Hydrator\SelectOption\TreeFolderHydratorInterface: class: Pimcore\Bundle\StudioBackendBundle\Class\Hydrator\SelectOption\TreeFolderHydrator + + Pimcore\Bundle\StudioBackendBundle\Class\Hydrator\SelectOption\DetailHydratorInterface: + class: Pimcore\Bundle\StudioBackendBundle\Class\Hydrator\SelectOption\DetailHydrator diff --git a/doc/05_Additional_Custom_Attributes.md b/doc/05_Additional_Custom_Attributes.md index 1ac47954f..cf4ce3892 100644 --- a/doc/05_Additional_Custom_Attributes.md +++ b/doc/05_Additional_Custom_Attributes.md @@ -160,7 +160,9 @@ final class AssetEvent extends AbstractPreResponseEvent - `pre_response.recycle_bin.item` - `pre_response.role_tree_node` - `pre_response.schedule` +- `pre_response.select_option.detail` - `pre_response.select_option.tree` +- `pre_response.select_option.usage_item` - `pre_response.settings.active_bundle` - `pre_response.settings.available_country` - `pre_response.simple_search.preview` diff --git a/src/Class/Controller/SelectOptions/CreateController.php b/src/Class/Controller/SelectOptions/CreateController.php new file mode 100644 index 000000000..b96bfc7e6 --- /dev/null +++ b/src/Class/Controller/SelectOptions/CreateController.php @@ -0,0 +1,80 @@ +value)] + #[Post( + path: self::PREFIX . self::ROUTE, + operationId: 'class_select_option_create', + description: 'class_select_option_create_description', + summary: 'class_select_option_create_summary', + tags: [Tags::ClassDefinition->value], + )] + #[ReferenceRequestBody(CreateSelectOption::class)] + #[SuccessResponse( + description: 'class_select_option_create_success_response', + content: new JsonContent(ref: SelectOptionDetail::class) + )] + #[DefaultResponses([ + HttpResponseCodes::CONFLICT, + HttpResponseCodes::INTERNAL_SERVER_ERROR, + HttpResponseCodes::UNAUTHORIZED, + ])] + public function createSelectOption( + #[MapRequestPayload] CreateSelectOptionParameters $parameters, + ): JsonResponse { + return $this->jsonResponse( + $this->selectOptionService->createSelectOption($parameters) + ); + } +} diff --git a/src/Class/Controller/SelectOptions/DeleteController.php b/src/Class/Controller/SelectOptions/DeleteController.php new file mode 100644 index 000000000..e1a0f3459 --- /dev/null +++ b/src/Class/Controller/SelectOptions/DeleteController.php @@ -0,0 +1,82 @@ +value)] + #[Delete( + path: self::PREFIX . self::ROUTE, + operationId: 'class_select_option_delete', + description: 'class_select_option_delete_description', + summary: 'class_select_option_delete_summary', + tags: [Tags::ClassDefinition->value], + )] + #[StringParameter( + name: 'id', + example: 'EventStatus', + description: 'Select option configuration ID', + required: true + )] + #[SuccessResponse( + description: 'class_select_option_delete_success_response' + )] + #[DefaultResponses([ + HttpResponseCodes::CONFLICT, + HttpResponseCodes::FORBIDDEN, + HttpResponseCodes::INTERNAL_SERVER_ERROR, + HttpResponseCodes::NOT_FOUND, + HttpResponseCodes::UNAUTHORIZED, + ])] + public function deleteSelectOption(string $id): Response + { + $this->selectOptionService->deleteSelectOption($id); + + return new Response(); + } +} diff --git a/src/Class/Controller/SelectOptions/GetController.php b/src/Class/Controller/SelectOptions/GetController.php new file mode 100644 index 000000000..71d0c86dc --- /dev/null +++ b/src/Class/Controller/SelectOptions/GetController.php @@ -0,0 +1,79 @@ +value)] + #[Get( + path: self::PREFIX . self::ROUTE, + operationId: 'class_select_option_get', + description: 'class_select_option_get_description', + summary: 'class_select_option_get_summary', + tags: [Tags::ClassDefinition->value], + )] + #[StringParameter( + name: 'id', + example: 'EventStatus', + description: 'Select option configuration ID', + required: true + )] + #[SuccessResponse( + description: 'class_select_option_get_success_response', + content: new JsonContent(ref: SelectOptionDetail::class) + )] + #[DefaultResponses([ + HttpResponseCodes::NOT_FOUND, + HttpResponseCodes::UNAUTHORIZED, + ])] + public function getSelectOption(string $id): JsonResponse + { + return $this->jsonResponse( + $this->selectOptionService->getSelectOption($id) + ); + } +} diff --git a/src/Class/Controller/SelectOptions/TreeController.php b/src/Class/Controller/SelectOptions/TreeController.php index a2bdee163..d703d8c4a 100644 --- a/src/Class/Controller/SelectOptions/TreeController.php +++ b/src/Class/Controller/SelectOptions/TreeController.php @@ -16,7 +16,7 @@ use OpenApi\Attributes\Get; use Pimcore\Bundle\StudioBackendBundle\Class\Attribute\Response\Property\AnyOfSelectOptionNodes; use Pimcore\Bundle\StudioBackendBundle\Class\MappedParameter\TreeParameter; -use Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptionServiceInterface; +use Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptions\TreeServiceInterface; use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Query\BoolParameter; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\CollectionJson; @@ -44,12 +44,12 @@ final class TreeController extends AbstractApiController public function __construct( SerializerInterface $serializer, - private readonly SelectOptionServiceInterface $optionService, + private readonly TreeServiceInterface $optionService, ) { parent::__construct($serializer); } - #[Route(self::ROUTE, name: 'pimcore_studio_api_class_select_option_tree', methods: ['GET'])] + #[Route(self::ROUTE, name: 'pimcore_studio_api_class_select_option_tree', methods: ['GET'], priority: 10)] #[IsGranted(UserPermissions::SELECT_OPTIONS->value)] #[Get( path: self::PREFIX . self::ROUTE, diff --git a/src/Class/Controller/SelectOptions/UpdateController.php b/src/Class/Controller/SelectOptions/UpdateController.php new file mode 100644 index 000000000..82c558b7a --- /dev/null +++ b/src/Class/Controller/SelectOptions/UpdateController.php @@ -0,0 +1,91 @@ +value)] + #[Put( + path: self::PREFIX . self::ROUTE, + operationId: 'class_select_option_update', + description: 'class_select_option_update_description', + summary: 'class_select_option_update_summary', + tags: [Tags::ClassDefinition->value], + )] + #[StringParameter( + name: 'id', + example: 'EventStatus', + description: 'Select option configuration ID', + required: true + )] + #[ReferenceRequestBody(UpdateSelectOption::class)] + #[SuccessResponse( + description: 'class_select_option_update_success_response', + content: new JsonContent(ref: SelectOptionDetail::class) + )] + #[DefaultResponses([ + HttpResponseCodes::FORBIDDEN, + HttpResponseCodes::INTERNAL_SERVER_ERROR, + HttpResponseCodes::NOT_FOUND, + HttpResponseCodes::UNAUTHORIZED, + ])] + public function updateSelectOption( + string $id, + #[MapRequestPayload] UpdateSelectOptionParameters $parameters, + ): JsonResponse { + return $this->jsonResponse( + $this->selectOptionService->updateSelectOption($id, $parameters) + ); + } +} diff --git a/src/Class/Controller/SelectOptions/UsagesController.php b/src/Class/Controller/SelectOptions/UsagesController.php new file mode 100644 index 000000000..99dcf144d --- /dev/null +++ b/src/Class/Controller/SelectOptions/UsagesController.php @@ -0,0 +1,83 @@ +value)] + #[Get( + path: self::PREFIX . self::ROUTE, + operationId: 'class_select_option_get_usages', + description: 'class_select_option_get_usages_description', + summary: 'class_select_option_get_usages_summary', + tags: [Tags::ClassDefinition->value], + )] + #[StringParameter( + name: 'id', + example: 'EventStatus', + description: 'Select option configuration ID', + required: true + )] + #[SuccessResponse( + description: 'class_select_option_get_usages_success_response', + content: new ItemsJson(SelectOptionUsageItem::class) + )] + #[DefaultResponses([ + HttpResponseCodes::NOT_FOUND, + HttpResponseCodes::UNAUTHORIZED, + ])] + public function getSelectOptionUsages(string $id): JsonResponse + { + return $this->jsonResponse( + ['items' => $this->selectOptionService->getSelectOptionUsages($id)] + ); + } +} diff --git a/src/Class/Event/SelectOption/DetailEvent.php b/src/Class/Event/SelectOption/DetailEvent.php new file mode 100644 index 000000000..f815f9e44 --- /dev/null +++ b/src/Class/Event/SelectOption/DetailEvent.php @@ -0,0 +1,33 @@ +selectOptionDetail; + } +} diff --git a/src/Class/Event/SelectOption/UsageItemEvent.php b/src/Class/Event/SelectOption/UsageItemEvent.php new file mode 100644 index 000000000..fd66eb22d --- /dev/null +++ b/src/Class/Event/SelectOption/UsageItemEvent.php @@ -0,0 +1,33 @@ +usageItem; + } +} diff --git a/src/Class/Hydrator/SelectOption/DetailHydrator.php b/src/Class/Hydrator/SelectOption/DetailHydrator.php new file mode 100644 index 000000000..dd69e6acf --- /dev/null +++ b/src/Class/Hydrator/SelectOption/DetailHydrator.php @@ -0,0 +1,56 @@ +getId(), + $config->getGroup(), + $config->getAdminOnly(), + $config->getUseTraits(), + $config->getImplementsInterfaces(), + $this->hydrateSelectOptions($config->getSelectOptions()), + $config->getEnumName(true), + $isWriteable, + ); + } + + /** + * @param SelectOption[] $selectOptions + * + * @return SelectOptionData[] + */ + private function hydrateSelectOptions(array $selectOptions): array + { + return array_map( + static fn (SelectOption $option): SelectOptionData => new SelectOptionData( + $option->getValue(), + $option->getLabel(), + $option->getName(), + ), + $selectOptions, + ); + } +} diff --git a/src/Class/Hydrator/SelectOption/DetailHydratorInterface.php b/src/Class/Hydrator/SelectOption/DetailHydratorInterface.php new file mode 100644 index 000000000..4c84afb2e --- /dev/null +++ b/src/Class/Hydrator/SelectOption/DetailHydratorInterface.php @@ -0,0 +1,25 @@ +id; + } +} diff --git a/src/Class/MappedParameter/UpdateSelectOptionParameters.php b/src/Class/MappedParameter/UpdateSelectOptionParameters.php new file mode 100644 index 000000000..7e62da27d --- /dev/null +++ b/src/Class/MappedParameter/UpdateSelectOptionParameters.php @@ -0,0 +1,54 @@ +group; + } + + public function isAdminOnly(): bool + { + return $this->adminOnly; + } + + public function getUseTraits(): string + { + return $this->useTraits; + } + + public function getImplementsInterfaces(): string + { + return $this->implementsInterfaces; + } + + public function getSelectOptions(): ?array + { + return $this->selectOptions; + } +} diff --git a/src/Class/Repository/SelectOptionRepository.php b/src/Class/Repository/SelectOptionRepository.php new file mode 100644 index 000000000..406423e74 --- /dev/null +++ b/src/Class/Repository/SelectOptionRepository.php @@ -0,0 +1,132 @@ +load(); + } + + public function getById(string $id): Config + { + $config = $this->configResolver->getById($id); + + if ($config === null) { + throw new NotFoundException(type: 'Select Option', id: $id); + } + + return $config; + } + + /** + * {@inheritdoc} + */ + public function create(string $id): Config + { + $listing = new Listing(); + + if ($listing->hasConfig($id)) { + throw new ElementExistsException( + sprintf( + 'Select options with the same ID already exists (lower/upper cases may be different): %s', + $id + ) + ); + } + + try { + $config = $this->configResolver->createFromData([ + Config::PROPERTY_ID => $id, + ]); + } catch (InvalidArgumentException | RuntimeException $e) { + throw new ApiInvalidArgumentException(message: $e->getMessage(), previous: $e); + } + + try { + $config->save(); + } catch (Exception $e) { + throw new ElementSavingFailedException(null, $e->getMessage(), $e); + } + + return $config; + } + + /** + * {@inheritdoc} + */ + public function save(Config $config): void + { + if (!$this->isWriteable($config)) { + throw new NotWriteableException(self::NOT_WRITEABLE_EXCEPTION_MESSAGE); + } + + try { + $config->save(); + } catch (Exception $e) { + throw new ElementSavingFailedException(null, $e->getMessage(), $e); + } + } + + /** + * {@inheritdoc} + */ + public function delete(Config $config): void + { + if (!$this->isWriteable($config)) { + throw new NotWriteableException(self::NOT_WRITEABLE_EXCEPTION_MESSAGE); + } + + try { + $config->delete(); + } catch (RuntimeException $e) { + throw new ConflictException($e->getMessage(), $e); + } + } + + public function isWriteable(Config $config): bool + { + return $config->isWriteable(); + } + + public function getFieldsUsedIn(Config $config): array + { + return $config->getFieldsUsedIn(); + } +} diff --git a/src/Class/Repository/SelectOptionRepositoryInterface.php b/src/Class/Repository/SelectOptionRepositoryInterface.php new file mode 100644 index 000000000..d0fa8e1c8 --- /dev/null +++ b/src/Class/Repository/SelectOptionRepositoryInterface.php @@ -0,0 +1,64 @@ + + */ + public function getFieldsUsedIn(Config $config): array; +} diff --git a/src/Class/Schema/SelectOption/CreateSelectOption.php b/src/Class/Schema/SelectOption/CreateSelectOption.php new file mode 100644 index 000000000..a7f966845 --- /dev/null +++ b/src/Class/Schema/SelectOption/CreateSelectOption.php @@ -0,0 +1,40 @@ +id; + } +} diff --git a/src/Class/Schema/SelectOption/SelectOptionData.php b/src/Class/Schema/SelectOption/SelectOptionData.php new file mode 100644 index 000000000..739d66e0a --- /dev/null +++ b/src/Class/Schema/SelectOption/SelectOptionData.php @@ -0,0 +1,54 @@ +value; + } + + public function getLabel(): string + { + return $this->label; + } + + public function getName(): string + { + return $this->name; + } +} diff --git a/src/Class/Schema/SelectOption/SelectOptionDetail.php b/src/Class/Schema/SelectOption/SelectOptionDetail.php new file mode 100644 index 000000000..f9679f47e --- /dev/null +++ b/src/Class/Schema/SelectOption/SelectOptionDetail.php @@ -0,0 +1,115 @@ +id; + } + + public function getGroup(): ?string + { + return $this->group; + } + + public function isAdminOnly(): bool + { + return $this->adminOnly; + } + + public function getUseTraits(): string + { + return $this->useTraits; + } + + public function getImplementsInterfaces(): string + { + return $this->implementsInterfaces; + } + + /** + * @return SelectOptionData[] + */ + public function getSelectOptions(): array + { + return $this->selectOptions; + } + + public function getEnumName(): string + { + return $this->enumName; + } + + public function getIsWriteable(): bool + { + return $this->isWriteable; + } +} diff --git a/src/Class/Schema/SelectOption/SelectOptionUsageItem.php b/src/Class/Schema/SelectOption/SelectOptionUsageItem.php new file mode 100644 index 000000000..0d31cdb4e --- /dev/null +++ b/src/Class/Schema/SelectOption/SelectOptionUsageItem.php @@ -0,0 +1,51 @@ +class; + } + + public function getField(): string + { + return $this->field; + } +} diff --git a/src/Class/Schema/SelectOption/UpdateSelectOption.php b/src/Class/Schema/SelectOption/UpdateSelectOption.php new file mode 100644 index 000000000..f1544485f --- /dev/null +++ b/src/Class/Schema/SelectOption/UpdateSelectOption.php @@ -0,0 +1,80 @@ +group; + } + + public function isAdminOnly(): bool + { + return $this->adminOnly; + } + + public function getUseTraits(): string + { + return $this->useTraits; + } + + public function getImplementsInterfaces(): string + { + return $this->implementsInterfaces; + } + + public function getSelectOptions(): ?array + { + return $this->selectOptions; + } +} diff --git a/src/Class/Service/SelectOptions/SelectOptionService.php b/src/Class/Service/SelectOptions/SelectOptionService.php new file mode 100644 index 000000000..8df9dca67 --- /dev/null +++ b/src/Class/Service/SelectOptions/SelectOptionService.php @@ -0,0 +1,169 @@ +selectOptionRepository->getById($id); + + return $this->hydrateDetail($config); + } + + /** + * {@inheritdoc} + */ + public function createSelectOption(CreateSelectOptionParameters $parameters): SelectOptionDetail + { + $config = $this->selectOptionRepository->create($parameters->getId()); + + return $this->hydrateDetail($config); + } + + /** + * {@inheritdoc} + */ + public function updateSelectOption(string $id, UpdateSelectOptionParameters $parameters): SelectOptionDetail + { + $config = $this->selectOptionRepository->getById($id); + $this->checkAdminAccess($config); + + $this->validateSelectOptions($parameters->getSelectOptions()); + + try { + $config = $this->configResolver->createFromData([ + Config::PROPERTY_ID => $id, + Config::PROPERTY_GROUP => $parameters->getGroup(), + Config::PROPERTY_ADMIN_ONLY => $parameters->isAdminOnly(), + Config::PROPERTY_USE_TRAITS => $parameters->getUseTraits(), + Config::PROPERTY_IMPLEMENTS_INTERFACES => $parameters->getImplementsInterfaces(), + Config::PROPERTY_SELECT_OPTIONS => $parameters->getSelectOptions(), + ]); + } catch (InvalidArgumentException | RuntimeException $e) { + throw new ApiInvalidArgumentException(message: $e->getMessage(), previous: $e); + } + + $this->selectOptionRepository->save($config); + + return $this->hydrateDetail($config); + } + + /** + * {@inheritdoc} + */ + public function deleteSelectOption(string $id): void + { + $config = $this->selectOptionRepository->getById($id); + $this->checkAdminAccess($config); + $this->selectOptionRepository->delete($config); + } + + /** + * {@inheritdoc} + */ + public function getSelectOptionUsages(string $id): array + { + $config = $this->selectOptionRepository->getById($id); + $fieldsUsedIn = $this->selectOptionRepository->getFieldsUsedIn($config); + $usages = []; + + foreach ($fieldsUsedIn as $className => $fields) { + foreach ($fields as $field) { + $usageItem = new SelectOptionUsageItem($className, $field); + $this->eventDispatcher->dispatch( + new UsageItemEvent($usageItem), + UsageItemEvent::EVENT_NAME + ); + $usages[] = $usageItem; + } + } + + return $usages; + } + + private function hydrateDetail(Config $config): SelectOptionDetail + { + $isWriteable = $this->selectOptionRepository->isWriteable($config); + $detail = $this->detailHydrator->hydrate($config, $isWriteable); + $this->eventDispatcher->dispatch(new DetailEvent($detail), DetailEvent::EVENT_NAME); + + return $detail; + } + + /** + * @throws ApiInvalidArgumentException + */ + private function validateSelectOptions(?array $selectOptions): void + { + if ($selectOptions === null) { + return; + } + + foreach ($selectOptions as $index => $option) { + if (!is_array($option) || !isset($option['value']) || $option['value'] === '') { + throw new ApiInvalidArgumentException( + message: sprintf( + 'Select option at index %d must have a non-empty "value" field', + $index, + ), + ); + } + } + } + + /** + * @throws ForbiddenException + */ + private function checkAdminAccess(Config $config): void + { + if ($config->getAdminOnly() && !$this->securityService->getCurrentUser()->isAdmin()) { + throw new ForbiddenException('Restricted to admin users'); + } + } +} diff --git a/src/Class/Service/SelectOptions/SelectOptionServiceInterface.php b/src/Class/Service/SelectOptions/SelectOptionServiceInterface.php new file mode 100644 index 000000000..b81779c22 --- /dev/null +++ b/src/Class/Service/SelectOptions/SelectOptionServiceInterface.php @@ -0,0 +1,68 @@ +selectOptionRepository->listSelectOptions(); if ($grouped === false) { return $this->getUngroupedTree($selectOptionConfigs); @@ -56,11 +57,13 @@ public function getTree(bool $grouped = false): array return $this->getGroupedNodes($groups); } - private function getUngroupedTree(Listing $configs): array + /** + * @param Config[] $configs + */ + private function getUngroupedTree(array $configs): array { $hydrated = []; - /** @var Config $config */ foreach ($configs as $config) { $hydrated[] = $this->hydrateConfig($config); } @@ -68,11 +71,13 @@ private function getUngroupedTree(Listing $configs): array return $hydrated; } - private function getGroups(Listing $configs): array + /** + * @param Config[] $configs + */ + private function getGroups(array $configs): array { $groups = []; - /** @var Config $config */ foreach ($configs as $config) { [$groupName, $type] = $this->resolveGroupInfo($config); @@ -103,8 +108,11 @@ private function resolveGroupInfo(Config $config): array private function sortGroups(array $groups): array { - $types = array_column($groups, 'type'); - array_multisort($types, SORT_DESC, array_keys($groups), SORT_ASC, $groups); + uksort($groups, static function (string $a, string $b) use ($groups): int { + $typeComparison = $groups[$b]['type'] <=> $groups[$a]['type']; + + return $typeComparison !== 0 ? $typeComparison : $a <=> $b; + }); return $groups; } diff --git a/src/Class/Service/SelectOptionServiceInterface.php b/src/Class/Service/SelectOptions/TreeServiceInterface.php similarity index 87% rename from src/Class/Service/SelectOptionServiceInterface.php rename to src/Class/Service/SelectOptions/TreeServiceInterface.php index f468877e7..9a77fff9a 100644 --- a/src/Class/Service/SelectOptionServiceInterface.php +++ b/src/Class/Service/SelectOptions/TreeServiceInterface.php @@ -11,7 +11,7 @@ * @license Pimcore Open Core License (POCL) */ -namespace Pimcore\Bundle\StudioBackendBundle\Class\Service; +namespace Pimcore\Bundle\StudioBackendBundle\Class\Service\SelectOptions; use Pimcore\Bundle\StudioBackendBundle\Class\Schema\SelectOption\SelectOptionTree; use Pimcore\Bundle\StudioBackendBundle\Class\Schema\SelectOption\SelectOptionTreeFolder; @@ -19,7 +19,7 @@ /** * @internal */ -interface SelectOptionServiceInterface +interface TreeServiceInterface { /** * @return SelectOptionTree[]|SelectOptionTreeFolder[] diff --git a/translations/studio_api_docs.en.yaml b/translations/studio_api_docs.en.yaml index 9d6f768d1..21bf8b379 100644 --- a/translations/studio_api_docs.en.yaml +++ b/translations/studio_api_docs.en.yaml @@ -1612,6 +1612,31 @@ class_select_option_get_tree_description: | Get select options tree data. Results can be grouped based on the {withGroup} parameter. class_select_option_get_tree_summary: Get select options tree data class_select_option_get_tree_success_response: Select options data for the tree view +class_select_option_get_description: | + Get a single select option configuration by its ID. + Returns all configuration details including select option entries, group, traits, interfaces, and the fully qualified enum name. +class_select_option_get_summary: Get select option configuration by ID +class_select_option_get_success_response: Select option configuration detail +class_select_option_create_description: | + Create a new select option configuration. + The ID must be unique (case-insensitive). Returns the newly created configuration detail. +class_select_option_create_summary: Create a new select option configuration +class_select_option_create_success_response: Newly created select option configuration detail +class_select_option_update_description: | + Update an existing select option configuration. + Replaces the configuration data with the provided values. Admin-only configurations require admin access. +class_select_option_update_summary: Update a select option configuration +class_select_option_update_success_response: Updated select option configuration detail +class_select_option_delete_description: | + Delete a select option configuration by its ID. + Fails with a conflict error if the configuration is currently in use by class definitions. + Admin-only configurations require admin access. +class_select_option_delete_summary: Delete a select option configuration +class_select_option_delete_success_response: Successfully deleted the select option configuration +class_select_option_get_usages_description: | + Get the list of class definitions and fields that use a specific select option configuration. +class_select_option_get_usages_summary: Get usages of a select option configuration +class_select_option_get_usages_success_response: List of classes and fields using the select option configuration class_custom_layout_get: Get custom layout by given id class_custom_layout_get_description: Get custom layout by given id class_custom_layout_get_summary: Get custom layout by given id