diff --git a/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php b/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php index 7ddf3e72186d6..ffff3006f7184 100644 --- a/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php +++ b/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php @@ -35,6 +35,8 @@ public function __construct( private ManagerRegistry $registry, private ?ExpressionLanguage $expressionLanguage = null, private MapEntity $defaults = new MapEntity(), + /** @var array */ + private readonly array $typeAliases = [], ) { } @@ -50,6 +52,9 @@ public function resolve(Request $request, ArgumentMetadata $argument): array if (!$options->class || $options->disabled) { return []; } + + $options->class = $this->typeAliases[$options->class] ?? $options->class; + if (!$manager = $this->getManager($options->objectManager, $options->class)) { return []; } diff --git a/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php b/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php index 73d73d58b23bb..c9d07ed389244 100644 --- a/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php +++ b/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php @@ -53,7 +53,7 @@ public function __construct( public function withDefaults(self $defaults, ?string $class): static { $clone = clone $this; - $clone->class ??= class_exists($class ?? '') ? $class : null; + $clone->class ??= class_exists($class ?? '') || interface_exists($class ?? '', false) ? $class : null; $clone->objectManager ??= $defaults->objectManager; $clone->expr ??= $defaults->expr; $clone->mapping ??= $defaults->mapping; diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index f1133dfefe9a6..5e1448edaa90c 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Accept `ReadableCollection` in `CollectionToArrayTransformer` + * Add type aliases support to `EntityValueResolver` 7.1 --- diff --git a/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php b/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php index baa7b1c345359..121dfcb633124 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php @@ -125,6 +125,42 @@ public function testResolveWithId(string|int $id) $this->assertSame([$object], $resolver->resolve($request, $argument)); } + /** + * @dataProvider idsProvider + */ + public function testResolveWithIdAndTypeAlias(string|int $id) + { + $manager = $this->getMockBuilder(ObjectManager::class)->getMock(); + $registry = $this->createRegistry($manager); + $resolver = new EntityValueResolver( + $registry, + null, + new MapEntity(), + // Using \Throwable because it is an interface + ['Throwable' => 'stdClass'], + ); + + $request = new Request(); + $request->attributes->set('id', $id); + + $argument = $this->createArgument('Throwable', $mapEntity = new MapEntity(id: 'id')); + + $repository = $this->getMockBuilder(ObjectRepository::class)->getMock(); + $repository->expects($this->once()) + ->method('find') + ->with($id) + ->willReturn($object = new \stdClass()); + + $manager->expects($this->once()) + ->method('getRepository') + ->with('stdClass') + ->willReturn($repository); + + $this->assertSame([$object], $resolver->resolve($request, $argument)); + // Ensure the original MapEntity object was not updated + $this->assertNull($mapEntity->class); + } + public function testResolveWithNullId() { $manager = $this->createMock(ObjectManager::class);