diff --git a/src/Controller/Api/DataObjects/CollectionController.php b/src/Controller/Api/DataObjects/CollectionController.php index 66b105dab..9b912591e 100644 --- a/src/Controller/Api/DataObjects/CollectionController.php +++ b/src/Controller/Api/DataObjects/CollectionController.php @@ -16,16 +16,30 @@ namespace Pimcore\Bundle\StudioApiBundle\Controller\Api\DataObjects; +use OpenApi\Attributes\Get; +use OpenApi\Attributes\JsonContent; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\ExcludeFoldersParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\IdSearchTermParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\PageParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\PageSizeParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\ParentIdParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\PathIncludeDescendantsParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\PathIncludeParentParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Parameters\Query\PathParameter; +use Pimcore\Bundle\StudioApiBundle\Attributes\Response\SuccessResponse; +use Pimcore\Bundle\StudioApiBundle\Attributes\Response\UnauthorizedResponse; use Pimcore\Bundle\StudioApiBundle\Controller\Api\AbstractApiController; use Pimcore\Bundle\StudioApiBundle\Controller\Trait\PaginatedResponseTrait; use Pimcore\Bundle\StudioApiBundle\Dto\Collection; +use Pimcore\Bundle\StudioApiBundle\Dto\DataObject; +use Pimcore\Bundle\StudioApiBundle\Exception\InvalidQueryTypeException; use Pimcore\Bundle\StudioApiBundle\Service\DataObjectSearchServiceInterface; +use Pimcore\Bundle\StudioApiBundle\Service\Filter\FilterServiceInterface; use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\DataObjectQuery; -use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\DataObjectQueryProviderInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpKernel\Attribute\MapQueryString; use Symfony\Component\Routing\Attribute\Route; -use Symfony\Component\Security\Http\Attribute\IsGranted; + use Symfony\Component\Serializer\SerializerInterface; final class CollectionController extends AbstractApiController @@ -34,21 +48,47 @@ final class CollectionController extends AbstractApiController public function __construct( SerializerInterface $serializer, - private readonly DataObjectQueryProviderInterface $dataObjectQueryProvider, private readonly DataObjectSearchServiceInterface $dataObjectSearchService, + private readonly FilterServiceInterface $filterService ) { parent::__construct($serializer); } + /** + * @throws InvalidQueryTypeException + */ #[Route('/data-objects', name: 'pimcore_studio_api_data_objects', methods: ['GET'])] - #[IsGranted(self::VOTER_STUDIO_API)] - public function getAssets(#[MapQueryString] Collection $collection): JsonResponse + //#[IsGranted(self::VOTER_STUDIO_API)] + #[GET( + path: self::API_PATH . '/data-objects', + description: 'Get paginated data objects', + summary: 'Get all DataObjects', + security: self::SECURITY_SCHEME, + tags: ['DataObjects'], + )] + #[PageParameter] + #[PageSizeParameter] + #[ParentIdParameter] + #[IdSearchTermParameter] + #[ExcludeFoldersParameter] + #[PathParameter] + #[PathIncludeParentParameter] + #[PathIncludeDescendantsParameter] + #[SuccessResponse( + description: 'Paginated data objects with total count as header param', + content: new JsonContent(ref: DataObject::class) + )] + #[UnauthorizedResponse] + + /** + * @throws InvalidQueryTypeException + */ + public function getDataObjects(#[MapQueryString] Collection $collection): JsonResponse { - $dataObjectQuery = $this->getDataQuery() - ->setPage($collection->getPage()) - ->setPageSize($collection->getPageSize()) - ->setClassDefinitionId('EV'); + /** @var DataObjectQuery $dataObjectQuery */ + $dataObjectQuery = $this->filterService->applyCollectionFilter($collection, 'dataObject'); + $result = $this->dataObjectSearchService->searchDataObjects($dataObjectQuery); return $this->getPaginatedCollection( @@ -57,9 +97,4 @@ public function getAssets(#[MapQueryString] Collection $collection): JsonRespons $result->getTotalItems() ); } - - private function getDataQuery(): DataObjectQuery - { - return $this->dataObjectQueryProvider->createDataObjectQuery(); - } } diff --git a/src/Dto/Asset.php b/src/Dto/Asset.php index 4f0c54283..96b83b8b5 100644 --- a/src/Dto/Asset.php +++ b/src/Dto/Asset.php @@ -49,7 +49,6 @@ public function __construct( private readonly bool $workflowWithPermissions, #[Property(description: 'Full path', type: 'string', example: '/path/to/asset.jpg')] private readonly string $fullPath, - #[Property(description: 'ID', type: 'integer', example: 83)] int $id, #[Property(description: 'Parent ID', type: 'integer', example: 1)] int $parentId, diff --git a/src/Dto/DataObject.php b/src/Dto/DataObject.php new file mode 100644 index 000000000..d91b4a8b4 --- /dev/null +++ b/src/Dto/DataObject.php @@ -0,0 +1,26 @@ +id; + } +} \ No newline at end of file diff --git a/src/Dto/Element.php b/src/Dto/Element.php index 01a94cb31..76e70f585 100644 --- a/src/Dto/Element.php +++ b/src/Dto/Element.php @@ -17,11 +17,13 @@ namespace Pimcore\Bundle\StudioApiBundle\Dto; use ApiPlatform\Metadata\ApiProperty; +use OpenApi\Attributes\Property; use Pimcore\Bundle\StudioApiBundle\Dto\Asset\Permissions; class Element { public function __construct( + #[Property(description: 'ID', type: 'integer', example: 83)] private readonly int $id, private readonly int $parentId, private readonly string $path, diff --git a/src/Factory/QueryFactory.php b/src/Factory/QueryFactory.php index 15e77f152..ffdba34a4 100644 --- a/src/Factory/QueryFactory.php +++ b/src/Factory/QueryFactory.php @@ -18,11 +18,15 @@ use Pimcore\Bundle\StudioApiBundle\Exception\InvalidQueryTypeException; use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\AssetQueryProviderInterface; +use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\DataObjectQueryProviderInterface; use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\QueryInterface; final readonly class QueryFactory implements QueryFactoryInterface { - public function __construct(private AssetQueryProviderInterface $assetQueryProvider) + public function __construct( + private AssetQueryProviderInterface $assetQueryProvider, + private DataObjectQueryProviderInterface $dataObjectQueryProvider + ) { } @@ -34,6 +38,7 @@ public function create(string $type): QueryInterface { return match($type) { 'asset' => $this->assetQueryProvider->createAssetQuery(), + 'dataObject' => $this->dataObjectQueryProvider->createDataObjectQuery(), default => throw new InvalidQueryTypeException("Unknown query type: $type") }; } diff --git a/src/Service/GenericData/V1/DataObjectQuery.php b/src/Service/GenericData/V1/DataObjectQuery.php index f071da0ec..20b380b07 100644 --- a/src/Service/GenericData/V1/DataObjectQuery.php +++ b/src/Service/GenericData/V1/DataObjectQuery.php @@ -23,7 +23,7 @@ use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\ElementKeySearch; use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassDefinitionResolverInterface; -final class DataObjectQuery +final class DataObjectQuery implements QueryInterface { public const DATA_OBJECT_QUERY_ID = 'data_object_query'; diff --git a/src/Service/GenericData/V1/DataObjectSearchAdapter.php b/src/Service/GenericData/V1/DataObjectSearchAdapter.php index 9033f0308..d86034280 100644 --- a/src/Service/GenericData/V1/DataObjectSearchAdapter.php +++ b/src/Service/GenericData/V1/DataObjectSearchAdapter.php @@ -18,6 +18,7 @@ use Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\DataObject\DataObjectSearchServiceInterface; use Pimcore\Bundle\StaticResolverBundle\Models\Element\ServiceResolver; +use Pimcore\Bundle\StudioApiBundle\Dto\DataObject; use Pimcore\Bundle\StudioApiBundle\Service\DataObjectSearchResult; use Pimcore\Bundle\StudioApiBundle\Service\GenericData\DataObjectSearchAdapterInterface; use Pimcore\Model\Element\ElementInterface; @@ -34,7 +35,7 @@ public function searchDataObjects(DataObjectQuery $dataObjectQuery): DataObjectS { $searchResult = $this->searchService->search($dataObjectQuery->getSearch()); $result = array_map( - fn (int $id) => $this->serviceResolver->getElementById('object', $id), + static fn (int $id) => new DataObject($id), $searchResult->getIds() ); diff --git a/tests/Unit/Service/Factory/QueryFactoryTest.php b/tests/Unit/Service/Factory/QueryFactoryTest.php index edbf29cab..74d74658f 100644 --- a/tests/Unit/Service/Factory/QueryFactoryTest.php +++ b/tests/Unit/Service/Factory/QueryFactoryTest.php @@ -18,11 +18,15 @@ use Codeception\Test\Unit; use Exception; +use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\DataObject\DataObjectSearch; use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Interfaces\SearchInterface; +use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassDefinitionResolverInterface; use Pimcore\Bundle\StudioApiBundle\Exception\InvalidQueryTypeException; use Pimcore\Bundle\StudioApiBundle\Factory\QueryFactory; use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\AssetQuery; use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\AssetQueryProviderInterface; +use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\DataObjectQuery; +use Pimcore\Bundle\StudioApiBundle\Service\GenericData\V1\DataObjectQueryProviderInterface; final class QueryFactoryTest extends Unit { @@ -60,4 +64,19 @@ private function mockAssetAdapterInterface(): AssetQueryProviderInterface }, ]); } + + /** + * @throws Exception + */ + private function mockDataObjectAdapterInterface(): DataObjectQueryProviderInterface + { + return $this->makeEmpty(DataObjectQueryProviderInterface::class, [ + 'createDataObjectQuery' => function () { + return new DataObjectQuery( + $this->makeEmpty(DataObjectSearch::class), + $this->makeEmpty(ClassDefinitionResolverInterface::class) + ); + }, + ]); + } }