Skip to content

Commit 080574a

Browse files
fix(symfony): register property_info fallback when not provided by Symfony (#7969)
Co-authored-by: soyuka <soyuka@users.noreply.github.com> Signed-off-by: Guillaume Delré <delre.guillaume@gmail.com> Fixes #7876 Fix #7876 Closes api-platform/docs#2262
1 parent ae4ea86 commit 080574a

3 files changed

Lines changed: 62 additions & 25 deletions

File tree

src/Symfony/Bundle/Resources/config/api.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@
4646
use ApiPlatform\Symfony\Routing\Router;
4747
use ApiPlatform\Symfony\Routing\SkolemIriConverter;
4848
use Negotiation\Negotiator;
49+
use phpDocumentor\Reflection\DocBlockFactory;
50+
use phpDocumentor\Reflection\Types\ContextFactory;
51+
use PHPStan\PhpDocParser\Parser\PhpDocParser;
52+
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
53+
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
54+
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
55+
use Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor;
56+
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
4957
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
5058
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
5159

@@ -68,7 +76,38 @@
6876

6977
$services->alias('api_platform.property_accessor', 'property_accessor');
7078

71-
$services->alias('api_platform.property_info', 'property_info');
79+
$services->set('api_platform.property_info.reflection_extractor', ReflectionExtractor::class)
80+
->tag('property_info.list_extractor', ['priority' => -1000])
81+
->tag('property_info.type_extractor', ['priority' => -1002])
82+
->tag('property_info.access_extractor', ['priority' => -1000])
83+
->tag('property_info.initializable_extractor', ['priority' => -1000]);
84+
85+
if (class_exists(DocBlockFactory::class)) {
86+
$services->set('api_platform.property_info.php_doc_extractor', PhpDocExtractor::class)
87+
->tag('property_info.description_extractor', ['priority' => -1000])
88+
->tag('property_info.type_extractor', ['priority' => -1001]);
89+
}
90+
91+
if (class_exists(PhpDocParser::class) && class_exists(ContextFactory::class)) {
92+
$services->set('api_platform.property_info.phpstan_extractor', PhpStanExtractor::class)
93+
->tag('property_info.type_extractor', ['priority' => -1000]);
94+
}
95+
96+
$services->set('api_platform.property_info', PropertyInfoExtractor::class)
97+
->args([
98+
tagged_iterator('property_info.list_extractor'),
99+
tagged_iterator('property_info.type_extractor'),
100+
tagged_iterator('property_info.description_extractor'),
101+
tagged_iterator('property_info.access_extractor'),
102+
tagged_iterator('property_info.initializable_extractor'),
103+
]);
104+
105+
$services->set('api_platform.property_info.cache', PropertyInfoCacheExtractor::class)
106+
->decorate('api_platform.property_info')
107+
->args([
108+
service('.inner'),
109+
service('cache.property_info'),
110+
]);
72111

73112
$services->set('api_platform.negotiator', Negotiator::class);
74113

src/Symfony/Tests/Bundle/DependencyInjection/ApiPlatformExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ public function testCommonConfiguration(): void
190190
'api_platform.path_segment_name_generator.dash',
191191
'api_platform.path_segment_name_generator.underscore',
192192
'api_platform.metadata.inflector',
193+
'api_platform.property_info',
193194
'api_platform.resource_class_resolver',
194195
'api_platform.route_loader',
195196
'api_platform.router',
@@ -231,7 +232,6 @@ public function testCommonConfiguration(): void
231232
'api_platform.iri_converter',
232233
'api_platform.path_segment_name_generator',
233234
'api_platform.property_accessor',
234-
'api_platform.property_info',
235235
'api_platform.serializer',
236236
'api_platform.inflector',
237237
];

tests/Symfony/Bundle/ApiPlatformBundleTest.php

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,38 +29,36 @@
2929
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\TestClientPass;
3030
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\TestMercureHubPass;
3131
use PHPUnit\Framework\TestCase;
32-
use Prophecy\Argument;
33-
use Prophecy\PhpUnit\ProphecyTrait;
34-
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
3532
use Symfony\Component\DependencyInjection\ContainerBuilder;
3633

