Skip to content

Commit

Permalink
feat(WebResponse): Expose request attribute `_web_response_item_class…
Browse files Browse the repository at this point in the history
…` to store WebResponse item class name
  • Loading branch information
roadiz-ci committed Mar 26, 2024
1 parent 8cf5631 commit cb44b25
Show file tree
Hide file tree
Showing 22 changed files with 617 additions and 149 deletions.
6 changes: 6 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -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
41 changes: 1 addition & 40 deletions config/api_resources/web_response.yml
Original file line number Diff line number Diff line change
@@ -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: []
1 change: 1 addition & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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/'
Expand Down
67 changes: 67 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>

<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="./tests/bootstrap.php"
convertDeprecationsToExceptions="false"
>
<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="weak" />
<!-- ###+ sentry/sentry-symfony ### -->
<env name="SENTRY_DSN" value=""/>
<!-- ###- sentry/sentry-symfony ### -->

<!-- ###+ lexik/jwt-authentication-bundle ### -->
<env name="JWT_SECRET_KEY" value="%kernel.project_dir%/config/jwt/private.pem"/>
<env name="JWT_PUBLIC_KEY" value="%kernel.project_dir%/config/jwt/public.pem"/>
<env name="JWT_PASSPHRASE" value="6e5690ad7417d7b8dea7d497e6d552f1"/>
<!-- ###- lexik/jwt-authentication-bundle ### -->

<!-- ###+ nelmio/cors-bundle ### -->
<env name="CORS_ALLOW_ORIGIN" value="'^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'"/>
<!-- ###- nelmio/cors-bundle ### -->

<!--<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[total]=999999"/>-->

<!-- ###+ symfony/lock ### -->
<!-- Choose one of the stores below -->
<!-- postgresql+advisory://db_user:db_password@localhost/db_name -->
<env name="LOCK_DSN" value="flock"/>
<!-- ###- symfony/lock ### -->
</php>

<testsuites>
<testsuite name="Roadiz Monorepo Test Suite">
<directory>src/Test</directory>
</testsuite>
</testsuites>

<coverage cacheDirectory="coverage"
includeUncoveredFiles="true"
processUncoveredFiles="true"
pathCoverage="false"
ignoreDeprecatedCodeUnits="true"
disableCodeCoverageIgnore="true">
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<text outputFile="php://stdout"/>
<clover outputFile="coverage/clover.xml"/>
<cobertura outputFile="coverage/cobertura.xml"/>
</report>
</coverage>

<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
</phpunit>
41 changes: 30 additions & 11 deletions src/Api/Controller/GetWebResponseByPathController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,6 +32,7 @@ public function __construct(
private readonly IriConverterInterface $iriConverter,
private readonly PreviewResolverInterface $previewResolver,
private readonly ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator,
private readonly LoggerInterface $logger
) {
}

Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>|null
*/
public function transform(PersistableInterface $object, string $to, array $context = []): ?WebResponseInterface;

Expand Down
16 changes: 13 additions & 3 deletions src/Api/DataTransformer/WebResponseOutputDataTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,14 +26,25 @@ 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<WebResponseInterface> $webResponseClass
*/
public function __construct(
protected readonly NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory,
protected readonly BreadcrumbsFactoryInterface $breadcrumbsFactory,
protected readonly WalkerContextInterface $walkerContext,
protected readonly CacheItemPoolInterface $cacheItemPool,
protected readonly UrlGeneratorInterface $urlGenerator,
protected readonly RealmResolverInterface $realmResolver,
protected readonly TreeWalkerGenerator $treeWalkerGenerator
protected readonly TreeWalkerGenerator $treeWalkerGenerator,
private readonly string $webResponseClass
) {
}

Expand Down Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions src/Api/Model/WebResponseInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion src/Api/Model/WebResponseTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -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"])]
Expand Down
4 changes: 4 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/RoadizCoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit cb44b25

Please sign in to comment.