Skip to content

Commit 9d54eec

Browse files
committed
Merge branch '3.0'
* 3.0: fixed issue with PHP 5.3 The WebProcessor now forwards the client IP minor changes [#17878] Fixing a bug where scalar values caused invalid ordering [#17724] Fixing autowiring bug where if some args are set, new ones are put in the wrong spot bumped Symfony version to 2.3.39 updated VERSION for 2.3.38 update CONTRIBUTORS for 2.3.38 updated CHANGELOG for 2.3.38
2 parents c6c4ab9 + dfcf29b commit 9d54eec

File tree

2 files changed

+155
-7
lines changed

2 files changed

+155
-7
lines changed

Compiler/AutowirePass.php

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,20 @@ private function completeDefinition($id, Definition $definition)
7171

7272
$arguments = $definition->getArguments();
7373
foreach ($constructor->getParameters() as $index => $parameter) {
74-
$argumentExists = array_key_exists($index, $arguments);
75-
if ($argumentExists && '' !== $arguments[$index]) {
74+
if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
7675
continue;
7776
}
7877

7978
try {
8079
if (!$typeHint = $parameter->getClass()) {
80+
// no default value? Then fail
81+
if (!$parameter->isOptional()) {
82+
throw new RuntimeException(sprintf('Unable to autowire argument index %d ($%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));
83+
}
84+
85+
// specifically pass the default value
86+
$arguments[$index] = $parameter->getDefaultValue();
87+
8188
continue;
8289
}
8390

@@ -110,12 +117,13 @@ private function completeDefinition($id, Definition $definition)
110117
$value = $parameter->getDefaultValue();
111118
}
112119

113-
if ($argumentExists) {
114-
$definition->replaceArgument($index, $value);
115-
} else {
116-
$definition->addArgument($value);
117-
}
120+
$arguments[$index] = $value;
118121
}
122+
123+
// it's possible index 1 was set, then index 0, then 2, etc
124+
// make sure that we re-order so they're injected as expected
125+
ksort($arguments);
126+
$definition->setArguments($arguments);
119127
}
120128

121129
/**

Tests/Compiler/AutowirePassTest.php

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,121 @@ public function testDontUseAbstractServices()
297297
$arguments = $container->getDefinition('bar')->getArguments();
298298
$this->assertSame('foo', (string) $arguments[0]);
299299
}
300+
301+
public function testSomeSpecificArgumentsAreSet()
302+
{
303+
$container = new ContainerBuilder();
304+
305+
$container->register('foo', __NAMESPACE__.'\Foo');
306+
$container->register('a', __NAMESPACE__.'\A');
307+
$container->register('dunglas', __NAMESPACE__.'\Dunglas');
308+
$container->register('multiple', __NAMESPACE__.'\MultipleArguments')
309+
->setAutowired(true)
310+
// set the 2nd (index 1) argument only: autowire the first and third
311+
// args are: A, Foo, Dunglas
312+
->setArguments(array(
313+
1 => new Reference('foo'),
314+
));
315+
316+
$pass = new AutowirePass();
317+
$pass->process($container);
318+
319+
$definition = $container->getDefinition('multiple');
320+
$this->assertEquals(
321+
array(
322+
new Reference('a'),
323+
new Reference('foo'),
324+
new Reference('dunglas'),
325+
),
326+
$definition->getArguments()
327+
);
328+
}
329+
330+
/**
331+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
332+
* @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.
333+
*/
334+
public function testScalarArgsCannotBeAutowired()
335+
{
336+
$container = new ContainerBuilder();
337+
338+
$container->register('a', __NAMESPACE__.'\A');
339+
$container->register('dunglas', __NAMESPACE__.'\Dunglas');
340+
$container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
341+
->setAutowired(true);
342+
343+
$pass = new AutowirePass();
344+
$pass->process($container);
345+
346+
$container->getDefinition('arg_no_type_hint');
347+
}
348+
349+
/**
350+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
351+
* @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.
352+
*/
353+
public function testOptionalScalarNotReallyOptionalThrowException()
354+
{
355+
$container = new ContainerBuilder();
356+
357+
$container->register('a', __NAMESPACE__.'\A');
358+
$container->register('lille', __NAMESPACE__.'\Lille');
359+
$container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional')
360+
->setAutowired(true);
361+
362+
$pass = new AutowirePass();
363+
$pass->process($container);
364+
}
365+
366+
public function testOptionalScalarArgsDontMessUpOrder()
367+
{
368+
$container = new ContainerBuilder();
369+
370+
$container->register('a', __NAMESPACE__.'\A');
371+
$container->register('lille', __NAMESPACE__.'\Lille');
372+
$container->register('with_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalar')
373+
->setAutowired(true);
374+
375+
$pass = new AutowirePass();
376+
$pass->process($container);
377+
378+
$definition = $container->getDefinition('with_optional_scalar');
379+
$this->assertEquals(
380+
array(
381+
new Reference('a'),
382+
// use the default value
383+
'default_val',
384+
new Reference('lille'),
385+
),
386+
$definition->getArguments()
387+
);
388+
}
389+
390+
public function testOptionalScalarArgsNotPassedIfLast()
391+
{
392+
$container = new ContainerBuilder();
393+
394+
$container->register('a', __NAMESPACE__.'\A');
395+
$container->register('lille', __NAMESPACE__.'\Lille');
396+
$container->register('with_optional_scalar_last', __NAMESPACE__.'\MultipleArgumentsOptionalScalarLast')
397+
->setAutowired(true);
398+
399+
$pass = new AutowirePass();
400+
$pass->process($container);
401+
402+
$definition = $container->getDefinition('with_optional_scalar_last');
403+
$this->assertEquals(
404+
array(
405+
new Reference('a'),
406+
new Reference('lille'),
407+
// third arg shouldn't *need* to be passed
408+
// but that's hard to "pull of" with autowiring, so
409+
// this assumes passing the default val is ok
410+
'some_val',
411+
),
412+
$definition->getArguments()
413+
);
414+
}
300415
}
301416

302417
class Foo
@@ -421,3 +536,28 @@ public function __construct(A $k)
421536
{
422537
}
423538
}
539+
class MultipleArguments
540+
{
541+
public function __construct(A $k, $foo, Dunglas $dunglas)
542+
{
543+
}
544+
}
545+
546+
class MultipleArgumentsOptionalScalar
547+
{
548+
public function __construct(A $a, $foo = 'default_val', Lille $lille = null)
549+
{
550+
}
551+
}
552+
class MultipleArgumentsOptionalScalarLast
553+
{
554+
public function __construct(A $a, Lille $lille, $foo = 'some_val')
555+
{
556+
}
557+
}
558+
class MultipleArgumentsOptionalScalarNotReallyOptional
559+
{
560+
public function __construct(A $a, $foo = 'default_val', Lille $lille)
561+
{
562+
}
563+
}

0 commit comments

Comments
 (0)