8000 [DI] Allow binding by type+name · symfony/symfony@32fc58d · GitHub
[go: up one dir, main page]

Skip to content

Commit 32fc58d

Browse files
[DI] Allow binding by type+name
1 parent cada38f commit 32fc58d

File tree

8 files changed

+65
-13
lines changed

8 files changed

+65
-13
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
208208
continue;
209209
}
210210
$type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, false);
211-
$type = $type ? sprintf('is type-hinted "%s"', $type) : 'has no type-hint';
211+
$type = $type ? sprintf('is type-hinted "%s"', ltrim($type, '\\')) : 'has no type-hint';
212212

213213
throw new AutowiringFailedException($this->currentId, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" %s, you should configure its value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method, $type));
214214
}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ protected function processValue($value, $isRoot = false)
7474
$this->unusedBindings[$bindingId] = array($key, $this->currentId);
7575
}
7676

77-
if (isset($key[0]) && '$' === $key[0]) {
77+
if (preg_match('/^(?:(?:array|bool|float|int|string) )?\$/', $key)) {
7878
continue;
7979
}
8080

@@ -113,15 +113,21 @@ protected function processValue($value, $isRoot = false)
113113
continue;
114114
}
115115

116+
$typeHint = ProxyHelper::getTypeHint($reflectionMethod, $parameter);
117+
118+
if (array_key_exists($k = ltrim($typeHint, '\\').' $'.$parameter->name, $bindings)) {
119+
$arguments[$key] = $this->getBindingValue($bindings[$k]);
120+
121+
continue;
122+
}
123+
116124
if (array_key_exists('$'.$parameter->name, $bindings)) {
117125
$arguments[$key] = $this->getBindingValue($bindings['$'.$parameter->name]);
118126

119127
continue;
120128
}
121129

122-
$typeHint = ProxyHelper::getTypeHint($reflectionMethod, $parameter, true);
123-
124-
if (!isset($bindings[$typeHint])) {
130+
if (!$typeHint || '\\' !== $typeHint[0] || !isset($bindings[$typeHint = substr($typeHint, 1)])) {
125131
continue;
126132
}
127133

src/Symfony/Component/DependencyInjection/Definition.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,10 @@ public function getBindings()
859859
public function setBindings(array $bindings)
860860
{
861861
foreach ($bindings as $key => $binding) {
862+
if (0 < strpos($key, '$') && $key !== $k = preg_replace('/[ \t]*\$/', ' $', $key)) {
863+
unset($bindings[$key]);
864+
$bindings[$key = $k] = $binding;
865+
}
862866
if (!$binding instanceof BoundArgument) {
863867
$bindings[$key] = new BoundArgument($binding);
864868
}

src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ trait BindTrait
3131
final public function bind($nameOrFqcn, $valueOrRef)
3232
{
3333
$valueOrRef = static::processValue($valueOrRef, true);
34-
if (isset($nameOrFqcn[0]) && '$' !== $nameOrFqcn[0] && !$valueOrRef instanceof Reference) {
34+
if (!preg_match('/^(?:(?:array|bool|float|int|string)[ \t]*+)?\$/', $nameOrFqcn) && !$valueOrRef instanceof Reference) {
3535
throw new InvalidArgumentException(sprintf('Invalid binding for service "%s": named arguments must start with a "$", and FQCN must map to references. Neither applies to binding "%s".', $this->id, $nameOrFqcn));
3636
}
3737
$bindings = $this->definition->getBindings();

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,28 @@ public function testScalarSetter()
9595

9696
$this->assertEquals(array(array('setDefaultLocale', array('fr'))), $definition->getMethodCalls());
9797
}
98+
99+
public function testTupleBinding()
100+
{
101+
$container = new ContainerBuilder();
102+
103+
$bindings = array(
104+
'$c' => new BoundArgument(new Reference('bar')),
105+
CaseSensitiveClass::class.'$c' => new BoundArgument(new Reference('foo')),
106+
);
107+
108+
$definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class);
109+
$definition->addMethodCall('setSensitiveClass');
110+
$definition->addMethodCall('setAnotherC');
111+
$definition->setBindings($bindings);
112+
113+
$pass = new ResolveBindingsPass();
114+
$pass->process($container);
115+
116+
$expected = array(
117+
array('setSensitiveClass', array(new Reference('foo'))),
118+
array('setAnotherC', array(new Reference('bar'))),
119+
);
120+
$this->assertEquals($expected, $definition->getMethodCalls());
121+
}
98122
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedArgumentsDummy.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ public function setApiKey($apiKey)
1818
public function setSensitiveClass(CaseSensitiveClass $c)
1919
{
2020
}
21+
22+
public function setAnotherC($c)
23+
{
24+
}
2125
}

src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public function process(ContainerBuilder $container)
120120
$args = array();
121121
foreach ($parameters as $p) {
122122
/** @var \ReflectionParameter $p */
123-
$type = $target = ProxyHelper::getTypeHint($r, $p, true);
123+
$type = ltrim($target = ProxyHelper::getTypeHint($r, $p), '\\');
124124
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
125125

126126
if (isset($arguments[$r->name][$p->name])) {
@@ -132,7 +132,7 @@ public function process(ContainerBuilder $container)
132132
} elseif ($p->allowsNull() && !$p->isOptional()) {
133133
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
134134
}
135-
} elseif (isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) {
135+
} elseif (isset($bindings[$bindingName = $type.' $'.$p->name]) || isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) {
136136
$binding = $bindings[$bindingName];
137137

138138
list($bindingValue, $bindingId) = $binding->getValues();
@@ -148,7 +148,7 @@ public function process(ContainerBuilder $container)
148148
}
149149

150150
continue;
151-
} elseif (!$type || !$autowire) {
151+
} elseif (!$type || !$autowire || '\\' !== $target[0]) {
152152
continue;
153153
} elseif (!$p->allowsNull()) {
154154
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
@@ -169,6 +169,7 @@ public function process(ContainerBuilder $container)
169169
throw new InvalidArgumentException($message);
170170
}
171171

172+
$target = ltrim($target, '\\');
172173
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior) : new Reference($target, $invalidBehavior);
173174
}
174175
// register the maps as a per-method service-locators