3734
/**
3835
* @author Kévin Dunglas <dunglas@gmail.com>
3936
*/
4037
class ApiPlatformBundleTest extends TestCase
4138
{
42-
use ProphecyTrait;
43-
4439
public function testBuild(): void
4540
{
46-
$containerProphecy = $this->prophesize(ContainerBuilder::class);
47-
// TODO: remove in 5.x
48-
$containerProphecy->addCompilerPass(Argument::type(DataProviderPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
49-
$containerProphecy->addCompilerPass(Argument::type(AttributeFilterPass::class), PassConfig::TYPE_BEFORE_OPTIMIZATION, 101)->willReturn($containerProphecy->reveal())->shouldBeCalled();
50-
$containerProphecy->addCompilerPass(Argument::type(AttributeResourcePass::class))->shouldBeCalled()->willReturn($containerProphecy->reveal())->shouldBeCalled();
51-
$containerProphecy->addCompilerPass(Argument::type(FilterPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
52-
$containerProphecy->addCompilerPass(Argument::type(ElasticsearchClientPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
53-
$containerProphecy->addCompilerPass(Argument::type(GraphQlTypePass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
54-
$containerProphecy->addCompilerPass(Argument::type(GraphQlResolverPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
55-
$containerProphecy->addCompilerPass(Argument::type(MetadataAwareNameConverterPass::class), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100)->willReturn($containerProphecy->reveal())->shouldBeCalled();
56-
$containerProphecy->addCompilerPass(Argument::type(TestClientPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
57-
$containerProphecy->addCompilerPass(Argument::type(TestMercureHubPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
58-
$containerProphecy->addCompilerPass(Argument::type(AuthenticatorManagerPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
59-
$containerProphecy->addCompilerPass(Argument::type(SerializerMappingLoaderPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
60-
$containerProphecy->addCompilerPass(Argument::type(MutatorPass::class))->willReturn($containerProphecy->reveal())->shouldBeCalled();
61-
$containerProphecy->addCompilerPass(Argument::type(JsonStreamerTransformerPass::class), PassConfig::TYPE_BEFORE_OPTIMIZATION, -10)->willReturn($containerProphecy->reveal())->shouldBeCalled();
62-
41+
$container = new ContainerBuilder();
6342
$bundle = new ApiPlatformBundle();
64-
$bundle->build($containerProphecy->reveal());
43+
$bundle->build($container);
44+
45+
$passes = $container->getCompilerPassConfig()->getBeforeOptimizationPasses();
46+
$passClasses = array_map(static fn (object $p): string => $p::class, $passes);
47+
48+
// TODO: remove in 5.x
49+
$this->assertContains(DataProviderPass::class, $passClasses);
50+
$this->assertContains(AttributeFilterPass::class, $passClasses);
51+
$this->assertContains(AttributeResourcePass::class, $passClasses);
52+
$this->assertContains(FilterPass::class, $passClasses);
53+
$this->assertContains(ElasticsearchClientPass::class, $passClasses);
54+
$this->assertContains(GraphQlTypePass::class, $passClasses);
55+
$this->assertContains(GraphQlResolverPass::class, $passClasses);
56+
$this->assertContains(MetadataAwareNameConverterPass::class, $passClasses);
57+
$this->assertContains(TestClientPass::class, $passClasses);
58+
$this->assertContains(TestMercureHubPass::class, $passClasses);
59+
$this->assertContains(AuthenticatorManagerPass::class, $passClasses);
60+
$this->assertContains(SerializerMappingLoaderPass::class, $passClasses);
61+
$this->assertContains(MutatorPass::class, $passClasses);
62+
$this->assertContains(JsonStreamerTransformerPass::class, $passClasses);
6563
}
6664
}

0 commit comments

Comments
 (0)