From f5709c590a4c57b337a7b154ba2c68d366f7ef25 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Wed, 29 Nov 2017 08:28:02 +0100 Subject: [PATCH] [HttpKernel] Add a better error messages when passing a private or non-tagged controller --- .../ContainerControllerResolver.php | 14 ++++- .../ContainerControllerResolverTest.php | 56 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php index fbcecad25e18a..f657aee21a0e7 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php @@ -13,6 +13,8 @@ use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\Debug\Exception\FatalThrowableError; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\HttpFoundation\Request; /** @@ -86,6 +88,16 @@ protected function instantiateController($class) return $this->container->get($class); } - return parent::instantiateController($class); + try { + return parent::instantiateController($class); + } catch (FatalThrowableError $e) { + } catch (\ArgumentCountError $e) { + } + + if ($this->container instanceof Container && in_array($class, $this->container->getRemovedIds(), true)) { + throw new \LogicException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $class), 0, $e); + } + + throw $e; } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php index b3deb03c9138a..ec696ac1d71a7 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php @@ -13,6 +13,9 @@ use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\Debug\ErrorHandler; +use Symfony\Component\Debug\Exception\ContextErrorException; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver; @@ -106,6 +109,48 @@ public function testNonInstantiableController() $this->assertSame(array(NonInstantiableController::class, 'action'), $controller); } + /** + * @expectedException \LogicException + * @expectedExceptionMessage Controller "Symfony\Component\HttpKernel\Tests\Controller\ImpossibleConstructController" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"? + */ + public function testNonConstructController() + { + $container = $this->getMockBuilder(Container::class)->getMock(); + $container->expects($this->at(0)) + ->method('has') + ->with(ImpossibleConstructController::class) + ->will($this->returnValue(true)) + ; + + $container->expects($this->at(1)) + ->method('has') + ->with(ImpossibleConstructController::class) + ->will($this->returnValue(false)) + ; + + $container->expects($this->atLeastOnce()) + ->method('getRemovedIds') + ->with() + ->will($this->returnValue(array(ImpossibleConstructController::class))) + ; + + $resolver = $this->createControllerResolver(null, $container); + $request = Request::create('/'); + $request->attributes->set('_controller', array(ImpossibleConstructController::class, 'action')); + + if (\PHP_VERSION_ID < 70000) { + ErrorHandler::register(); + try { + $resolver->getController($request); + } finally { + restore_error_handler(); + restore_exception_handler(); + } + } else { + $resolver->getController($request); + } + } + public function testNonInstantiableControllerWithCorrespondingService() { $service = new \stdClass(); @@ -196,3 +241,14 @@ public static function action() { } } + +class ImpossibleConstructController +{ + public function __construct($toto, $controller) + { + } + + public function action() + { + } +}