diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
index cf39090b833..97d00587f79 100644
--- a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
+++ b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
@@ -97,6 +97,7 @@ public function load(array $configs, ContainerBuilder $container): void
}
$this->registerCommonConfiguration($container, $config, $loader, $formats, $patchFormats, $errorFormats);
+ $this->registerRestListenerConfiguration($container, $config, $loader);
$this->registerMetadataConfiguration($container, $config, $loader);
$this->registerOAuthConfiguration($container, $config);
$this->registerSwaggerConfiguration($container, $config, $loader);
@@ -370,6 +371,18 @@ private function registerJsonProblemConfiguration(array $errorFormats, XmlFileLo
$loader->load('problem.xml');
}
+ private function registerRestListenerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
+ {
+ $container->setParameter('api_platform.rest.disable_rest', $config['disable_rest']);
+
+ if ($config['disable_rest']) {
+ return;
+ }
+
+ $loader->load('rest_event_listener.xml');
+
+ }
+
private function registerGraphQlConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
{
$enabled = $this->isConfigEnabled($container, $config['graphql']);
diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
index b49c43b28ed..287c951cf35 100644
--- a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
+++ b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
@@ -106,6 +106,7 @@ public function getConfigTreeBuilder()
->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
->end()
->end()
+ ->booleanNode('disable_rest')->defaultFalse()->info('Disable the rest listeners')->end()
->booleanNode('enable_fos_user')->defaultValue(class_exists(FOSUserBundle::class))->info('Enable the FOSUserBundle integration.')->end()
->booleanNode('enable_nelmio_api_doc')
->defaultFalse()
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml
index 5b07b360cf2..4cfa2c3f457 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml
@@ -44,6 +44,7 @@
%api_platform.enable_docs%
%api_platform.graphql.graphiql.enabled%
%api_platform.graphql.graphql_playground.enabled%
+ %api_platform.rest.disable_rest%
@@ -155,56 +156,6 @@
-
-
-
-
- %api_platform.formats%
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
%api_platform.error_formats%
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/metadata/metadata.xml b/src/Bridge/Symfony/Bundle/Resources/config/metadata/metadata.xml
index 1a50a9b0e14..cebe44f8211 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/metadata/metadata.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/metadata/metadata.xml
@@ -25,6 +25,7 @@
%api_platform.patch_formats%
+ %api_platform.rest.disable_rest%%
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/rest_event_listener.xml b/src/Bridge/Symfony/Bundle/Resources/config/rest_event_listener.xml
new file mode 100644
index 00000000000..6447def5ba7
--- /dev/null
+++ b/src/Bridge/Symfony/Bundle/Resources/config/rest_event_listener.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Metadata/Resource/Factory/OperationResourceMetadataFactory.php b/src/Metadata/Resource/Factory/OperationResourceMetadataFactory.php
index ef2590edad1..9793d920668 100644
--- a/src/Metadata/Resource/Factory/OperationResourceMetadataFactory.php
+++ b/src/Metadata/Resource/Factory/OperationResourceMetadataFactory.php
@@ -43,11 +43,13 @@ final class OperationResourceMetadataFactory implements ResourceMetadataFactoryI
private $decorated;
private $patchFormats;
+ private $disableRest;
- public function __construct(ResourceMetadataFactoryInterface $decorated, array $patchFormats = [])
+ public function __construct(ResourceMetadataFactoryInterface $decorated, array $patchFormats = [], $disableRest = false)
{
$this->decorated = $decorated;
$this->patchFormats = $patchFormats;
+ $this->disableRest = $disableRest;
}
/**
@@ -59,6 +61,11 @@ public function create(string $resourceClass): ResourceMetadata
$isAbstract = (new \ReflectionClass($resourceClass))->isAbstract();
$collectionOperations = $resourceMetadata->getCollectionOperations();
+ // If rest is disabled we don't want to add the default operations
+ // but we want to have the placeholder get operation
+ if (true === $this->disableRest) {
+ $collectionOperations = [];
+ }
if (null === $collectionOperations) {
$resourceMetadata = $resourceMetadata->withCollectionOperations($this->createOperations($isAbstract ? ['GET'] : ['GET', 'POST']));
} else {
@@ -66,6 +73,12 @@ public function create(string $resourceClass): ResourceMetadata
}
$itemOperations = $resourceMetadata->getItemOperations();
+ // If rest is disabled we don't want to add the default operations
+ // but we want to have the placeholder get operation
+ if (true === $this->disableRest) {
+ $itemOperations = [];
+ }
+
if (null === $itemOperations) {
$methods = ['GET', 'DELETE'];
diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
index 11f23d41b3f..514700bb8b6 100644
--- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
+++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
@@ -294,7 +294,7 @@ public function testFosUserPriority()
$builder = new ContainerBuilder();
$loader = new XmlFileLoader($builder, new FileLocator(\dirname(__DIR__).'/../../../../src/Bridge/Symfony/Bundle/Resources/config'));
- $loader->load('api.xml');
+ $loader->load('rest_event_listener.xml');
$loader->load('fos_user.xml');
$fosListener = $builder->getDefinition('api_platform.fos_user.event_listener');
@@ -757,6 +757,26 @@ public function testKeepCachePoolClearerCacheWarmerWithDebug()
$this->extension->load(self::DEFAULT_CONFIG, $containerBuilder);
}
+ public function testDisableRest()
+ {
+ $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy();
+ $containerBuilderProphecy->setDefinition('api_platform.listener.request.add_format', Argument::type(Definition::class))->shouldNotBeCalled();
+ $containerBuilderProphecy->setDefinition('api_platform.listener.request.read', Argument::type(Definition::class))->shouldNotBeCalled();
+ $containerBuilderProphecy->setDefinition('api_platform.listener.view.write', Argument::type(Definition::class))->shouldNotBeCalled();
+ $containerBuilderProphecy->setDefinition('api_platform.listener.request.deserialize', Argument::type(Definition::class))->shouldNotBeCalled();
+ $containerBuilderProphecy->setDefinition('api_platform.listener.view.serialize', Argument::type(Definition::class))->shouldNotBeCalled();
+ $containerBuilderProphecy->setDefinition('api_platform.listener.view.respond', Argument::type(Definition::class))->shouldNotBeCalled();
+ $containerBuilderProphecy->setParameter('api_platform.rest.disable_rest', false)->shouldNotBeCalled();
+ $containerBuilderProphecy->setParameter('api_platform.rest.disable_rest', true)->shouldBeCalled();
+
+ $containerBuilder = $containerBuilderProphecy->reveal();
+
+ $config = self::DEFAULT_CONFIG;
+ $config['api_platform']['disable_rest'] = true;
+
+ $this->extension->load($config, $containerBuilder);
+ }
+
private function getPartialContainerBuilderProphecy()
{
$parameterBag = new EnvPlaceholderParameterBag();
@@ -806,6 +826,7 @@ private function getPartialContainerBuilderProphecy()
'api_platform.http_cache.public' => null,
'api_platform.enable_entrypoint' => true,
'api_platform.enable_docs' => true,
+ 'api_platform.rest.disable_rest' => false,
];
$pagination = [
@@ -1073,6 +1094,7 @@ private function getBaseContainerBuilderProphecy(array $doctrineIntegrationsToLo
'api_platform.graphql.collection.pagination' => ['enabled' => true],
'api_platform.graphql.graphiql.enabled' => true,
'api_platform.graphql.graphql_playground.enabled' => true,
+ 'api_platform.rest.disable_rest' => false,
'api_platform.resource_class_directories' => Argument::type('array'),
'api_platform.validator.serialize_payload_fields' => [],
'api_platform.elasticsearch.enabled' => false,
diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
index a891c8724e2..20c44a5cd29 100644
--- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
+++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
@@ -204,6 +204,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm
],
'allow_plain_identifiers' => false,
'resource_class_directories' => [],
+ 'disable_rest' => false
], $config);
}
diff --git a/tests/Metadata/Resource/Factory/OperationResourceMetadataFactoryTest.php b/tests/Metadata/Resource/Factory/OperationResourceMetadataFactoryTest.php
index 4bdbbbdecb2..413fcb060d4 100644
--- a/tests/Metadata/Resource/Factory/OperationResourceMetadataFactoryTest.php
+++ b/tests/Metadata/Resource/Factory/OperationResourceMetadataFactoryTest.php
@@ -29,12 +29,12 @@ class OperationResourceMetadataFactoryTest extends TestCase
/**
* @dataProvider getMetadata
*/
- public function testCreateOperation(ResourceMetadata $before, ResourceMetadata $after, array $formats = []): void
+ public function testCreateOperation(ResourceMetadata $before, ResourceMetadata $after, array $formats = [], $disableRest = false ): void
{
$decoratedProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
$decoratedProphecy->create(Dummy::class)->shouldBeCalled()->willReturn($before);
- $this->assertEquals($after, (new OperationResourceMetadataFactory($decoratedProphecy->reveal(), $formats))->create(Dummy::class));
+ $this->assertEquals($after, (new OperationResourceMetadataFactory($decoratedProphecy->reveal(), $formats, $disableRest))->create(Dummy::class));
}
public function getMetadata(): iterable
@@ -46,6 +46,7 @@ public function getMetadata(): iterable
yield [new ResourceMetadata(null, null, null, null, [], null, [], []), new ResourceMetadata(null, null, null, $this->getOperations(['get', 'put', 'patch', 'delete']), [], null, [], []), $jsonapi];
yield [new ResourceMetadata(null, null, null, ['get'], [], null, [], []), new ResourceMetadata(null, null, null, $this->getOperations(['get']), [], null, [], [])];
yield [new ResourceMetadata(null, null, null, [], [], null, [], []), new ResourceMetadata(null, null, null, $this->getPlaceholderOperation(), [], null, [], [])];
+ yield [new ResourceMetadata(null, null, null, null, null, null, [], []), new ResourceMetadata(null, null, null, $this->getPlaceholderOperation(), [], null, [], []), [], true];
yield [new ResourceMetadata(null, null, null, ['put'], [], null, [], []), new ResourceMetadata(null, null, null, $this->getOperations(['put']), [], null, [], [])];
yield [new ResourceMetadata(null, null, null, ['delete'], [], null, [], []), new ResourceMetadata(null, null, null, $this->getOperations(['delete']), [], null, [], [])];
yield [new ResourceMetadata(null, null, null, ['patch' => ['method' => 'PATCH', 'route_name' => 'patch']], [], null, [], []), new ResourceMetadata(null, null, null, array_merge(['patch' => ['method' => 'PATCH', 'route_name' => 'patch']], $this->getPlaceholderOperation()), [], null, [], [])];