Merge branch '6.4' into 7.4

* 6.4:
  [DependencyInjection][HttpKernel] Fix parsing Target attributes on properties and on controllers
This commit is contained in:
Nicolas Grekas
2026-01-29 15:29:36 +01:00
3 changed files with 51 additions and 4 deletions

View File

@@ -198,8 +198,10 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE);
++$erroredIds;
} else {
$target = preg_replace('/(^|[(|&])\\\\/', '\1', $target);
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, Target::parseName($p)) : new Reference($target, $invalidBehavior);
$targetAttribute = null;
$name = Target::parseName($p, $targetAttribute);
$target = preg_replace('/(^|[(|&])\\\\/', '\\1', $target);
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, $name, $targetAttribute ? [$targetAttribute] : []) : new Reference($target, $invalidBehavior);
}
}
// register the maps as a per-method service-locators

View File

@@ -462,12 +462,35 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
$expected = [
'apiKey' => new ServiceClosureArgument(new Reference('the_api_key')),
'service1' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'imageStorage')),
'service1' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'imageStorage', [new Target('image.storage')])),
'service2' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'service2')),
];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function testTargetAttributeUsesShortNameForControllerArguments()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('limiter.anonymous_action', DummyRateLimiterFactory::class);
$container->registerAliasForArgument('limiter.anonymous_action', DummyLimiterFactoryInterface::class, 'anonymous_action.limiter', 'anonymous_action');
$container->register('foo', WithTargetShortName::class)
->addTag('controller.service_arguments');
(new RegisterControllerArgumentLocatorsPass())->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$argument = $locator->getArgument(0)['limiterFactory']->getValues()[0];
$this->assertInstanceOf(TypedReference::class, $argument);
$this->assertSame(DummyLimiterFactoryInterface::class, $argument->getType());
$this->assertSame('anonymous_action', $argument->getName());
$this->assertEquals([new Target('anonymous_action')], $argument->getAttributes());
}
public function testResponseArgumentIsIgnored()
{
$container = new ContainerBuilder();
@@ -715,6 +738,28 @@ class WithTarget
}
}
class WithTargetShortName
{
public function fooAction(
#[Target('anonymous_action')]
DummyLimiterFactoryInterface $limiterFactory,
) {
}
}
interface DummyLimiterFactoryInterface
{
public function create(mixed $key = null): object;
}
class DummyRateLimiterFactory implements DummyLimiterFactoryInterface
{
public function create(mixed $key = null): object
{
throw new \BadMethodCallException('Not used in tests.');
}
}
class WithResponseArgument
{
public function fooAction(Response $response, ?Response $nullableResponse)

View File

@@ -30,7 +30,7 @@
"symfony/config": "^6.4|^7.0|^8.0",
"symfony/console": "^6.4|^7.0|^8.0",
"symfony/css-selector": "^6.4|^7.0|^8.0",
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
"symfony/dependency-injection": "^6.4.1|^7.0.1|^8.0",
"symfony/dom-crawler": "^6.4|^7.0|^8.0",
"symfony/expression-language": "^6.4|^7.0|^8.0",
"symfony/finder": "^6.4|^7.0|^8.0",