diff --git a/config/api_resources/nsarticle.yml b/config/api_resources/nsarticle.yml index b9b68e3b..d46ced1d 100644 --- a/config/api_resources/nsarticle.yml +++ b/config/api_resources/nsarticle.yml @@ -2,8 +2,9 @@ App\GeneratedEntity\NSArticle: types: - Article operations: - ApiPlatform\Metadata\GetCollection: + article_get_collection: method: GET + class: ApiPlatform\Metadata\GetCollection shortName: Article normalizationContext: enable_max_depth: true @@ -16,7 +17,7 @@ App\GeneratedEntity\NSArticle: - document_display - document_thumbnails - document_display_sources - _api_article_archives: + article_archives_collection: method: GET class: ApiPlatform\Metadata\GetCollection shortName: Article @@ -25,8 +26,9 @@ App\GeneratedEntity\NSArticle: archive_enabled: true openapiContext: summary: 'Retrieve all Article ressources archives months and years' - ApiPlatform\Metadata\Get: + article_get: method: GET + class: ApiPlatform\Metadata\Get shortName: Article normalizationContext: groups: @@ -38,7 +40,7 @@ App\GeneratedEntity\NSArticle: - document_display - document_thumbnails - document_display_sources - getByPath: + article_get_by_path: method: GET class: ApiPlatform\Metadata\Get uriTemplate: /web_response_by_path diff --git a/config/api_resources/nsarticlecontainer.yml b/config/api_resources/nsarticlecontainer.yml index f3fabcf8..d914c2f9 100644 --- a/config/api_resources/nsarticlecontainer.yml +++ b/config/api_resources/nsarticlecontainer.yml @@ -2,8 +2,9 @@ App\GeneratedEntity\NSArticleContainer: types: - ArticleContainer operations: - ApiPlatform\Metadata\GetCollection: + articlecontainer_get_collection: method: GET + class: ApiPlatform\Metadata\GetCollection shortName: ArticleContainer normalizationContext: enable_max_depth: true @@ -16,8 +17,9 @@ App\GeneratedEntity\NSArticleContainer: - document_display - document_thumbnails - document_display_sources - ApiPlatform\Metadata\Get: + articlecontainer_get: method: GET + class: ApiPlatform\Metadata\Get shortName: ArticleContainer normalizationContext: groups: @@ -29,7 +31,7 @@ App\GeneratedEntity\NSArticleContainer: - document_display - document_thumbnails - document_display_sources - getByPath: + articlecontainer_get_by_path: method: GET class: ApiPlatform\Metadata\Get uriTemplate: /web_response_by_path diff --git a/config/api_resources/nsarticlefeedblock.yml b/config/api_resources/nsarticlefeedblock.yml index 1c2b35a0..16381af4 100644 --- a/config/api_resources/nsarticlefeedblock.yml +++ b/config/api_resources/nsarticlefeedblock.yml @@ -2,8 +2,9 @@ App\GeneratedEntity\NSArticleFeedBlock: types: - ArticleFeedBlock operations: - ApiPlatform\Metadata\Get: + articlefeedblock_get: method: GET + class: ApiPlatform\Metadata\Get shortName: ArticleFeedBlock normalizationContext: groups: diff --git a/config/api_resources/nsbasicblock.yml b/config/api_resources/nsbasicblock.yml index 6f9976b3..32fea5d0 100644 --- a/config/api_resources/nsbasicblock.yml +++ b/config/api_resources/nsbasicblock.yml @@ -2,12 +2,14 @@ App\GeneratedEntity\NSBasicBlock: types: - BasicBlock operations: - ApiPlatform\Metadata\Get: + basicblock_get: method: GET + class: ApiPlatform\Metadata\Get shortName: BasicBlock normalizationContext: groups: - nodes_sources + - node_listing - urls - tag_base - translation_base diff --git a/config/api_resources/nsgroupblock.yml b/config/api_resources/nsgroupblock.yml index d718be4f..ac048de7 100644 --- a/config/api_resources/nsgroupblock.yml +++ b/config/api_resources/nsgroupblock.yml @@ -2,12 +2,14 @@ App\GeneratedEntity\NSGroupBlock: types: - GroupBlock operations: - ApiPlatform\Metadata\Get: + groupblock_get: method: GET + class: ApiPlatform\Metadata\Get shortName: GroupBlock normalizationContext: groups: - nodes_sources + - node_listing - urls - tag_base - translation_base diff --git a/config/api_resources/nsmenu.yml b/config/api_resources/nsmenu.yml index f24b6e8a..0dfa6d5b 100644 --- a/config/api_resources/nsmenu.yml +++ b/config/api_resources/nsmenu.yml @@ -2,12 +2,14 @@ App\GeneratedEntity\NSMenu: types: - Menu operations: - ApiPlatform\Metadata\Get: + menu_get: method: GET + class: ApiPlatform\Metadata\Get shortName: Menu normalizationContext: groups: - nodes_sources + - node_listing - urls - tag_base - translation_base diff --git a/config/api_resources/nsmenulink.yml b/config/api_resources/nsmenulink.yml index 1ab52a2b..c8a7cee2 100644 --- a/config/api_resources/nsmenulink.yml +++ b/config/api_resources/nsmenulink.yml @@ -2,12 +2,14 @@ App\GeneratedEntity\NSMenuLink: types: - MenuLink operations: - ApiPlatform\Metadata\Get: + menulink_get: method: GET + class: ApiPlatform\Metadata\Get shortName: MenuLink normalizationContext: groups: - nodes_sources + - node_listing - urls - tag_base - translation_base diff --git a/config/api_resources/nsneutral.yml b/config/api_resources/nsneutral.yml index 7bd3dcdb..56e0245f 100644 --- a/config/api_resources/nsneutral.yml +++ b/config/api_resources/nsneutral.yml @@ -2,12 +2,14 @@ App\GeneratedEntity\NSNeutral: types: - Neutral operations: - ApiPlatform\Metadata\Get: + neutral_get: method: GET + class: ApiPlatform\Metadata\Get shortName: Neutral normalizationContext: groups: - nodes_sources + - node_listing - urls - tag_base - translation_base diff --git a/config/api_resources/nsoffer.yml b/config/api_resources/nsoffer.yml index 297d06fe..cf443bfe 100644 --- a/config/api_resources/nsoffer.yml +++ b/config/api_resources/nsoffer.yml @@ -2,8 +2,9 @@ App\GeneratedEntity\NSOffer: types: - Offer operations: - ApiPlatform\Metadata\GetCollection: + offer_get_collection: method: GET + class: ApiPlatform\Metadata\GetCollection shortName: Offer normalizationContext: enable_max_depth: true @@ -16,19 +17,21 @@ App\GeneratedEntity\NSOffer: - document_display - document_thumbnails - document_display_sources - ApiPlatform\Metadata\Get: + offer_get: method: GET + class: ApiPlatform\Metadata\Get shortName: Offer normalizationContext: groups: - nodes_sources + - node_listing - urls - tag_base - translation_base - document_display - document_thumbnails - document_display_sources - getByPath: + offer_get_by_path: method: GET class: ApiPlatform\Metadata\Get uriTemplate: /web_response_by_path @@ -39,6 +42,7 @@ App\GeneratedEntity\NSOffer: enable_max_depth: true groups: - nodes_sources + - node_listing - urls - tag_base - translation_base diff --git a/config/api_resources/nspage.yml b/config/api_resources/nspage.yml index edbd2393..85b77e27 100644 --- a/config/api_resources/nspage.yml +++ b/config/api_resources/nspage.yml @@ -2,8 +2,9 @@ App\GeneratedEntity\NSPage: types: - Page operations: - ApiPlatform\Metadata\GetCollection: + page_get_collection: method: GET + class: ApiPlatform\Metadata\GetCollection shortName: Page normalizationContext: enable_max_depth: true @@ -18,7 +19,8 @@ App\GeneratedEntity\NSPage: - document_display_sources - nodes_sources_images - nodes_sources_boolean - _api_page_archives: + - nodes_sources_geo + page_archives_collection: method: GET class: ApiPlatform\Metadata\GetCollection shortName: Page @@ -27,8 +29,9 @@ App\GeneratedEntity\NSPage: archive_enabled: true openapiContext: summary: 'Retrieve all Page ressources archives months and years' - ApiPlatform\Metadata\Get: + page_get: method: GET + class: ApiPlatform\Metadata\Get shortName: Page normalizationContext: groups: @@ -42,7 +45,8 @@ App\GeneratedEntity\NSPage: - document_display_sources - nodes_sources_images - nodes_sources_boolean - getByPath: + - nodes_sources_geo + page_get_by_path: method: GET class: ApiPlatform\Metadata\Get uriTemplate: /web_response_by_path @@ -62,6 +66,7 @@ App\GeneratedEntity\NSPage: - document_display_sources - nodes_sources_images - nodes_sources_boolean + - nodes_sources_geo - web_response - walker - walker_level diff --git a/config/api_resources/web_response.yml b/config/api_resources/web_response.yml index 8e9ddb30..cf9513c9 100644 --- a/config/api_resources/web_response.yml +++ b/config/api_resources/web_response.yml @@ -25,7 +25,7 @@ RZ\Roadiz\CoreBundle\Api\Model\WebResponse: - tag_base - translation_base - document_display - #- node_attributes + - node_attributes - document_display_sources openapiContext: summary: Get a resource by its path wrapped in a WebResponse object diff --git a/lib/RoadizCoreBundle/src/Api/Controller/GetWebResponseByPathController.php b/lib/RoadizCoreBundle/src/Api/Controller/GetWebResponseByPathController.php index eee75100..87523f85 100644 --- a/lib/RoadizCoreBundle/src/Api/Controller/GetWebResponseByPathController.php +++ b/lib/RoadizCoreBundle/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/lib/RoadizCoreBundle/src/NodeType/ApiResourceGenerator.php b/lib/RoadizCoreBundle/src/NodeType/ApiResourceGenerator.php index 548ae63d..d42bfc0b 100644 --- a/lib/RoadizCoreBundle/src/NodeType/ApiResourceGenerator.php +++ b/lib/RoadizCoreBundle/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/lib/RoadizCoreBundle/src/NodeType/ApiResourceOperationNameGenerator.php b/lib/RoadizCoreBundle/src/NodeType/ApiResourceOperationNameGenerator.php new file mode 100644 index 00000000..bd3da5fa --- /dev/null +++ b/lib/RoadizCoreBundle/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'); + } +}