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

Skip to content

Commit e9870a4

Browse files
feature #48707 [DependencyInjection] Target Attribute must fail if the target does not exist (rodmen)
This PR was merged into the 6.3 branch. Discussion ---------- [DependencyInjection] Target Attribute must fail if the target does not exist | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #48555 | License | MIT | Doc PR | - This change checks if an attribute is a Target to not auto bind with a new default object if the target name does not exists. The existent behavior should be in charge of suggest possible options for a typo on the Target name. I can't mark `allow edit by maintainers` I think because I'm open the PR from a organization repo. Commits ------- 983cd08 [DependencyInjection] Target Attribute must fail if the target does not exist
2 parents 516e8d9 + 983cd08 commit e9870a4

File tree

5 files changed

+31
-5
lines changed

5 files changed

+31
-5
lines changed

src/Symfony/Component/DependencyInjection/Attribute/Target.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ public function __construct(string $name)
2828
$this->name = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name))));
2929
}
3030

31-
public static function parseName(\ReflectionParameter $parameter): string
31+
public static function parseName(\ReflectionParameter $parameter, self &$attribute = null): string
3232
{
33+
$attribute = null;
3334
if (!$target = $parameter->getAttributes(self::class)[0] ?? null) {
3435
return $parameter->name;
3536
}
3637

37-
$name = $target->newInstance()->name;
38+
$attribute = $target->newInstance();
39+
$name = $attribute->name;
3840

3941
if (!preg_match('/^[a-zA-Z_\x7f-\xff]/', $name)) {
4042
if (($function = $parameter->getDeclaringFunction()) instanceof \ReflectionMethod) {

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ CHANGELOG
99
* Add `RemoveBuildParametersPass`, which removes parameters starting with a dot during compilation
1010
* Add support for nesting autowiring-related attributes into `#[Autowire(...)]`
1111
* Deprecate undefined and numeric keys with `service_locator` config
12+
* Fail if Target attribute does not exist during compilation
1213

1314
6.2
1415
---

src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ private function doProcessValue(mixed $value, bool $isRoot = false): mixed
128128
return $this->processAttribute($attribute, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $value->getInvalidBehavior());
129129
}
130130

131-
$value = new TypedReference($value->getType(), $value->getType(), $value->getInvalidBehavior(), $attribute->name);
131+
$value = new TypedReference($value->getType(), $value->getType(), $value->getInvalidBehavior(), $attribute->name, [$attribute]);
132132
}
133133
if ($ref = $this->getAutowiredReference($value, true)) {
134134
return $ref;
@@ -332,7 +332,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
332332
}
333333

334334
$getValue = function () use ($type, $parameter, $class, $method) {
335-
if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, Target::parseName($parameter)), false)) {
335+
$name = Target::parseName($parameter, $target);
336+
if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $name, $target ? [$target] : []), false)) {
336337
$failureMessage = $this->createTypeNotFoundMessageCallback($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
337338

338339
if ($parameter->isDefaultValueAvailable()) {
@@ -420,6 +421,10 @@ private function getAutowiredReference(TypedReference $reference, bool $filterTy
420421
}
421422
}
422423
}
424+
425+
if ($reference->getAttributes()) {
426+
return null;
427+
}
423428
}
424429

425430
if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) {
@@ -544,6 +549,9 @@ private function createTypeNotFoundMessage(TypedReference $reference, string $la
544549
}
545550

546551
$message = sprintf('has type "%s" but this class %s.', $type, $parentMsg ? sprintf('is missing a parent class (%s)', $parentMsg) : 'was not found');
552+
} elseif ($reference->getAttributes()) {
553+
$message = $label;
554+
$label = sprintf('"#[Target(\'%s\')" on', $reference->getName());
547555
} else {
548556
$alternatives = $this->createTypeAlternatives($this->container, $reference);
549557
$message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';

src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,21 @@ public function testArgumentWithTarget()
11421142
$this->assertSame(BarInterface::class.' $imageStorage', (string) $container->getDefinition('with_target')->getArgument(0));
11431143
}
11441144

1145+
public function testArgumentWithTypoTarget()
1146+
{
1147+
$container = new ContainerBuilder();
1148+
1149+
$container->register(BarInterface::class, BarInterface::class);
1150+
$container->register(BarInterface::class.' $iamgeStorage', BarInterface::class);
1151+
$container->register('with_target', WithTarget::class)
1152+
->setAutowired(true);
1153+
1154+
$this->expectException(AutowiringFailedException::class);
1155+
$this->expectExceptionMessage('Cannot autowire service "with_target": "#[Target(\'imageStorage\')" on argument "$bar" of method "Symfony\Component\DependencyInjection\Tests\Fixtures\WithTarget::__construct()"');
1156+
1157+
(new AutowirePass())->process($container);
1158+
}
1159+
11451160
public function testDecorationWithServiceAndAliasedInterface()
11461161
{
11471162
$container = new ContainerBuilder();

src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ public static function getSubscribedServices(): array
463463
'autowired.nullable' => new ServiceClosureArgument(new Reference('service.id', ContainerInterface::NULL_ON_INVALID_REFERENCE)),
464464
'autowired.parameter' => new ServiceClosureArgument('foobar'),
465465
'map.decorated' => new ServiceClosureArgument(new Reference('.service_locator.oZHAdom.inner', ContainerInterface::NULL_ON_INVALID_REFERENCE)),
466-
'target' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 'someTarget')),
466+
'target' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 'someTarget', [new Target('someTarget')])),
467467
];
468468
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
469469
}

0 commit comments

Comments
 (0)