diff --git a/.env.test b/.env.test
new file mode 100644
index 00000000..9e7162f0
--- /dev/null
+++ b/.env.test
@@ -0,0 +1,6 @@
+# define your env variables for the test env here
+KERNEL_CLASS='App\Kernel'
+APP_SECRET='$ecretf0rt3st'
+SYMFONY_DEPRECATIONS_HELPER=999999
+PANTHER_APP_ENV=panther
+PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
diff --git a/config/api_resources/web_response.yml b/config/api_resources/web_response.yml
index cf9513c9..6a903423 100644
--- a/config/api_resources/web_response.yml
+++ b/config/api_resources/web_response.yml
@@ -1,41 +1,2 @@
RZ\Roadiz\CoreBundle\Api\Model\WebResponse:
- operations:
- getByPath:
- class: ApiPlatform\Metadata\Get
- method: 'GET'
- uriTemplate: '/web_response_by_path'
- read: false
- controller: RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController
- pagination_enabled: false
- normalizationContext:
- enable_max_depth: true
- pagination_enabled: false
- groups:
- - get
- - web_response
- - position
- - walker
- - walker_level
- - meta
- - children
- - children_count
- - nodes_sources
- - node_listing
- - urls
- - tag_base
- - translation_base
- - document_display
- - node_attributes
- - document_display_sources
- openapiContext:
- summary: Get a resource by its path wrapped in a WebResponse object
- description: |
- Get a resource by its path wrapped in a WebResponse
- parameters:
- - type: string
- name: path
- in: query
- required: true
- description: Resource path, or `/` for home page
- schema:
- type: string
+ operations: []
diff --git a/config/services.yaml b/config/services.yaml
index 32653476..64f8df1a 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -50,6 +50,7 @@ services:
$maxVersionsShowed: '%roadiz_core.max_versions_showed%'
$recaptchaPublicKey: '%roadiz_core.medias.recaptcha_public_key%'
$recaptchaPrivateKey: '%roadiz_core.medias.recaptcha_private_key%'
+ $webResponseClass: '%roadiz_core.web_response_class%'
RZ\Roadiz\CoreBundle\:
resource: '../src/'
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 00000000..c0f0120e
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ src/Test
+
+
+
+
+
+ src
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Api/Controller/GetWebResponseByPathController.php b/src/Api/Controller/GetWebResponseByPathController.php
index 60c75c60..d6ecf84b 100644
--- a/src/Api/Controller/GetWebResponseByPathController.php
+++ b/src/Api/Controller/GetWebResponseByPathController.php
@@ -7,7 +7,9 @@
use ApiPlatform\Api\IriConverterInterface;
use ApiPlatform\Exception\InvalidArgumentException;
use ApiPlatform\Exception\ResourceClassNotFoundException;
+use ApiPlatform\Metadata\Exception\OperationNotFoundException;
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;
@@ -30,6 +32,7 @@ public function __construct(
private readonly IriConverterInterface $iriConverter,
private readonly PreviewResolverInterface $previewResolver,
private readonly ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator,
+ private readonly LoggerInterface $logger
) {
}
@@ -46,18 +49,34 @@ public function __invoke(?Request $request): ?WebResponseInterface
$request,
(string) $request->query->get('path')
);
- $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 "%entity%_get_by_path" operation for your API resource configuration.
- */
- $resourceClass = get_class($resource);
- $operationName = $this->apiResourceOperationNameGenerator->generateGetByPath($resourceClass);
- $operation = $this->resourceMetadataCollectionFactory->create($resourceClass)->getOperation($operationName);
- $request->attributes->set('_api_operation', $operation);
- $request->attributes->set('_api_operation_name', $operationName);
- $request->attributes->set('_api_resource_class', $resourceClass);
+ $request->attributes->set('path', (string) $request->query->get('path'));
+ $request->attributes->set('_route_params', [
+ ...$request->attributes->get('_route_params', []),
+ 'path' => (string) $request->query->get('path'),
+ ]);
+
+ try {
+ /*
+ * Force API Platform to look for real resource configuration and serialization
+ * context. You must define "%entity%_get_by_path" operation for your WebResponse resource configuration.
+ * It should be generated automatically by Roadiz when you create new reachable NodeTypes.
+ */
+ $resourceClass = get_class($resource);
+ $operationName = $this->apiResourceOperationNameGenerator->generateGetByPath($resourceClass);
+ $webResponseClass = $request->attributes->get('_api_resource_class');
+ $operation = $this->resourceMetadataCollectionFactory
+ ->create($webResponseClass)
+ ->getOperation($operationName);
+ $request->attributes->set('_api_operation', $operation);
+ $request->attributes->set('_web_response_item_class', $resourceClass);
+ $request->attributes->set('_api_operation_name', $operationName);
+ } catch (OperationNotFoundException $exception) {
+ // Do not fail if operation is not found
+ // But warn in logs about missing operation configuration for this resource
+ $this->logger->warning($exception->getMessage());
+ }
+
$request->attributes->set('_stateless', true);
if ($resource instanceof NodesSources) {
diff --git a/src/Api/DataTransformer/WebResponseDataTransformerInterface.php b/src/Api/DataTransformer/WebResponseDataTransformerInterface.php
index 1c4924b1..424d02a3 100644
--- a/src/Api/DataTransformer/WebResponseDataTransformerInterface.php
+++ b/src/Api/DataTransformer/WebResponseDataTransformerInterface.php
@@ -10,10 +10,11 @@
interface WebResponseDataTransformerInterface
{
/**
- * @param PersistableInterface $object
+ * @template T of PersistableInterface
+ * @param T $object
* @param string $to
* @param array $context
- * @return WebResponseInterface|null
+ * @return WebResponseInterface|null
*/
public function transform(PersistableInterface $object, string $to, array $context = []): ?WebResponseInterface;
diff --git a/src/Api/DataTransformer/WebResponseOutputDataTransformer.php b/src/Api/DataTransformer/WebResponseOutputDataTransformer.php
index d4d46109..7cd9a1e1 100644
--- a/src/Api/DataTransformer/WebResponseOutputDataTransformer.php
+++ b/src/Api/DataTransformer/WebResponseOutputDataTransformer.php
@@ -11,7 +11,6 @@
use RZ\Roadiz\CoreBundle\Api\Model\BlocksAwareWebResponseInterface;
use RZ\Roadiz\CoreBundle\Api\Model\NodesSourcesHeadFactoryInterface;
use RZ\Roadiz\CoreBundle\Api\Model\RealmsAwareWebResponseInterface;
-use RZ\Roadiz\CoreBundle\Api\Model\WebResponse;
use RZ\Roadiz\CoreBundle\Api\Model\WebResponseInterface;
use RZ\Roadiz\CoreBundle\Api\TreeWalker\AutoChildrenNodeSourceWalker;
use RZ\Roadiz\CoreBundle\Api\TreeWalker\TreeWalkerGenerator;
@@ -27,6 +26,16 @@ class WebResponseOutputDataTransformer implements WebResponseDataTransformerInte
use BlocksAwareWebResponseOutputDataTransformerTrait;
use RealmsAwareWebResponseOutputDataTransformerTrait;
+ /**
+ * @param NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory
+ * @param BreadcrumbsFactoryInterface $breadcrumbsFactory
+ * @param WalkerContextInterface $walkerContext
+ * @param CacheItemPoolInterface $cacheItemPool
+ * @param UrlGeneratorInterface $urlGenerator
+ * @param RealmResolverInterface $realmResolver
+ * @param TreeWalkerGenerator $treeWalkerGenerator
+ * @param class-string $webResponseClass
+ */
public function __construct(
protected readonly NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory,
protected readonly BreadcrumbsFactoryInterface $breadcrumbsFactory,
@@ -34,7 +43,8 @@ public function __construct(
protected readonly CacheItemPoolInterface $cacheItemPool,
protected readonly UrlGeneratorInterface $urlGenerator,
protected readonly RealmResolverInterface $realmResolver,
- protected readonly TreeWalkerGenerator $treeWalkerGenerator
+ protected readonly TreeWalkerGenerator $treeWalkerGenerator,
+ private readonly string $webResponseClass
) {
}
@@ -73,7 +83,7 @@ protected function getRealmResolver(): RealmResolverInterface
public function createWebResponse(): WebResponseInterface
{
- return new WebResponse();
+ return new ($this->webResponseClass)();
}
public function transform(PersistableInterface $object, string $to, array $context = []): ?WebResponseInterface
diff --git a/src/Api/Model/WebResponseInterface.php b/src/Api/Model/WebResponseInterface.php
index 8a43399b..61ff1727 100644
--- a/src/Api/Model/WebResponseInterface.php
+++ b/src/Api/Model/WebResponseInterface.php
@@ -7,12 +7,23 @@
use RZ\Roadiz\Core\AbstractEntities\PersistableInterface;
use RZ\Roadiz\CoreBundle\Api\Breadcrumbs\BreadcrumbsInterface;
+/**
+ * @template T of PersistableInterface
+ */
interface WebResponseInterface
{
public function setHead(?NodesSourcesHeadInterface $head): self;
public function setBreadcrumbs(?BreadcrumbsInterface $breadcrumbs): self;
+
+ /**
+ * @param T|null $item
+ * @return self
+ */
public function setItem(?PersistableInterface $item): self;
public function setPath(?string $path): self;
+ /**
+ * @return T|null
+ */
public function getItem(): ?PersistableInterface;
public function getMaxAge(): ?int;
public function setMaxAge(?int $maxAge): self;
diff --git a/src/Api/Model/WebResponseTrait.php b/src/Api/Model/WebResponseTrait.php
index 141afde7..8acf455f 100644
--- a/src/Api/Model/WebResponseTrait.php
+++ b/src/Api/Model/WebResponseTrait.php
@@ -14,7 +14,12 @@
trait WebResponseTrait
{
- #[ApiProperty(identifier: true)]
+ #[ApiProperty(
+ description: "The path of the current WebResponse.",
+ readable: true,
+ writable: false,
+ identifier: true
+ )]
public ?string $path = null;
#[Serializer\Groups(["web_response"])]
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 89834aef..ff7e7d64 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -4,6 +4,7 @@
namespace RZ\Roadiz\CoreBundle\DependencyInjection;
+use RZ\Roadiz\CoreBundle\Api\Model\WebResponse;
use RZ\Roadiz\CoreBundle\Controller\DefaultNodeSourceController;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
@@ -40,6 +41,9 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('defaultNodeSourceController')
->defaultValue(DefaultNodeSourceController::class)
->end()
+ ->scalarNode('webResponseClass')
+ ->defaultValue(WebResponse::class)
+ ->end()
->booleanNode('useNativeJsonColumnType')
->defaultValue(true)
->end()
diff --git a/src/DependencyInjection/RoadizCoreExtension.php b/src/DependencyInjection/RoadizCoreExtension.php
index 25442d1f..e0608f74 100644
--- a/src/DependencyInjection/RoadizCoreExtension.php
+++ b/src/DependencyInjection/RoadizCoreExtension.php
@@ -66,6 +66,7 @@ public function load(array $configs, ContainerBuilder $container): void
$container->setParameter('roadiz_core.use_typed_node_names', $config['useTypedNodeNames']);
$container->setParameter('roadiz_core.hide_roadiz_version', $config['hideRoadizVersion']);
$container->setParameter('roadiz_core.use_accept_language_header', $config['useAcceptLanguageHeader']);
+ $container->setParameter('roadiz_core.web_response_class', $config['webResponseClass']);
/*
* Assets config
diff --git a/src/NodeType/ApiResourceGenerator.php b/src/NodeType/ApiResourceGenerator.php
index d42bfc0b..4ab4ff65 100644
--- a/src/NodeType/ApiResourceGenerator.php
+++ b/src/NodeType/ApiResourceGenerator.php
@@ -11,16 +11,24 @@
use Psr\Log\LoggerInterface;
use RZ\Roadiz\Contracts\NodeType\NodeTypeInterface;
use RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController;
+use RZ\Roadiz\CoreBundle\Api\Model\WebResponseInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\String\UnicodeString;
use Symfony\Component\Yaml\Yaml;
final class ApiResourceGenerator
{
+ /**
+ * @param ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator
+ * @param string $apiResourcesDir
+ * @param LoggerInterface $logger
+ * @param class-string $webResponseClass
+ */
public function __construct(
private readonly ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator,
private readonly string $apiResourcesDir,
- private readonly LoggerInterface $logger
+ private readonly LoggerInterface $logger,
+ private readonly string $webResponseClass
) {
}
@@ -37,6 +45,26 @@ public function generate(NodeTypeInterface $nodeType): ?string
}
$resourcePath = $this->getResourcePath($nodeType);
+ $webResponseResourcePath = $this->getWebResponseResourcePath();
+
+ if (!$filesystem->exists($webResponseResourcePath)) {
+ $filesystem->dumpFile(
+ $webResponseResourcePath,
+ Yaml::dump([
+ $this->webResponseClass => [
+ 'operations' => [],
+ ]
+ ], 6)
+ );
+ }
+ $filesystem->dumpFile(
+ $webResponseResourcePath,
+ Yaml::dump($this->addWebResponseResourceOperation($nodeType, $webResponseResourcePath), 6)
+ );
+ $this->logger->info('API WebResponse config file has been updated.', [
+ 'file' => $webResponseResourcePath,
+ ]);
+ \clearstatcache(true, $webResponseResourcePath);
if (!$filesystem->exists($resourcePath)) {
$filesystem->dumpFile(
@@ -63,6 +91,18 @@ public function remove(NodeTypeInterface $nodeType): void
}
$resourcePath = $this->getResourcePath($nodeType);
+ $webResponseResourcePath = $this->getWebResponseResourcePath();
+
+ if ($filesystem->exists($webResponseResourcePath)) {
+ $filesystem->dumpFile(
+ $webResponseResourcePath,
+ Yaml::dump($this->removeWebResponseResourceOperation($nodeType, $webResponseResourcePath), 6)
+ );
+ $this->logger->info('API WebResponse config file has been updated.', [
+ 'file' => $webResponseResourcePath,
+ ]);
+ \clearstatcache(true, $webResponseResourcePath);
+ }
if ($filesystem->exists($resourcePath)) {
$filesystem->remove($resourcePath);
@@ -74,7 +114,7 @@ public function remove(NodeTypeInterface $nodeType): void
}
}
- protected function getResourcePath(NodeTypeInterface $nodeType): string
+ public function getResourcePath(NodeTypeInterface $nodeType): string
{
return $this->apiResourcesDir . '/' . (new UnicodeString($nodeType->getName()))
->lower()
@@ -83,6 +123,11 @@ protected function getResourcePath(NodeTypeInterface $nodeType): string
->toString();
}
+ protected function getWebResponseResourcePath(): string
+ {
+ return $this->apiResourcesDir . '/web_response.yml';
+ }
+
protected function getResourceName(string $nodeTypeName): string
{
return (new UnicodeString($nodeTypeName))
@@ -112,6 +157,104 @@ protected function getApiResourceDefinition(NodeTypeInterface $nodeType): array
]];
}
+ protected function addWebResponseResourceOperation(NodeTypeInterface $nodeType, string $webResponseResourcePath): array
+ {
+ $getByPathOperationName = $this->apiResourceOperationNameGenerator->generateGetByPath(
+ $nodeType->getSourceEntityFullQualifiedClassName()
+ );
+ $webResponseResource = Yaml::parseFile($webResponseResourcePath);
+
+ if (!\array_key_exists($this->webResponseClass, $webResponseResource)) {
+ $webResponseResource = [
+ $this->webResponseClass => [
+ 'operations' => [],
+ ]
+ ];
+ }
+
+ if (\array_key_exists('operations', $webResponseResource[$this->webResponseClass])) {
+ $operations = $webResponseResource[$this->webResponseClass]['operations'];
+ } else {
+ $operations = [];
+ }
+
+ if (!$nodeType->isReachable()) {
+ // Do not add operation if node-type is not reachable
+ return $webResponseResource;
+ }
+ if (\array_key_exists($getByPathOperationName, $operations)) {
+ // Do not add operation if already exists
+ return $webResponseResource;
+ }
+
+ $groups = $this->getItemOperationSerializationGroups($nodeType);
+ $operations[$getByPathOperationName] = [
+ 'method' => 'GET',
+ 'class' => Get::class,
+ 'uriTemplate' => '/web_response_by_path',
+ 'read' => false,
+ 'controller' => GetWebResponseByPathController::class,
+ 'normalizationContext' => [
+ 'pagination_enabled' => false,
+ 'enable_max_depth' => true,
+ 'groups' => [
+ $getByPathOperationName,
+ ...array_values(array_filter(array_unique($groups))),
+ ...[
+ 'web_response',
+ 'walker',
+ 'children',
+ ]
+ ]
+ ],
+ 'openapiContext' => [
+ 'tags' => ['WebResponse'],
+ 'summary' => 'Get a ' . $nodeType->getName() . ' by its path wrapped in a WebResponse object',
+ 'description' => 'Get a ' . $nodeType->getName() . ' by its path wrapped in a WebResponse',
+ 'parameters' => [
+ [
+ 'type' => 'string',
+ 'name' => 'path',
+ 'in' => 'query',
+ 'required' => true,
+ 'description' => 'Resource path, or `/` for home page',
+ 'schema' => [
+ 'type' => 'string',
+ ],
+ ]
+ ]
+ ]
+ ];
+
+ $webResponseResource[$this->webResponseClass]['operations'] = $operations;
+ return $webResponseResource;
+ }
+
+ protected function removeWebResponseResourceOperation(NodeTypeInterface $nodeType, string $webResponseResourcePath): array
+ {
+ $getByPathOperationName = $this->apiResourceOperationNameGenerator->generateGetByPath(
+ $nodeType->getSourceEntityFullQualifiedClassName()
+ );
+ $webResponseResource = Yaml::parseFile($webResponseResourcePath);
+
+ if (!\array_key_exists($this->webResponseClass, $webResponseResource)) {
+ return $webResponseResource;
+ }
+ if (\array_key_exists('operations', $webResponseResource[$this->webResponseClass])) {
+ $operations = $webResponseResource[$this->webResponseClass]['operations'];
+ } else {
+ return $webResponseResource;
+ }
+ if (!\array_key_exists($getByPathOperationName, $operations)) {
+ // Do not remove operation if it does not exist
+ return $webResponseResource;
+ }
+
+ unset($operations[$getByPathOperationName]);
+ $webResponseResource[$this->webResponseClass]['operations'] = array_filter($operations);
+ return $webResponseResource;
+ }
+
protected function getCollectionOperations(NodeTypeInterface $nodeType): array
{
$operations = [];
@@ -176,9 +319,9 @@ protected function getCollectionOperations(NodeTypeInterface $nodeType): array
return $operations;
}
- protected function getItemOperations(NodeTypeInterface $nodeType): array
+ protected function getItemOperationSerializationGroups(NodeTypeInterface $nodeType): array
{
- $groups = [
+ return [
"nodes_sources",
"node_listing",
"urls",
@@ -189,11 +332,16 @@ protected function getItemOperations(NodeTypeInterface $nodeType): array
"document_display_sources",
...$this->getGroupedFieldsSerializationGroups($nodeType)
];
+ }
+
+ protected function getItemOperations(NodeTypeInterface $nodeType): array
+ {
+ $groups = $this->getItemOperationSerializationGroups($nodeType);
$itemOperationName = $this->apiResourceOperationNameGenerator->generate(
$nodeType->getSourceEntityFullQualifiedClassName(),
'get'
);
- $operations = [
+ return [
$itemOperationName => [
'method' => 'GET',
'class' => Get::class,
@@ -203,53 +351,6 @@ protected function getItemOperations(NodeTypeInterface $nodeType): array
],
]
];
-
- /*
- * Create itemOperation for WebResponseController action
- */
- if ($nodeType->isReachable()) {
- $operationName = $this->apiResourceOperationNameGenerator->generateGetByPath(
- $nodeType->getSourceEntityFullQualifiedClassName()
- );
- $operations[$operationName] = [
- 'method' => 'GET',
- 'class' => Get::class,
- 'uriTemplate' => '/web_response_by_path',
- 'read' => false,
- 'controller' => GetWebResponseByPathController::class,
- 'normalizationContext' => [
- 'pagination_enabled' => false,
- 'enable_max_depth' => true,
- 'groups' => array_merge(array_values(array_filter(array_unique($groups))), [
- 'web_response',
- 'walker',
- 'walker_level',
- 'walker_metadata',
- 'meta',
- 'children',
- ])
- ],
- 'openapiContext' => [
- 'tags' => ['WebResponse'],
- 'summary' => 'Get a resource by its path wrapped in a WebResponse object',
- 'description' => 'Get a resource by its path wrapped in a WebResponse',
- 'parameters' => [
- [
- 'type' => 'string',
- 'name' => 'path',
- 'in' => 'query',
- 'required' => true,
- 'description' => 'Resource path, or `/` for home page',
- 'schema' => [
- 'type' => 'string',
- ],
- ]
- ]
- ]
- ];
- }
-
- return $operations;
}
protected function getGroupedFieldsSerializationGroups(NodeTypeInterface $nodeType): array
diff --git a/src/Serializer/CircularReferenceHandler.php b/src/Serializer/CircularReferenceHandler.php
index d53c7666..8b5055d7 100644
--- a/src/Serializer/CircularReferenceHandler.php
+++ b/src/Serializer/CircularReferenceHandler.php
@@ -6,18 +6,11 @@
use ApiPlatform\Api\IriConverterInterface;
use ApiPlatform\Api\UrlGeneratorInterface;
-use ApiPlatform\Metadata\Operation;
final class CircularReferenceHandler
{
- private IriConverterInterface $iriConverter;
-
- /**
- * @param IriConverterInterface $iriConverter
- */
- public function __construct(IriConverterInterface $iriConverter)
+ public function __construct(private readonly IriConverterInterface $iriConverter)
{
- $this->iriConverter = $iriConverter;
}
public function __invoke(mixed $object, string $format, array $context): ?string
diff --git a/src/Serializer/Normalizer/DocumentNormalizer.php b/src/Serializer/Normalizer/DocumentNormalizer.php
index c5b1c8a7..b11d4d95 100644
--- a/src/Serializer/Normalizer/DocumentNormalizer.php
+++ b/src/Serializer/Normalizer/DocumentNormalizer.php
@@ -18,18 +18,13 @@
*/
final class DocumentNormalizer extends AbstractPathNormalizer
{
- private FilesystemOperator $documentsStorage;
- private EmbedFinderFactory $embedFinderFactory;
-
public function __construct(
- FilesystemOperator $documentsStorage,
NormalizerInterface $decorated,
UrlGeneratorInterface $urlGenerator,
- EmbedFinderFactory $embedFinderFactory
+ private readonly FilesystemOperator $documentsStorage,
+ private readonly EmbedFinderFactory $embedFinderFactory
) {
parent::__construct($decorated, $urlGenerator);
- $this->documentsStorage = $documentsStorage;
- $this->embedFinderFactory = $embedFinderFactory;
}
/**
diff --git a/src/Serializer/Normalizer/DocumentSourcesNormalizer.php b/src/Serializer/Normalizer/DocumentSourcesNormalizer.php
index 49b03c0c..e52f4004 100644
--- a/src/Serializer/Normalizer/DocumentSourcesNormalizer.php
+++ b/src/Serializer/Normalizer/DocumentSourcesNormalizer.php
@@ -11,15 +11,12 @@
final class DocumentSourcesNormalizer extends AbstractPathNormalizer
{
- protected DocumentFinderInterface $documentFinder;
-
public function __construct(
NormalizerInterface $decorated,
UrlGeneratorInterface $urlGenerator,
- DocumentFinderInterface $documentFinder
+ private readonly DocumentFinderInterface $documentFinder
) {
parent::__construct($decorated, $urlGenerator);
- $this->documentFinder = $documentFinder;
}
/**
diff --git a/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php b/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php
index 5c11a5de..8c7ea103 100644
--- a/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php
+++ b/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php
@@ -9,26 +9,20 @@
use RZ\Roadiz\CoreBundle\Entity\Realm;
use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\RealmVoter;
use Symfony\Bundle\SecurityBundle\Security;
-use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
final class RealmSerializationGroupNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;
private const ALREADY_CALLED = 'REALM_SERIALIZER_NORMALIZER_ALREADY_CALLED';
- private Security $security;
- private ManagerRegistry $managerRegistry;
- /**
- * @param Security $security
- * @param ManagerRegistry $managerRegistry
- */
- public function __construct(Security $security, ManagerRegistry $managerRegistry)
- {
- $this->security = $security;
- $this->managerRegistry = $managerRegistry;
+ public function __construct(
+ private readonly Security $security,
+ private readonly ManagerRegistry $managerRegistry
+ ) {
}
/**
diff --git a/src/Serializer/TranslationAwareContextBuilder.php b/src/Serializer/TranslationAwareContextBuilder.php
index 2af808c8..66867a64 100644
--- a/src/Serializer/TranslationAwareContextBuilder.php
+++ b/src/Serializer/TranslationAwareContextBuilder.php
@@ -13,18 +13,11 @@
final class TranslationAwareContextBuilder implements SerializerContextBuilderInterface
{
- private ManagerRegistry $managerRegistry;
- private SerializerContextBuilderInterface $decorated;
- private PreviewResolverInterface $previewResolver;
-
public function __construct(
- SerializerContextBuilderInterface $decorated,
- ManagerRegistry $managerRegistry,
- PreviewResolverInterface $previewResolver
+ private readonly SerializerContextBuilderInterface $decorated,
+ private readonly ManagerRegistry $managerRegistry,
+ private readonly PreviewResolverInterface $previewResolver
) {
- $this->decorated = $decorated;
- $this->managerRegistry = $managerRegistry;
- $this->previewResolver = $previewResolver;
}
/**
* @inheritDoc
diff --git a/src/Test/NodeType/ApiResourceGeneratorTest.php b/src/Test/NodeType/ApiResourceGeneratorTest.php
new file mode 100644
index 00000000..138a8efc
--- /dev/null
+++ b/src/Test/NodeType/ApiResourceGeneratorTest.php
@@ -0,0 +1,152 @@
+getContainer()->get(ApiResourceOperationNameGenerator::class);
+
+ return new ApiResourceGenerator(
+ $apiResourceOperationNameGenerator,
+ static::getGeneratedPath(),
+ new NullLogger(),
+ WebResponse::class
+ );
+ }
+
+ public function testGenerate(): void
+ {
+ $apiResourceGenerator = $this->getApiResourceGenerator();
+
+ $nodeType = new NodeType();
+ $nodeType->setName('Test');
+
+ $apiResourceGenerator->generate($nodeType);
+ $resourcePath = $apiResourceGenerator->getResourcePath($nodeType);
+ $this->assertFileExists($resourcePath);
+ $this->assertFileEquals(
+ dirname(__DIR__) . '/../../tests/expected_api_resources/nstest.yml',
+ $resourcePath
+ );
+ }
+
+ public function testReachableGenerate(): void
+ {
+ $apiResourceGenerator = $this->getApiResourceGenerator();
+
+ $nodeType = new NodeType();
+ $nodeType->setName('Test');
+ $nodeType->setReachable(true);
+
+ $apiResourceGenerator->generate($nodeType);
+ $resourcePath = $apiResourceGenerator->getResourcePath($nodeType);
+ $this->assertFileExists($resourcePath);
+ $this->assertFileExists(dirname(__DIR__) . '/../../tests/generated_api_resources/web_response.yml');
+ $this->assertFileEquals(
+ dirname(__DIR__) . '/../../tests/expected_api_resources/nstest.yml',
+ $resourcePath
+ );
+ $this->assertFileEquals(
+ dirname(__DIR__) . '/../../tests/expected_api_resources/web_response.yml',
+ dirname(__DIR__) . '/../../tests/generated_api_resources/web_response.yml',
+ );
+ }
+
+ public function testMultipleGenerate(): void
+ {
+ $apiResourceGenerator = $this->getApiResourceGenerator();
+
+ $nodeType = new NodeType();
+ $nodeType->setName('Test');
+ $nodeType->setReachable(true);
+
+ $nodeType2 = new NodeType();
+ $nodeType2->setName('SecondTest');
+ $nodeType2->setReachable(true);
+
+ $apiResourceGenerator->generate($nodeType);
+ $resourcePath = $apiResourceGenerator->getResourcePath($nodeType);
+ $this->assertFileExists($resourcePath);
+ $this->assertFileEquals(
+ dirname(__DIR__) . '/../../tests/expected_api_resources/nstest.yml',
+ $resourcePath
+ );
+
+ $apiResourceGenerator->generate($nodeType2);
+ $resourcePath2 = $apiResourceGenerator->getResourcePath($nodeType2);
+ $this->assertFileExists($resourcePath2);
+ $this->assertFileEquals(
+ dirname(__DIR__) . '/../../tests/expected_api_resources/nssecondtest.yml',
+ $resourcePath2
+ );
+
+ $this->assertFileExists(dirname(__DIR__) . '/../../tests/generated_api_resources/web_response.yml');
+ $this->assertFileEquals(
+ dirname(__DIR__) . '/../../tests/expected_api_resources/web_response_multiple.yml',
+ dirname(__DIR__) . '/../../tests/generated_api_resources/web_response.yml',
+ );
+ }
+
+ public function testRemoveGenerate(): void
+ {
+ $apiResourceGenerator = $this->getApiResourceGenerator();
+
+ $nodeType = new NodeType();
+ $nodeType->setName('Test');
+ $nodeType->setReachable(true);
+
+ $nodeType2 = new NodeType();
+ $nodeType2->setName('SecondTest');
+ $nodeType2->setReachable(true);
+
+ $apiResourceGenerator->generate($nodeType);
+ $apiResourceGenerator->generate($nodeType2);
+
+ // Remove second node-type to check if operation
+ // is removed from web_response
+ $apiResourceGenerator->remove($nodeType2);
+ $resourcePath2 = $apiResourceGenerator->getResourcePath($nodeType2);
+ $this->assertFileDoesNotExist($resourcePath2);
+
+ $this->assertFileExists(dirname(__DIR__) . '/../../tests/generated_api_resources/web_response.yml');
+ $this->assertFileEquals(
+ dirname(__DIR__) . '/../../tests/expected_api_resources/web_response.yml',
+ dirname(__DIR__) . '/../../tests/generated_api_resources/web_response.yml',
+ );
+ }
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $filesystem = new Filesystem();
+ $filesystem->mkdir(static::getGeneratedPath());
+ }
+
+
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+
+ $filesystem = new Filesystem();
+ $filesystem->remove(static::getGeneratedPath());
+ }
+}
diff --git a/tests/expected_api_resources/nssecondtest.yml b/tests/expected_api_resources/nssecondtest.yml
new file mode 100644
index 00000000..28427bd6
--- /dev/null
+++ b/tests/expected_api_resources/nssecondtest.yml
@@ -0,0 +1,33 @@
+App\GeneratedEntity\NSSecondTest:
+ types:
+ - SecondTest
+ operations:
+ secondtest_get_collection:
+ method: GET
+ class: ApiPlatform\Metadata\GetCollection
+ shortName: SecondTest
+ normalizationContext:
+ enable_max_depth: true
+ groups:
+ - nodes_sources_base
+ - nodes_sources_default
+ - urls
+ - tag_base
+ - translation_base
+ - document_display
+ - document_thumbnails
+ - document_display_sources
+ secondtest_get:
+ method: GET
+ class: ApiPlatform\Metadata\Get
+ shortName: SecondTest
+ normalizationContext:
+ groups:
+ - nodes_sources
+ - node_listing
+ - urls
+ - tag_base
+ - translation_base
+ - document_display
+ - document_thumbnails
+ - document_display_sources
diff --git a/tests/expected_api_resources/nstest.yml b/tests/expected_api_resources/nstest.yml
new file mode 100644
index 00000000..727aed77
--- /dev/null
+++ b/tests/expected_api_resources/nstest.yml
@@ -0,0 +1,33 @@
+App\GeneratedEntity\NSTest:
+ types:
+ - Test
+ operations:
+ test_get_collection:
+ method: GET
+ class: ApiPlatform\Metadata\GetCollection
+ shortName: Test
+ normalizationContext:
+ enable_max_depth: true
+ groups:
+ - nodes_sources_base
+ - nodes_sources_default
+ - urls
+ - tag_base
+ - translation_base
+ - document_display
+ - document_thumbnails
+ - document_display_sources
+ test_get:
+ method: GET
+ class: ApiPlatform\Metadata\Get
+ shortName: Test
+ normalizationContext:
+ groups:
+ - nodes_sources
+ - node_listing
+ - urls
+ - tag_base
+ - translation_base
+ - document_display
+ - document_thumbnails
+ - document_display_sources
diff --git a/tests/expected_api_resources/web_response.yml b/tests/expected_api_resources/web_response.yml
new file mode 100644
index 00000000..1789d94d
--- /dev/null
+++ b/tests/expected_api_resources/web_response.yml
@@ -0,0 +1,31 @@
+RZ\Roadiz\CoreBundle\Api\Model\WebResponse:
+ operations:
+ test_get_by_path:
+ method: GET
+ class: ApiPlatform\Metadata\Get
+ uriTemplate: /web_response_by_path
+ read: false
+ controller: RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController
+ normalizationContext:
+ pagination_enabled: false
+ enable_max_depth: true
+ groups:
+ - test_get_by_path
+ - nodes_sources
+ - node_listing
+ - urls
+ - tag_base
+ - translation_base
+ - document_display
+ - document_thumbnails
+ - document_display_sources
+ - web_response
+ - walker
+ - children
+ openapiContext:
+ tags:
+ - WebResponse
+ summary: 'Get a Test by its path wrapped in a WebResponse object'
+ description: 'Get a Test by its path wrapped in a WebResponse'
+ parameters:
+ - { type: string, name: path, in: query, required: true, description: 'Resource path, or `/` for home page', schema: { type: string } }
diff --git a/tests/expected_api_resources/web_response_multiple.yml b/tests/expected_api_resources/web_response_multiple.yml
new file mode 100644
index 00000000..34270be0
--- /dev/null
+++ b/tests/expected_api_resources/web_response_multiple.yml
@@ -0,0 +1,60 @@
+RZ\Roadiz\CoreBundle\Api\Model\WebResponse:
+ operations:
+ test_get_by_path:
+ method: GET
+ class: ApiPlatform\Metadata\Get
+ uriTemplate: /web_response_by_path
+ read: false
+ controller: RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController
+ normalizationContext:
+ pagination_enabled: false
+ enable_max_depth: true
+ groups:
+ - test_get_by_path
+ - nodes_sources
+ - node_listing
+ - urls
+ - tag_base
+ - translation_base
+ - document_display
+ - document_thumbnails
+ - document_display_sources
+ - web_response
+ - walker
+ - children
+ openapiContext:
+ tags:
+ - WebResponse
+ summary: 'Get a Test by its path wrapped in a WebResponse object'
+ description: 'Get a Test by its path wrapped in a WebResponse'
+ parameters:
+ - { type: string, name: path, in: query, required: true, description: 'Resource path, or `/` for home page', schema: { type: string } }
+ secondtest_get_by_path:
+ method: GET
+ class: ApiPlatform\Metadata\Get
+ uriTemplate: /web_response_by_path
+ read: false
+ controller: RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController
+ normalizationContext:
+ pagination_enabled: false
+ enable_max_depth: true
+ groups:
+ - secondtest_get_by_path
+ - nodes_sources
+ - node_listing
+ - urls
+ - tag_base
+ - translation_base
+ - document_display
+ - document_thumbnails
+ - document_display_sources
+ - web_response
+ - walker
+ - children
+ openapiContext:
+ tags:
+ - WebResponse
+ summary: 'Get a SecondTest by its path wrapped in a WebResponse object'
+ description: 'Get a SecondTest by its path wrapped in a WebResponse'
+ parameters:
+ - { type: string, name: path, in: query, required: true, description: 'Resource path, or `/` for home page', schema: { type: string } }