Skip to content

Commit

Permalink
feat: Create different operation names for each Entity with WebResponse.
Browse files Browse the repository at this point in the history
  • Loading branch information
roadiz-ci committed Feb 12, 2024
1 parent deef9ce commit 5ada723
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 37 deletions.
49 changes: 27 additions & 22 deletions src/Api/Controller/GetWebResponseByPathController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -93,21 +99,20 @@ 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
*/
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 ]);
Expand Down
48 changes: 33 additions & 15 deletions src/NodeType/ApiResourceGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
) {
}

/**
Expand Down Expand Up @@ -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,
Expand All @@ -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' => [
Expand Down Expand Up @@ -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)))
Expand All @@ -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,
Expand Down
28 changes: 28 additions & 0 deletions src/NodeType/ApiResourceOperationNameGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\NodeType;

use Symfony\Component\String\UnicodeString;

final class ApiResourceOperationNameGenerator
{
public function generate(string $resourceClass, string $operation): string
{
return sprintf(
'%s_%s',
(new UnicodeString($resourceClass))
->afterLast('\\')
->trimPrefix('NS')
->lower()
->toString(),
$operation
);
}

public function generateGetByPath(string $resourceClass): string
{
return self::generate($resourceClass, 'get_by_path');
}
}

0 comments on commit 5ada723

Please sign in to comment.