From 5ada7230d9f25bac345807c1cdfe034ff5e4b292 Mon Sep 17 00:00:00 2001 From: roadiz-ci Date: Mon, 12 Feb 2024 19:01:52 +0000 Subject: [PATCH] feat: Create different operation names for each Entity with WebResponse. --- .../GetWebResponseByPathController.php | 49 ++++++++++--------- src/NodeType/ApiResourceGenerator.php | 48 ++++++++++++------ .../ApiResourceOperationNameGenerator.php | 28 +++++++++++ 3 files changed, 88 insertions(+), 37 deletions(-) create mode 100644 src/NodeType/ApiResourceOperationNameGenerator.php diff --git a/src/Api/Controller/GetWebResponseByPathController.php b/src/Api/Controller/GetWebResponseByPathController.php index eee75100..87523f85 100644 --- a/src/Api/Controller/GetWebResponseByPathController.php +++ b/src/Api/Controller/GetWebResponseByPathController.php @@ -6,59 +6,65 @@ use ApiPlatform\Api\IriConverterInterface; use ApiPlatform\Exception\InvalidArgumentException; +use ApiPlatform\Exception\OperationNotFoundException; +use ApiPlatform\Exception\ResourceClassNotFoundException; +use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; +use Psr\Log\LoggerInterface; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\CoreBundle\Api\DataTransformer\WebResponseDataTransformerInterface; use RZ\Roadiz\CoreBundle\Api\Model\WebResponseInterface; use RZ\Roadiz\CoreBundle\Entity\Redirection; +use RZ\Roadiz\CoreBundle\NodeType\ApiResourceOperationNameGenerator; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; use RZ\Roadiz\CoreBundle\Routing\PathResolverInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\String\UnicodeString; final class GetWebResponseByPathController extends AbstractController { public function __construct( - private readonly RequestStack $requestStack, private readonly PathResolverInterface $pathResolver, private readonly WebResponseDataTransformerInterface $webResponseDataTransformer, private readonly IriConverterInterface $iriConverter, - private readonly PreviewResolverInterface $previewResolver + private readonly PreviewResolverInterface $previewResolver, + private readonly ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator, ) { } - public function __invoke(): ?WebResponseInterface + public function __invoke(?Request $request): ?WebResponseInterface { try { if ( - null === $this->requestStack->getMainRequest() || - empty($this->requestStack->getMainRequest()->query->get('path')) + null === $request || + empty($request->query->get('path')) ) { throw new InvalidArgumentException('path query parameter is mandatory'); } $resource = $this->normalizeResourcePath( - (string) $this->requestStack->getMainRequest()->query->get('path') + $request, + (string) $request->query->get('path') ); - $this->requestStack->getMainRequest()->attributes->set('data', $resource); - $this->requestStack->getMainRequest()->attributes->set('id', $resource->getId()); + $request->attributes->set('data', $resource); + $request->attributes->set('id', $resource->getId()); /* * Force API Platform to look for real resource configuration and serialization - * context. You must define "itemOperations.getByPath" for your API resource configuration. + * context. You must define "%entity%_get_by_path" operation for your API resource configuration. */ - $this->requestStack->getMainRequest()->attributes->set('_api_resource_class', get_class($resource)); + $resourceClass = get_class($resource); + $operationName = $this->apiResourceOperationNameGenerator->generateGetByPath($resourceClass); + + $request->attributes->set('_api_operation_name', $operationName); + $request->attributes->set('_api_resource_class', $resourceClass); + $request->attributes->set('_stateless', true); return $this->webResponseDataTransformer->transform($resource, WebResponseInterface::class); } catch (ResourceNotFoundException $exception) { - throw new NotFoundHttpException($exception->getMessage(), $exception); + throw $this->createNotFoundException($exception->getMessage(), $exception); } } - /** - * @param string $path - * @return PersistableInterface - */ - protected function normalizeResourcePath(string $path): PersistableInterface + protected function normalizeResourcePath(?Request $request, string $path): PersistableInterface { /* * Serve any PersistableInterface Resource by implementing @@ -93,11 +99,11 @@ protected function normalizeResourcePath(string $path): PersistableInterface * Recursive call to normalize path coming from Redirection if redirected path * is internal (starting with /) */ - return $this->normalizeResourcePath($resource->getRedirectUri()); + return $this->normalizeResourcePath($request, $resource->getRedirectUri()); } } - $this->addResourceToCacheTags($resource); + $this->addResourceToCacheTags($request, $resource); /* * Or plain entity @@ -105,9 +111,8 @@ protected function normalizeResourcePath(string $path): PersistableInterface return $resource; } - protected function addResourceToCacheTags(PersistableInterface $resource): void + protected function addResourceToCacheTags(?Request $request, PersistableInterface $resource): void { - $request = $this->requestStack->getMainRequest(); if (null !== $request) { $iri = $this->iriConverter->getIriFromResource($resource); $request->attributes->set('_resources', $request->attributes->get('_resources', []) + [ $iri => $iri ]); diff --git a/src/NodeType/ApiResourceGenerator.php b/src/NodeType/ApiResourceGenerator.php index 548ae63d..d42bfc0b 100644 --- a/src/NodeType/ApiResourceGenerator.php +++ b/src/NodeType/ApiResourceGenerator.php @@ -4,23 +4,24 @@ namespace RZ\Roadiz\CoreBundle\NodeType; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; use Doctrine\Inflector\InflectorFactory; use LogicException; use Psr\Log\LoggerInterface; use RZ\Roadiz\Contracts\NodeType\NodeTypeInterface; +use RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\String\UnicodeString; use Symfony\Component\Yaml\Yaml; final class ApiResourceGenerator { - private string $apiResourcesDir; - private LoggerInterface $logger; - - public function __construct(string $apiResourcesDir, LoggerInterface $logger) - { - $this->apiResourcesDir = $apiResourcesDir; - $this->logger = $logger; + public function __construct( + private readonly ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator, + private readonly string $apiResourcesDir, + private readonly LoggerInterface $logger + ) { } /** @@ -126,11 +127,17 @@ protected function getCollectionOperations(NodeTypeInterface $nodeType): array "document_display_sources", ...$this->getGroupedFieldsSerializationGroups($nodeType) ]; + + $collectionOperationName = $this->apiResourceOperationNameGenerator->generate( + $nodeType->getSourceEntityFullQualifiedClassName(), + 'get_collection' + ); $operations = array_merge( $operations, [ - 'ApiPlatform\Metadata\GetCollection' => [ + $collectionOperationName => [ 'method' => 'GET', + 'class' => GetCollection::class, 'shortName' => $nodeType->getName(), 'normalizationContext' => [ 'enable_max_depth' => true, @@ -141,13 +148,16 @@ protected function getCollectionOperations(NodeTypeInterface $nodeType): array ); } if ($nodeType->isPublishable()) { - $archivesRouteName = '_api_' . $this->getResourceName($nodeType->getName()) . '_archives'; + $archivesOperationName = $this->apiResourceOperationNameGenerator->generate( + $nodeType->getSourceEntityFullQualifiedClassName(), + 'archives_collection' + ); $operations = array_merge( $operations, [ - $archivesRouteName => [ + $archivesOperationName => [ 'method' => 'GET', - 'class' => 'ApiPlatform\Metadata\GetCollection', + 'class' => GetCollection::class, 'shortName' => $nodeType->getName(), 'uriTemplate' => $this->getResourceUriPrefix($nodeType) . '/archives', 'extraProperties' => [ @@ -179,9 +189,14 @@ protected function getItemOperations(NodeTypeInterface $nodeType): array "document_display_sources", ...$this->getGroupedFieldsSerializationGroups($nodeType) ]; + $itemOperationName = $this->apiResourceOperationNameGenerator->generate( + $nodeType->getSourceEntityFullQualifiedClassName(), + 'get' + ); $operations = [ - 'ApiPlatform\Metadata\Get' => [ + $itemOperationName => [ 'method' => 'GET', + 'class' => Get::class, 'shortName' => $nodeType->getName(), 'normalizationContext' => [ 'groups' => array_values(array_filter(array_unique($groups))) @@ -193,12 +208,15 @@ protected function getItemOperations(NodeTypeInterface $nodeType): array * Create itemOperation for WebResponseController action */ if ($nodeType->isReachable()) { - $operations['getByPath'] = [ + $operationName = $this->apiResourceOperationNameGenerator->generateGetByPath( + $nodeType->getSourceEntityFullQualifiedClassName() + ); + $operations[$operationName] = [ 'method' => 'GET', - 'class' => 'ApiPlatform\Metadata\Get', + 'class' => Get::class, 'uriTemplate' => '/web_response_by_path', 'read' => false, - 'controller' => 'RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController', + 'controller' => GetWebResponseByPathController::class, 'normalizationContext' => [ 'pagination_enabled' => false, 'enable_max_depth' => true, diff --git a/src/NodeType/ApiResourceOperationNameGenerator.php b/src/NodeType/ApiResourceOperationNameGenerator.php new file mode 100644 index 00000000..bd3da5fa --- /dev/null +++ b/src/NodeType/ApiResourceOperationNameGenerator.php @@ -0,0 +1,28 @@ +afterLast('\\') + ->trimPrefix('NS') + ->lower() + ->toString(), + $operation + ); + } + + public function generateGetByPath(string $resourceClass): string + { + return self::generate($resourceClass, 'get_by_path'); + } +}