From 4bf58bca38c2f88e4ec43eb6fb08631a2c7ba6d5 Mon Sep 17 00:00:00 2001 From: markus-moser Date: Thu, 25 Jun 2026 14:34:43 +0000 Subject: [PATCH] [Search] Add sorting to the saved search list endpoint Expose sortBy (name | modificationDate) + sortOrder (ASC | DESC) query params on GET /search/saved/configuration; sort the accessible configurations in the service before pagination. Default order (modification date, newest first) is unchanged. --- .../SavedSearch/ListConfigurationsController.php | 10 +++++++++- .../SavedSearchConfigurationRepository.php | 12 ++++++++++-- .../SavedSearchConfigurationRepositoryInterface.php | 2 +- .../Service/SavedSearchConfigurationService.php | 11 ++++++++--- .../SavedSearchConfigurationServiceInterface.php | 7 ++++++- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/Search/Controller/SavedSearch/ListConfigurationsController.php b/src/Search/Controller/SavedSearch/ListConfigurationsController.php index 997d8aae0..6e7bcdcd4 100644 --- a/src/Search/Controller/SavedSearch/ListConfigurationsController.php +++ b/src/Search/Controller/SavedSearch/ListConfigurationsController.php @@ -18,6 +18,8 @@ use Pimcore\Bundle\StudioBackendBundle\MappedParameter\CollectionParameters; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Query\PageParameter; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Query\PageSizeParameter; +use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Query\SortByParameter; +use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Query\SortOrderParameter; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Query\TextFieldParameter; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Property\GenericCollection; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\CollectionJson; @@ -72,6 +74,8 @@ public function __construct( description: 'Optional term to filter the saved search configurations by name.', required: false )] + #[SortByParameter(enum: ['name', 'modificationDate'])] + #[SortOrderParameter] #[SuccessResponse( description: 'saved_search_get_configurations_success_response', content: new CollectionJson(new GenericCollection(ConfigurationListItem::class)) @@ -81,11 +85,15 @@ public function __construct( ])] public function getSavedSearchConfigurations( #[MapQueryParameter] ?string $searchTerm = null, + #[MapQueryParameter] ?string $sortBy = null, + #[MapQueryParameter] ?string $sortOrder = null, #[MapQueryString] CollectionParameters $parameters = new CollectionParameters(), ): JsonResponse { $collection = $this->savedSearchConfigurationService->listConfigurations( $parameters, - $searchTerm + $searchTerm, + $sortBy, + $sortOrder ); return $this->getPaginatedCollection( diff --git a/src/Search/Repository/SavedSearchConfigurationRepository.php b/src/Search/Repository/SavedSearchConfigurationRepository.php index c5c0d65b7..6ba743671 100644 --- a/src/Search/Repository/SavedSearchConfigurationRepository.php +++ b/src/Search/Repository/SavedSearchConfigurationRepository.php @@ -42,12 +42,20 @@ public function getById(int $id): SavedSearchConfiguration return $configuration; } - public function getList(?string $searchTerm): array + public function getList(?string $searchTerm, ?string $sortBy = null, ?string $sortOrder = null): array { + // Whitelist the sortable fields to keep the ORDER BY safe; default to newest first. + $sortField = match ($sortBy) { + 'name' => 'c.name', + 'modificationDate' => 'c.modificationDate', + default => 'c.modificationDate', + }; + $direction = strtoupper((string) $sortOrder) === 'ASC' ? 'ASC' : 'DESC'; + $queryBuilder = $this->entityManager->createQueryBuilder() ->select('c') ->from(SavedSearchConfiguration::class, 'c') - ->orderBy('c.modificationDate', 'DESC'); + ->orderBy($sortField, $direction); $searchTerm = $searchTerm !== null ? trim($searchTerm) : null; if ($searchTerm !== null && $searchTerm !== '') { diff --git a/src/Search/Repository/SavedSearchConfigurationRepositoryInterface.php b/src/Search/Repository/SavedSearchConfigurationRepositoryInterface.php index b2ad99a2a..fbc524a77 100644 --- a/src/Search/Repository/SavedSearchConfigurationRepositoryInterface.php +++ b/src/Search/Repository/SavedSearchConfigurationRepositoryInterface.php @@ -29,7 +29,7 @@ public function getById(int $id): SavedSearchConfiguration; /** * @return SavedSearchConfiguration[] */ - public function getList(?string $searchTerm): array; + public function getList(?string $searchTerm, ?string $sortBy = null, ?string $sortOrder = null): array; /** * @return SavedSearchConfiguration[] diff --git a/src/Search/Service/SavedSearchConfigurationService.php b/src/Search/Service/SavedSearchConfigurationService.php index c5ef14507..4da406958 100644 --- a/src/Search/Service/SavedSearchConfigurationService.php +++ b/src/Search/Service/SavedSearchConfigurationService.php @@ -53,14 +53,19 @@ public function __construct( ) { } - public function listConfigurations(CollectionParameters $parameters, ?string $searchTerm): Collection - { + public function listConfigurations( + CollectionParameters $parameters, + ?string $searchTerm, + ?string $sortBy = null, + ?string $sortOrder = null, + ): Collection { $currentUser = $this->securityService->getCurrentUser(); $userId = $currentUser->getId(); + // The repository applies the ORDER BY; the share filter below preserves that order. $accessibleConfigurations = array_values( array_filter( - $this->repository->getList($searchTerm), + $this->repository->getList($searchTerm, $sortBy, $sortOrder), fn (SavedSearchConfiguration $configuration): bool => $this->shareService ->isConfigurationSharedWithUser($configuration, $currentUser) ) diff --git a/src/Search/Service/SavedSearchConfigurationServiceInterface.php b/src/Search/Service/SavedSearchConfigurationServiceInterface.php index 61b8f23bf..954dfa405 100644 --- a/src/Search/Service/SavedSearchConfigurationServiceInterface.php +++ b/src/Search/Service/SavedSearchConfigurationServiceInterface.php @@ -31,7 +31,12 @@ interface SavedSearchConfigurationServiceInterface /** * @return Collection */ - public function listConfigurations(CollectionParameters $parameters, ?string $searchTerm): Collection; + public function listConfigurations( + CollectionParameters $parameters, + ?string $searchTerm, + ?string $sortBy = null, + ?string $sortOrder = null, + ): Collection; /** * @return Collection