diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index 2e861f32cf970..0a492eae2e9a0 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -25,7 +25,9 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\HttpKernel\KernelInterface; /** * Creates the service-locators required by ServiceValueResolver. @@ -70,13 +72,21 @@ public function process(ContainerBuilder $container) if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } - $isContainerAware = $r->implementsInterface(ContainerAwareInterface::class) || is_subclass_of($class, AbstractController::class); + + $excludedMethod = []; + if ($r->implementsInterface(ContainerAwareInterface::class) || is_subclass_of($class, AbstractController::class)) { + $excludedMethod['setContainer'] = true; + } + if ($r->implementsInterface(KernelInterface::class)) { + $excludedMethod['registerContainerConfiguration'] = true; + $excludedMethod['loadRoutes'] = true; + } // get regular public methods $methods = []; $arguments = []; foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $r) { - if ('setContainer' === $r->name && $isContainerAware) { + if (!$r->getNumberOfParameters() || isset($excludedMethod[$r->name])) { continue; } if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) { @@ -150,11 +160,11 @@ public function process(ContainerBuilder $container) } elseif (is_subclass_of($type, \UnitEnum::class)) { // do not attempt to register enum typed arguments if not already present in bindings continue; - } elseif (!$p->allowsNull()) { + } elseif (!$p->allowsNull() && interface_exists($type, false)) { $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } - if (Request::class === $type || SessionInterface::class === $type) { + if (Request::class === $type || Response::class === $type || SessionInterface::class === $type) { continue; } diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php index 69b9511c05230..f65dfe5158c12 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php @@ -108,8 +108,6 @@ public function testControllerNameIsAnArray() public function testErrorIsTruncated() { - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('Cannot autowire argument $dummy of "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyController::index()": it references class "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyService" but no such service exists.'); $container = new ContainerBuilder(); $container->addCompilerPass(new RegisterControllerArgumentLocatorsPass()); @@ -119,7 +117,10 @@ public function testErrorIsTruncated() $container->compile(); $request = $this->requestWithAttributes(['_controller' => [DummyController::class, 'index']]); - $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null); + $argument = new ArgumentMetadata('dummy', DummyServiceInterface::class, false, false, null); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Cannot autowire argument $dummy of "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyController::index()": it references interface "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyServiceInterface" but no such service exists.'); $container->get('argument_resolver.service')->resolve($request, $argument)->current(); } @@ -145,13 +146,17 @@ private function assertYieldEquals(array $expected, \Generator $generator) } } +interface DummyServiceInterface +{ +} + class DummyService { } class DummyController { - public function index(DummyService $dummy) + public function index(DummyServiceInterface $dummy) { } } diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index 85e057439cfe6..495781bd56a44 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -141,7 +141,7 @@ public function testAllActions() $this->assertSame(ServiceLocator::class, $locator->getClass()); $this->assertFalse($locator->isPublic()); - $expected = ['bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'bar'))]; + $expected = ['bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE, 'bar'))]; $this->assertEquals($expected, $locator->getArgument(0)); } @@ -437,8 +437,8 @@ public function testBindWithTarget() $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')), - 'service2' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'service2')), + 'service1' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE, 'imageStorage')), + 'service2' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE, 'service2')), ]; $this->assertEquals($expected, $locator->getArgument(0)); }