diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php index 15110261a225..f91cfd06677a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php @@ -33,9 +33,6 @@ public function process(ContainerBuilder $container) if ($definition->getArguments()) { throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines arguments but these are not supported and should be removed.', $interface)); } - if ($definition->getMethodCalls()) { - throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines method calls but these are not supported and should be removed.', $interface)); - } } foreach ($container->getDefinitions() as $id => $definition) { @@ -64,6 +61,7 @@ private function processDefinition(ContainerBuilder $container, $id, Definition $definition->setInstanceofConditionals(array()); $parent = $shared = null; $instanceofTags = array(); + $instanceofCalls = array(); foreach ($conditionals as $interface => $instanceofDefs) { if ($interface !== $class && (!$container->getReflectionClass($class, false))) { @@ -81,7 +79,13 @@ private function processDefinition(ContainerBuilder $container, $id, Definition $parent = 'instanceof.'.$interface.'.'.$key.'.'.$id; $container->setDefinition($parent, $instanceofDef); $instanceofTags[] = $instanceofDef->getTags(); + + foreach ($instanceofDef->getMethodCalls() as $methodCall) { + $instanceofCalls[] = $methodCall; + } + $instanceofDef->setTags(array()); + $instanceofDef->setMethodCalls(array()); if (isset($instanceofDef->getChanges()['shared'])) { $shared = $instanceofDef->isShared(); @@ -98,6 +102,7 @@ private function processDefinition(ContainerBuilder $container, $id, Definition $definition = serialize($definition); $definition = substr_replace($definition, '53', 2, 2); $definition = substr_replace($definition, 'Child', 44, 0); + /** @var ChildDefinition $definition */ $definition = unserialize($definition); $definition->setParent($parent); @@ -117,6 +122,8 @@ private function processDefinition(ContainerBuilder $container, $id, Definition } } + $definition->setMethodCalls(array_merge($instanceofCalls, $definition->getMethodCalls())); + // reset fields with "merge" behavior $abstract ->setBindings($bindings) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index e7fdb3593aa3..3dbec91eb808 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -207,6 +207,16 @@ public function getYamlCompileTests() 'child_service', 'child_service_expected', ); + + $container = new ContainerBuilder(); + $container->registerForAutoconfiguration(IntegrationTestStub::class) + ->addMethodCall('setSunshine', array('supernova')); + yield array( + 'instanceof_and_calls', + 'main_service', + 'main_service_expected', + $container, + ); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php index 21a2810578e9..45022a411798 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php @@ -200,16 +200,34 @@ public function testBadInterfaceForAutomaticInstanceofIsOk() } /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines method calls but these are not supported and should be removed. + * Test that autoconfigured calls are handled gracefully. */ - public function testProcessThrowsExceptionForAutoconfiguredCalls() + public function testProcessForAutoconfiguredCalls() { $container = new ContainerBuilder(); - $container->registerForAutoconfiguration(parent::class) - ->addMethodCall('setFoo'); + + $expected = array( + array('setFoo', array( + 'plain_value', + '%some_parameter%', + )), + array('callBar', array()), + array('isBaz', array()), + ); + + $container->registerForAutoconfiguration(parent::class)->addMethodCall('setFoo', $expected[0][1]); + $container->registerForAutoconfiguration(self::class)->addMethodCall('callBar'); + + $def = $container->register('foo', self::class)->setAutoconfigured(true)->addMethodCall('isBaz'); + $this->assertEquals( + array(array('isBaz', array())), + $def->getMethodCalls(), + 'Definition shouldn\'t have only one method call.' + ); (new ResolveInstanceofConditionalsPass())->process($container); + + $this->assertEquals($expected, $container->findDefinition('foo')->getMethodCalls()); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/integration/instanceof_and_calls/expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/integration/instanceof_and_calls/expected.yml new file mode 100644 index 000000000000..2d485a7a24ce --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/integration/instanceof_and_calls/expected.yml @@ -0,0 +1,10 @@ +services: + # main_service should look like this in the end + main_service_expected: + class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub + public: true + autoconfigure: true + calls: + - [setSunshine, [supernova]] + - [setSunshine, [warm]] + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/integration/instanceof_and_calls/main.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/integration/instanceof_and_calls/main.yml new file mode 100644 index 000000000000..aa0924e107e4 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/integration/instanceof_and_calls/main.yml @@ -0,0 +1,9 @@ +services: + _instanceof: + Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStubParent: + calls: + - [setSunshine, [warm]] + main_service: + class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub + autoconfigure: true + public: true