Skip to content

Commit 2a8bd95

Browse files
committed
[#17878] Fixing a bug where scalar values caused invalid ordering
1 parent 9868039 commit 2a8bd95

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ private function completeDefinition($id, Definition $definition)
7878

7979
try {
8080
if (!$typeHint = $parameter->getClass()) {
81+
// no default value? Then fail
82+
if (!$parameter->isOptional()) {
83+
throw new RuntimeException(sprintf('Unable to autowire argument index %s ($%s) for the service "%s". If this is an object, give it a type-hint. Otherwise, specify this argument\'s value explicitly.', $index, $parameter->name, $id));
84+
}
85+
86+
// specifically pass the default value
87+
$arguments[$index] = $parameter->getDefaultValue();
88+
8189
continue;
8290
}
8391

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

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,6 @@ public function testSomeSpecificArgumentsAreSet()
301301
$pass->process($container);
302302

303303
$definition = $container->getDefinition('multiple');
304-
// takes advantage of Reference's __toString
305304
$this->assertEquals(
306305
array(
307306
new Reference('a'),
@@ -311,6 +310,92 @@ public function testSomeSpecificArgumentsAreSet()
311310
$definition->getArguments()
312311
);
313312
}
313+
314+
/**
315+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
316+
* @expectedExceptionMessage Unable to autowire argument index 1 ($foo) for the service "arg_no_type_hint". If this is an object, give it a type-hint. Otherwise, specify this argument's value explicitly.
317+
*/
318+
public function testScalarArgsCannotBeAutowired()
319+
{
320+
$container = new ContainerBuilder();
321+
322+
$container->register('a', __NAMESPACE__ . '\A');
323+
$container->register('dunglas', __NAMESPACE__.'\Dunglas');
324+
$container->register('arg_no_type_hint', __NAMESPACE__ . '\MultipleArguments')
325+
->setAutowired(true);
326+
327+
$pass = new AutowirePass();
328+
$pass->process($container);
329+
330+
$container->getDefinition('arg_no_type_hint');
331+
}
332+
333+
/**
334+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
335+
* @expectedExceptionMessage Unable to autowire argument index 1 ($foo) for the service "not_really_optional_scalar". If this is an object, give it a type-hint. Otherwise, specify this argument's value explicitly.
336+
*/
337+
public function testOptionalScalarNotReallyOptionalThrowException()
338+
{
339+
$container = new ContainerBuilder();
340+
341+
$container->register('a', __NAMESPACE__ . '\A');
342+
$container->register('lille', __NAMESPACE__ . '\Lille');
343+
$container->register('not_really_optional_scalar', __NAMESPACE__ . '\MultipleArgumentsOptionalScalarNotReallyOptional')
344+
->setAutowired(true);
345+
346+
$pass = new AutowirePass();
347+
$pass->process($container);
348+
}
349+
350+
public function testOptionalScalarArgsDontMessUpOrder()
351+
{
352+
$container = new ContainerBuilder();
353+
354+
$container->register('a', __NAMESPACE__ . '\A');
355+
$container->register('lille', __NAMESPACE__ . '\Lille');
356+
$container->register('with_optional_scalar', __NAMESPACE__ . '\MultipleArgumentsOptionalScalar')
357+
->setAutowired(true);
358+
359+
$pass = new AutowirePass();
360+
$pass->process($container);
361+
362+
$definition = $container->getDefinition('with_optional_scalar');
363+
$this->assertEquals(
364+
array(
365+
new Reference('a'),
366+
// use the default value
367+
'default_val',
368+
new Reference('lille'),
369+
),
370+
$definition->getArguments()
371+
);
372+
}
373+
374+
public function testOptionalScalarArgsNotPassedIfLast()
375+
{
376+
$container = new ContainerBuilder();
377+
378+
$container->register('a', __NAMESPACE__ . '\A');
379+
$container->register('lille', __NAMESPACE__ . '\Lille');
380+
$container->register('with_optional_scalar_last', __NAMESPACE__ . '\MultipleArgumentsOptionalScalarLast')
381+
->setAutowired(true);
382+
383+
$pass = new AutowirePass();
384+
$pass->process($container);
385+
386+
$definition = $container->getDefinition('with_optional_scalar_last');
387+
$this->assertEquals(
388+
array(
389+
new Reference('a'),
390+
new Reference('lille'),
391+
// third arg shouldn't *need* to be passed
392+
// but that's hard to "pull of" with autowiring, so
393+
// this assumes passing the default val is ok
394+
'some_val'
395+
),
396+
$definition->getArguments()
397+
);
398+
}
314399
}
315400

316401
class Foo
@@ -432,4 +517,23 @@ class MultipleArguments
432517
public function __construct(A $k, $foo, Dunglas $dunglas)
433518
{
434519
}
520+
}
521+
522+
class MultipleArgumentsOptionalScalar
523+
{
524+
public function __construct(A $a, $foo = 'default_val', Lille $lille = null)
525+
{
526+
}
527+
}
528+
class MultipleArgumentsOptionalScalarLast
529+
{
530+
public function __construct(A $a, Lille $lille, $foo = 'some_val')
531+
{
532+
}
533+
}
534+
class MultipleArgumentsOptionalScalarNotReallyOptional
535+
{
536+
public function __construct(A $a, $foo = 'default_val', Lille $lille)
537+
{
538+
}
435539
}

0 commit comments

Comments
 (0)