src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,16 +308,23 @@ public function testBindings($bindingName)
308308

309309
public function provideBindings()
310310
{
311-
return array(array(ControllerDummy::class), array('$bar'));
311+
return array(
312+
array(ControllerDummy::class.'$bar'),
313+
array(ControllerDummy::class),
314+
array('$bar'),
315+
);
312316
}
313317

314-
public function testBindScalarValueToControllerArgument()
318+
/**
319+
* @dataProvider provideBindScalarValueToControllerArgument
320+
*/
321+
public function testBindScalarValueToControllerArgument($bindingKey)
315322
{
316323
$container = new ContainerBuilder();
317324
$resolver = $container->register('argument_resolver.service')->addArgument(array());
318325

319326
$container->register('foo', ArgumentWithoutTypeController::class)
320-
->setBindings(array('$someArg' => '%foo%'))
327+
->setBindings(array($bindingKey => '%foo%'))
321328
->addTag('controller.service_arguments');
322329

323330
$container->setParameter('foo', 'foo_val');
@@ -339,6 +346,12 @@ public function testBindScalarValueToControllerArgument()
339346
$this->assertTrue($container->has((string) $reference));
340347
$this->assertSame('foo_val', $container->get((string) $reference));
341348
}
349+
350+
public function provideBindScalarValueToControllerArgument()
351+
{
352+
yield array('$someArg');
353+
yield array('string $someArg');
354+
}
342355
}
343356

344357
class RegisterTestController
@@ -396,7 +409,7 @@ public function barAction(NonExistentClass $nonExistent = null, $bar)
396409

397410
class ArgumentWithoutTypeController
398411
{
399-
public function fooAction($someArg)
412+
public function fooAction(string $someArg)
400413
{
401414
}
402415
}

0 commit comments

Comments
 (0)
0