Skip to content

Commit 13d9024

Browse files
authored
feat(symfony): request and view kernel listeners (#6102)
1 parent 8a799bb commit 13d9024

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2414
-326
lines changed

Bundle/DependencyInjection/ApiPlatformExtension.php

+85-18
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@
2929
use ApiPlatform\GraphQl\Resolver\QueryCollectionResolverInterface;
3030
use ApiPlatform\GraphQl\Resolver\QueryItemResolverInterface;
3131
use ApiPlatform\GraphQl\Type\Definition\TypeInterface as GraphQlTypeInterface;
32+
use ApiPlatform\Hydra\EventListener\AddLinkHeaderListener as HydraAddLinkHeaderListener;
3233
use ApiPlatform\Metadata\ApiResource;
3334
use ApiPlatform\Metadata\FilterInterface;
3435
use ApiPlatform\Metadata\UrlGeneratorInterface;
3536
use ApiPlatform\Metadata\Util\Inflector;
3637
use ApiPlatform\State\ApiResource\Error;
3738
use ApiPlatform\State\ProcessorInterface;
3839
use ApiPlatform\State\ProviderInterface;
40+
use ApiPlatform\Symfony\EventListener\AddHeadersListener;
41+
use ApiPlatform\Symfony\EventListener\AddLinkHeaderListener;
42+
use ApiPlatform\Symfony\EventListener\AddTagsListener;
43+
use ApiPlatform\Symfony\EventListener\DenyAccessListener;
3944
use ApiPlatform\Symfony\GraphQl\Resolver\Factory\DataCollectorResolverFactory;
4045
use ApiPlatform\Symfony\Validator\Exception\ValidationException;
4146
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRestrictionMetadataInterface;
@@ -182,10 +187,9 @@ public function load(array $configs, ContainerBuilder $container): void
182187

183188
private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats, array $docsFormats): void
184189
{
185-
$loader->load('symfony/events.xml');
186-
$loader->load('symfony/controller.xml');
190+
$loader->load('state/state.xml');
191+
$loader->load('symfony/symfony.xml');
187192
$loader->load('api.xml');
188-
$loader->load('state.xml');
189193
$loader->load('filter.xml');
190194

191195
if (class_exists(Uuid::class)) {
@@ -198,7 +202,29 @@ private function registerCommonConfiguration(ContainerBuilder $container, array
198202

199203
// TODO: remove in 4.x
200204
$container->setParameter('api_platform.event_listeners_backward_compatibility_layer', $config['event_listeners_backward_compatibility_layer']);
201-
$loader->load('legacy/events.xml');
205+
$container->setParameter('api_platform.use_symfony_listeners', $config['use_symfony_listeners']);
206+
207+
if ($config['event_listeners_backward_compatibility_layer']) {
208+
trigger_deprecation('api-platform/core', '3.3', sprintf('The "event_listeners_backward_compatibility_layer" will be removed in 4.0. Use the configuration "use_symfony_listeners" to use Symfony listeners. The following listeners are deprecated and will be removed in API Platform 4.0: "%s"', implode(', ', [
209+
AddHeadersListener::class,
210+
AddTagsListener::class,
211+
AddLinkHeaderListener::class,
212+
HydraAddLinkHeaderListener::class,
213+
DenyAccessListener::class,
214+
])));
215+
}
216+
217+
if ($config['event_listeners_backward_compatibility_layer']) {
218+
$loader->load('legacy/events.xml');
219+
}
220+
221+
if ($config['use_symfony_listeners']) {
222+
$loader->load('symfony/events.xml');
223+
} else {
224+
$loader->load('symfony/controller.xml');
225+
$loader->load('state/provider.xml');
226+
$loader->load('state/processor.xml');
227+
}
202228

203229
$container->setParameter('api_platform.enable_entrypoint', $config['enable_entrypoint']);
204230
$container->setParameter('api_platform.enable_docs', $config['enable_docs']);
@@ -476,7 +502,15 @@ private function registerSwaggerConfiguration(ContainerBuilder $container, array
476502
$loader->load('openapi.xml');
477503
$loader->load('swagger_ui.xml');
478504

479-
$loader->load('legacy/swagger_ui.xml');
505+
if ($config['event_listeners_backward_compatibility_layer']) {
506+
$loader->load('legacy/swagger_ui.xml');
507+
}
508+
509+
if ($config['use_symfony_listeners']) {
510+
$loader->load('symfony/swagger_ui.xml');
511+
}
512+
513+
$loader->load('state/swagger_ui.xml');
480514

481515
if (!$config['enable_swagger_ui'] && !$config['enable_re_doc']) {
482516
// Remove the listener but keep the controller to allow customizing the path of the UI
@@ -498,8 +532,12 @@ private function registerJsonApiConfiguration(array $formats, XmlFileLoader $loa
498532
return;
499533
}
500534

535+
if ($config['event_listeners_backward_compatibility_layer']) {
536+
$loader->load('legacy/jsonapi.xml');
537+
}
538+
501539
$loader->load('jsonapi.xml');
502-
$loader->load('legacy/jsonapi.xml');
540+
$loader->load('state/jsonapi.xml');
503541
}
504542

505543
private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, XmlFileLoader $loader, array $config): void
@@ -508,8 +546,18 @@ private function registerJsonLdHydraConfiguration(ContainerBuilder $container, a
508546
return;
509547
}
510548

549+
if ($config['use_symfony_listeners']) {
550+
$loader->load('symfony/jsonld.xml');
551+
} else {
552+
$loader->load('state/jsonld.xml');
553+
}
554+
555+
if ($config['event_listeners_backward_compatibility_layer']) {
556+
$loader->load('legacy/hydra.xml');
557+
}
558+
559+
$loader->load('state/hydra.xml');
511560
$loader->load('jsonld.xml');
512-
$loader->load('legacy/hydra.xml');
513561
$loader->load('hydra.xml');
514562

515563
if (!$container->has('api_platform.json_schema.schema_factory')) {
@@ -588,7 +636,7 @@ private function registerGraphQlConfiguration(ContainerBuilder $container, array
588636
->addTag('api_platform.graphql.error_handler');
589637

590638
/* TODO: remove these in 4.x only one resolver factory is used and we're using providers/processors */
591-
if ($config['event_listeners_backward_compatibility_layer'] ?? true) {
639+
if ($config['event_listeners_backward_compatibility_layer']) {
592640
// @TODO: API Platform 3.3 trigger_deprecation('api-platform/core', '3.3', 'In API Platform 4 only one factory "api_platform.graphql.resolver.factory.item" will remain. Stages are deprecated in favor of using a provider/processor.');
593641
// + deprecate every service from legacy/graphql.xml
594642
$loader->load('legacy/graphql.xml');
@@ -683,7 +731,10 @@ private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $conta
683731
private function registerHttpCacheConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
684732
{
685733
$loader->load('http_cache.xml');
686-
$loader->load('legacy/http_cache.xml');
734+
735+
if ($config['event_listeners_backward_compatibility_layer']) {
736+
$loader->load('legacy/http_cache.xml');
737+
}
687738

688739
if (!$this->isConfigEnabled($container, $config['http_cache']['invalidation'])) {
689740
return;
@@ -693,8 +744,12 @@ private function registerHttpCacheConfiguration(ContainerBuilder $container, arr
693744
$loader->load('doctrine_orm_http_cache_purger.xml');
694745
}
695746

747+
if ($config['event_listeners_backward_compatibility_layer']) {
748+
$loader->load('legacy/http_cache_purger.xml');
749+
}
750+
751+
$loader->load('state/http_cache_purger.xml');
696752
$loader->load('http_cache_purger.xml');
697-
$loader->load('legacy/http_cache_purger.xml');
698753

699754
foreach ($config['http_cache']['invalidation']['scoped_clients'] as $client) {
700755
$definition = $container->getDefinition($client);
@@ -738,18 +793,22 @@ private function registerValidatorConfiguration(ContainerBuilder $container, arr
738793
{
739794
if (interface_exists(ValidatorInterface::class)) {
740795
$loader->load('metadata/validator.xml');
741-
$loader->load('symfony/validator.xml');
796+
$loader->load('validator/validator.xml');
742797

743798
if ($this->isConfigEnabled($container, $config['graphql'])) {
744799
$loader->load('graphql/validator.xml');
745800
}
746801

802+
if ($config['event_listeners_backward_compatibility_layer']) {
803+
$loader->load('legacy/validator.xml');
804+
}
805+
806+
$loader->load($config['use_symfony_listeners'] ? 'validator/events.xml' : 'validator/state.xml');
807+
747808
$container->registerForAutoconfiguration(ValidationGroupsGeneratorInterface::class)
748809
->addTag('api_platform.validation_groups_generator');
749810
$container->registerForAutoconfiguration(PropertySchemaRestrictionMetadataInterface::class)
750811
->addTag('api_platform.metadata.property_schema_restriction');
751-
752-
$loader->load('legacy/validator.xml');
753812
}
754813

755814
if (!$config['validator']) {
@@ -786,8 +845,11 @@ private function registerMercureConfiguration(ContainerBuilder $container, array
786845

787846
$container->setParameter('api_platform.mercure.include_type', $config['mercure']['include_type']);
788847

789-
$loader->load('legacy/mercure.xml');
790-
$loader->load('mercure.xml');
848+
if ($config['event_listeners_backward_compatibility_layer']) {
849+
$loader->load('legacy/mercure.xml');
850+
}
851+
852+
$loader->load('state/mercure.xml');
791853

792854
if ($this->isConfigEnabled($container, $config['doctrine'])) {
793855
$loader->load('doctrine_orm_mercure_publisher.xml');
@@ -847,10 +909,15 @@ private function registerSecurityConfiguration(ContainerBuilder $container, arra
847909
}
848910

849911
$loader->load('security.xml');
850-
$loader->load('legacy/security.xml');
851912

852-
if (interface_exists(ValidatorInterface::class)) {
853-
$loader->load('symfony/security_validator.xml');
913+
if ($config['event_listeners_backward_compatibility_layer']) {
914+
$loader->load('legacy/security.xml');
915+
}
916+
917+
$loader->load('state/security.xml');
918+
919+
if (interface_exists(ValidatorInterface::class) && !$config['use_symfony_listeners']) {
920+
$loader->load('state/security_validator.xml');
854921
}
855922

856923
if ($this->isConfigEnabled($container, $config['graphql'])) {

Bundle/DependencyInjection/Configuration.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use ApiPlatform\Metadata\Post;
2222
use ApiPlatform\Metadata\Put;
2323
use ApiPlatform\ParameterValidator\Exception\ValidationExceptionInterface;
24+
use ApiPlatform\Symfony\Controller\MainController;
2425
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
2526
use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
2627
use Doctrine\ORM\EntityManagerInterface;
@@ -83,7 +84,8 @@ public function getConfigTreeBuilder(): TreeBuilder
8384
->defaultValue('0.0.0')
8485
->end()
8586
->booleanNode('show_webby')->defaultTrue()->info('If true, show Webby on the documentation page')->end()
86-
->booleanNode('event_listeners_backward_compatibility_layer')->defaultTrue()->info('If true API Platform uses Symfony event listeners instead of providers and processors.')->end() // TODO: Add link to the documentation
87+
->booleanNode('event_listeners_backward_compatibility_layer')->defaultNull()->info('If true API Platform uses Symfony event listeners instead of providers and processors.')->end() // TODO: Add link to the documentation
88+
->booleanNode('use_symfony_listeners')->defaultFalse()->info(sprintf('Uses Symfony event listeners instead of the %s.', MainController::class))->end() // TODO: Add link to the documentation
8789
->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
8890
->scalarNode('asset_package')->defaultNull()->info('Specify an asset package name to use.')->end()
8991
->scalarNode('path_segment_name_generator')->defaultValue('api_platform.metadata.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end()

Bundle/Resources/config/api.xml

+4-47
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8+
<service id="api_platform.action.not_found" class="ApiPlatform\Action\NotFoundAction" public="true" />
9+
<service id="api_platform.action.not_exposed" class="ApiPlatform\Action\NotExposedAction" public="true" />
10+
<service id="ApiPlatform\Action\NotFoundAction" alias="api_platform.action.not_found" public="true" />
11+
<service id="ApiPlatform\Action\NotExposedAction" alias="api_platform.action.not_exposed" public="true" />
812
<service id="api_platform.serializer" alias="serializer" />
913
<service id="api_platform.property_accessor" alias="property_accessor" public="false" />
1014
<service id="api_platform.property_info" alias="property_info" public="false" />
@@ -84,39 +88,6 @@
8488
<service id="api_platform.metadata.path_segment_name_generator.dash" class="ApiPlatform\Metadata\Operation\DashPathSegmentNameGenerator" public="false" />
8589

8690
<!-- Action -->
87-
88-
<service id="api_platform.action.placeholder" class="ApiPlatform\Action\PlaceholderAction" public="true" />
89-
<service id="ApiPlatform\Action\PlaceholderAction" alias="api_platform.action.placeholder" public="true" />
90-
<service id="api_platform.action.get_collection" alias="api_platform.action.placeholder" public="true" />
91-
<service id="api_platform.action.post_collection" alias="api_platform.action.placeholder" public="true" />
92-
<service id="api_platform.action.get_item" alias="api_platform.action.placeholder" public="true" />
93-
<service id="api_platform.action.patch_item" alias="api_platform.action.placeholder" public="true" />
94-
<service id="api_platform.action.put_item" alias="api_platform.action.placeholder" public="true" />
95-
<service id="api_platform.action.delete_item" alias="api_platform.action.placeholder" public="true" />
96-
<service id="api_platform.action.not_found" class="ApiPlatform\Action\NotFoundAction" public="true" />
97-
<service id="api_platform.action.not_exposed" class="ApiPlatform\Action\NotExposedAction" public="true" />
98-
<service id="ApiPlatform\Action\NotFoundAction" alias="api_platform.action.not_found" public="true" />
99-
<service id="ApiPlatform\Action\NotExposedAction" alias="api_platform.action.not_exposed" public="true" />
100-
101-
<service id="api_platform.action.entrypoint" class="ApiPlatform\Documentation\Action\EntrypointAction" public="true">
102-
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
103-
<argument type="service" id="api_platform.state_provider.main" on-invalid="null" />
104-
<argument type="service" id="api_platform.state_processor.main" on-invalid="null" />
105-
<argument>%api_platform.docs_formats%</argument>
106-
</service>
107-
108-
<service id="api_platform.action.documentation" class="ApiPlatform\Documentation\Action\DocumentationAction" public="true">
109-
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
110-
<argument>%api_platform.title%</argument>
111-
<argument>%api_platform.description%</argument>
112-
<argument>%api_platform.version%</argument>
113-
<argument type="service" id="api_platform.openapi.factory" on-invalid="null" />
114-
<argument type="service" id="api_platform.state_provider.main" on-invalid="null" />
115-
<argument type="service" id="api_platform.state_processor.main" on-invalid="null" />
116-
<argument type="service" id="api_platform.negotiator" on-invalid="null" />
117-
<argument>%api_platform.docs_formats%</argument>
118-
</service>
119-
12091
<service id="api_platform.action.exception" class="ApiPlatform\Action\ExceptionAction" public="true">
12192
<argument type="service" id="api_platform.serializer" />
12293
<argument>%api_platform.error_formats%</argument>
@@ -191,20 +162,6 @@
191162
<service id="ApiPlatform\Api\IriConverterInterface" alias="api_platform.symfony.iri_converter" />
192163
<service id="ApiPlatform\Metadata\IriConverterInterface" alias="api_platform.symfony.iri_converter" />
193164

194-
<service id="api_platform.error_listener" class="ApiPlatform\Symfony\EventListener\ErrorListener">
195-
<argument key="$controller">api_platform.symfony.main_controller</argument>
196-
<argument key="$logger" type="service" id="logger" on-invalid="null" />
197-
<argument key="$debug">%kernel.debug%</argument>
198-
<argument key="$exceptionsMapping" type="collection"></argument>
199-
<argument key="$resourceMetadataCollectionFactory" type="service" id="api_platform.metadata.resource.metadata_collection_factory" />
200-
<argument key="$errorFormats">%api_platform.error_formats%</argument>
201-
<argument key="$exceptionToStatus">%api_platform.exception_to_status%</argument>
202-
<argument key="$identifiersExtractor">null</argument>
203-
<argument key="$resourceClassResolver" type="service" id="api_platform.resource_class_resolver"/>
204-
<argument key="$negotiator">null</argument>
205-
<argument key="$problemCompliantErrors">%api_platform.rfc_7807_compliant_errors%</argument>
206-
</service>
207-
208165
<service id="api_platform.state.error_provider" class="ApiPlatform\State\ErrorProvider">
209166
<argument key="$debug">%kernel.debug%</argument>
210167
<argument type="service" key="$resourceClassResolver" id="api_platform.resource_class_resolver" />

Bundle/Resources/config/http_cache_purger.xml

-6
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,5 @@
1818
<argument type="tagged" tag="api_platform.http_cache.http_client" />
1919
<argument>%api_platform.http_cache.invalidation.max_header_length%</argument>
2020
</service>
21-
22-
<service id="api_platform.http_cache_purger.processor.add_tags" class="ApiPlatform\HttpCache\State\AddTagsProcessor" decorates="api_platform.state_processor.respond">
23-
<argument type="service" id="api_platform.http_cache_purger.processor.add_tags.inner" />
24-
<argument type="service" id="api_platform.iri_converter" />
25-
<argument type="service" id="api_platform.http_cache.purger" on-invalid="null" />
26-
</service>
2721
</services>
2822
</container>

Bundle/Resources/config/hydra.xml

-9
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,7 @@
1919
<tag name="serializer.normalizer" priority="-800" />
2020
</service>
2121

22-
23-
<!-- State -->
24-
25-
<service id="api_platform.hydra.processor.link" class="ApiPlatform\Hydra\State\HydraLinkProcessor" decorates="api_platform.state_processor.main" decoration-priority="410">
26-
<argument type="service" id="api_platform.hydra.processor.link.inner" />
27-
<argument type="service" id="api_platform.router" />
28-
</service>
29-
3022
<!-- Serializer -->
31-
3223
<service id="api_platform.hydra.normalizer.constraint_violation_list" class="ApiPlatform\Hydra\Serializer\ConstraintViolationListNormalizer" public="false">
3324
<argument type="service" id="api_platform.router" />
3425
<argument>%api_platform.validator.serialize_payload_fields%</argument>

Bundle/Resources/config/jsonapi.xml

-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@
1515
<argument type="service" id="api_platform.name_converter" on-invalid="ignore" />
1616
</service>
1717

18-
<service id="api_platform.jsonapi.state_provider" class="ApiPlatform\JsonApi\State\JsonApiProvider" public="false" decorates="api_platform.state_provider.read">
19-
<argument type="service" id="api_platform.jsonapi.state_provider.inner" />
20-
<argument>%api_platform.collection.order_parameter_name%</argument>
21-
</service>
22-
2318
<service id="api_platform.jsonapi.normalizer.entrypoint" class="ApiPlatform\JsonApi\Serializer\EntrypointNormalizer" public="false">
2419
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory" />
2520
<argument type="service" id="api_platform.iri_converter" />

0 commit comments

Comments
 (0)