Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a04cfae

Browse files
committed
[DoctrineBridge] Add argument to EntityValueResolver to set type aliases
This allows for fixing #51765; with a consequential Doctrine bundle update, the resolve_target_entities configuration can be injected similarly to ResolveTargetEntityListener in the Doctrine codebase. Alternatively the config and ValueResolver can be injected using a compiler pass in the Symfony core code, however the value resolver seems to be configured in the Doctrine bundle already.
1 parent 9b323c6 commit a04cfae

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,27 @@
3131
*/
3232
final class EntityValueResolver implements ValueResolverInterface
3333
{
34+
/** @var array<class-string, class-string> */
35+
private array $typeAliases = [];
36+
3437
public function __construct(
3538
private ManagerRegistry $registry,
3639
private ?ExpressionLanguage $expressionLanguage = null,
3740
private MapEntity $defaults = new MapEntity(),
3841
) {
3942
}
4043

44+
/**
45+
* Adds an original class name to resolve to a target class name.
46+
*
47+
* @param class-string $original
48+
* @param class-string $target
49+
*/
50+
public function addTypeAlias(string $original, string $target): void
51+
{
52+
$this->typeAliases[ltrim($original, '\\')] = ltrim($target, '\\');
53+
}
54+
4155
public function resolve(Request $request, ArgumentMetadata $argument): array
4256
{
4357
if (\is_object($request->attributes->get($argument->getName()))) {
@@ -50,6 +64,13 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
5064
if (!$options->class || $options->disabled) {
5165
return [];
5266
}
67+
68+
if (isset($this->typeAliases[$options->class])) {
69+
// Overwriting the property of MapEntity at this point is safe,
70+
// since withDefaults called above created a clone of the original object.
71+
$options->class = $this->typeAliases[$options->class];
72+
}
73+
5374
if (!$manager = $this->getManager($options->objectManager, $options->class)) {
5475
return [];
5576
}

src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function __construct(
5252
public function withDefaults(self $defaults, ?string $class): static
5353
{
5454
$clone = clone $this;
55-
$clone->class ??= class_exists($class ?? '') ? $class : null;
55+
$clone->class ??= class_exists($class ?? '') || interface_exists($class ?? '', false) ? $class : null;
5656
$clone->objectManager ??= $defaults->objectManager;
5757
$clone->expr ??= $defaults->expr;
5858
$clone->mapping ??= $defaults->mapping;

src/Symfony/Bridge/Doctrine/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
7.1
55
---
66

7+
* Add type aliases support to `EntityValueResolver` through the `addTypeAlias` method
78
* Deprecate the `DoctrineExtractor::getTypes()` method, use `DoctrineExtractor::getType()` instead
89

910
7.0

src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,42 @@ public function testResolveWithId(string|int $id)
130130
$this->assertSame([$object], $resolver->resolve($request, $argument));
131131
}
132132

133+
/**
134+
* @dataProvider idsProvider
135+
*/
136+
public function testResolveWithIdAndTypeAlias(string|int $id)
137+
{
138+
$manager = $this->getMockBuilder(ObjectManager::class)->getMock();
139+
$registry = $this->createRegistry($manager);
140+
$resolver = new EntityValueResolver(
141+
$registry,
142+
null,
143+
new MapEntity(),
144+
);
145+
// Using \Throwable here because it is built in to PHP and an interface.
146+
$resolver->addTypeAlias('Throwable', 'stdClass');
147+
148+
$request = new Request();
149+
$request->attributes->set('id', $id);
150+
151+
$argument = $this->createArgument('Throwable', $mapEntity = new MapEntity(id: 'id'));
152+
153+
$repository = $this->getMockBuilder(ObjectRepository::class)->getMock();
154+
$repository->expects($this->once())
155+
->method('find')
156+
->with($id)
157+
->willReturn($object = new \stdClass());
158+
159+
$manager->expects($this->once())
160+
->method('getRepository')
161+
->with('stdClass')
162+
->willReturn($repository);
163+
164+
$this->assertSame([$object], $resolver->resolve($request, $argument));
165+
// Ensure the original MapEntity object was not updated
166+
$this->assertNull($mapEntity->class);
167+
}
168+
133169
public function testResolveWithNullId()
134170
{
135171
$manager = $this->getMockBuilder(ObjectManager::class)->getMock();

0 commit comments

Comments
 (0)