Skip to content

Commit 4b1b94c

Browse files
authored
feat(symfony): Autoconfigure classes using #[ApiResource] attribute (#6943)
1 parent 7c796de commit 4b1b94c

File tree

5 files changed

+56
-0
lines changed

5 files changed

+56
-0
lines changed

src/Symfony/Bundle/ApiPlatformBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Symfony\Bundle;
1515

1616
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\AttributeFilterPass;
17+
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\AttributeResourcePass;
1718
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\AuthenticatorManagerPass;
1819
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\DataProviderPass;
1920
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\ElasticsearchClientPass;
@@ -47,6 +48,7 @@ public function build(ContainerBuilder $container): void
4748
$container->addCompilerPass(new DataProviderPass());
4849
// Run the compiler pass before the {@see ResolveInstanceofConditionalsPass} to allow autoconfiguration of generated filter definitions.
4950
$container->addCompilerPass(new AttributeFilterPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 101);
51+
$container->addCompilerPass(new AttributeResourcePass());
5052
$container->addCompilerPass(new FilterPass());
5153
$container->addCompilerPass(new ElasticsearchClientPass());
5254
$container->addCompilerPass(new GraphQlTypePass());

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
use Ramsey\Uuid\Uuid;
5050
use Symfony\Component\Config\FileLocator;
5151
use Symfony\Component\Config\Resource\DirectoryResource;
52+
use Symfony\Component\DependencyInjection\ChildDefinition;
5253
use Symfony\Component\DependencyInjection\ContainerBuilder;
5354
use Symfony\Component\DependencyInjection\Definition;
5455
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@@ -177,6 +178,11 @@ public function load(array $configs, ContainerBuilder $container): void
177178
->addTag('api_platform.uri_variables.transformer');
178179
$container->registerForAutoconfiguration(ParameterProviderInterface::class)
179180
->addTag('api_platform.parameter_provider');
181+
$container->registerAttributeForAutoconfiguration(ApiResource::class, static function (ChildDefinition $definition): void {
182+
$definition->setAbstract(true)
183+
->addTag('api_platform.resource')
184+
->addTag('container.excluded', ['source' => 'by #[ApiResource] attribute']);
185+
});
180186

181187
if (!$container->has('api_platform.state.item_provider')) {
182188
$container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
18+
use Symfony\Component\DependencyInjection\ContainerBuilder;
19+
20+
/**
21+
* Registers resource classes from {@see ApiResource} attribute.
22+
*
23+
* @internal
24+
*
25+
* @author Jérôme Tamarelle <[email protected]>
26+
*/
27+
final class AttributeResourcePass implements CompilerPassInterface
28+
{
29+
/**
30+
* {@inheritdoc}
31+
*/
32+
public function process(ContainerBuilder $container): void
33+
{
34+
$classes = $container->getParameter('api_platform.class_name_resources');
35+
36+
// findTaggedServiceIds cannot be used, as the services are excluded
37+
foreach ($container->getDefinitions() as $definition) {
38+
if ($definition->hasTag('api_platform.resource')) {
39+
$classes[] = $definition->getClass();
40+
}
41+
}
42+
43+
$container->setParameter('api_platform.class_name_resources', array_unique($classes));
44+
}
45+
}

src/Symfony/Bundle/DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ public function getConfigTreeBuilder(): TreeBuilder
141141
->end()
142142
->arrayNode('resource_class_directories')
143143
->prototype('scalar')->end()
144+
->setDeprecated('api-platform/symfony', '4.1', 'The "resource_class_directories" configuration is deprecated, classes using #[ApiResource] attribute are autoconfigured by the dependency injection container.')
144145
->end()
145146
->arrayNode('serializer')
146147
->addDefaultsIfNotSet()

tests/Symfony/Bundle/ApiPlatformBundleTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
1717
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\AttributeFilterPass;
18+
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\AttributeResourcePass;
1819
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\AuthenticatorManagerPass;
1920
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\DataProviderPass;
2021
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\ElasticsearchClientPass;
@@ -45,6 +46,7 @@ public function testBuild(): void
4546
$containerProphecy = $this->prophesize(ContainerBuilder::class);
4647
$containerProphecy->addCompilerPass(Argument::type(DataProviderPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
4748
$containerProphecy->addCompilerPass(Argument::type(AttributeFilterPass::class), PassConfig::TYPE_BEFORE_OPTIMIZATION, 101)->willReturn($containerProphecy->reveal())->shouldBeCalled();
49+
$containerProphecy->addCompilerPass(Argument::type(AttributeResourcePass::class))->shouldBeCalled()->willReturn($containerProphecy->reveal())->shouldBeCalled();
4850
$containerProphecy->addCompilerPass(Argument::type(FilterPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
4951
$containerProphecy->addCompilerPass(Argument::type(ElasticsearchClientPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
5052
$containerProphecy->addCompilerPass(Argument::type(GraphQlTypePass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();

0 commit comments

Comments
 (0)