* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Tests\Controller; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver; class ContainerControllerResolverTest extends ControllerResolverTest { use ExpectDeprecationTrait; /** * @group legacy */ public function testGetControllerServiceWithSingleColon() { $this->expectDeprecation('Since symfony/http-kernel 5.1: Referencing controllers with a single colon is deprecated. Use "foo::action" instead.'); $service = new ControllerTestService('foo'); $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') ->with('foo') ->willReturn(true); $container->expects($this->once()) ->method('get') ->with('foo') ->willReturn($service) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); $request->attributes->set('_controller', 'foo:action'); $controller = $resolver->getController($request); $this->assertSame($service, $controller[0]); $this->assertSame('action', $controller[1]); } public function testGetControllerService() { $service = new ControllerTestService('foo'); $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') ->with('foo') ->willReturn(true); $container->expects($this->once()) ->method('get') ->with('foo') ->willReturn($service) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); $request->attributes->set('_controller', 'foo::action'); $controller = $resolver->getController($request); $this->assertSame($service, $controller[0]); $this->assertSame('action', $controller[1]); } public function testGetControllerInvokableService() { $service = new InvokableControllerService('bar'); $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') ->with('foo') ->willReturn(true) ; $container->expects($this->once()) ->method('get') ->with('foo') ->willReturn($service) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); $request->attributes->set('_controller', 'foo'); $controller = $resolver->getController($request); $this->assertSame($service, $controller); } public function testGetControllerInvokableServiceWithClassNameAsName() { $service = new InvokableControllerService('bar'); $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') ->with(InvokableControllerService::class) ->willReturn(true) ; $container->expects($this->once()) ->method('get') ->with(InvokableControllerService::class) ->willReturn($service) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); $request->attributes->set('_controller', InvokableControllerService::class); $controller = $resolver->getController($request); $this->assertSame($service, $controller); } /** * @dataProvider getControllers */ public function testInstantiateControllerWhenControllerStartsWithABackslash($controller) { $service = new ControllerTestService('foo'); $class = ControllerTestService::class; $container = $this->createMockContainer(); $container->expects($this->once())->method('has')->with($class)->willReturn(true); $container->expects($this->once())->method('get')->with($class)->willReturn($service); $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); $request->attributes->set('_controller', $controller); $controller = $resolver->getController($request); $this->assertInstanceOf(ControllerTestService::class, $controller[0]); $this->assertSame('action', $controller[1]); } public static function getControllers() { return [ ['\\'.ControllerTestService::class.'::action'], ]; } public function testExceptionWhenUsingRemovedControllerServiceWithClassNameAsName() { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?'); $container = $this->createMock(Container::class); $container->expects($this->once()) ->method('has') ->with(ControllerTestService::class) ->willReturn(false) ; $container->expects($this->atLeastOnce()) ->method('getRemovedIds') ->with() ->willReturn([ControllerTestService::class => true]) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); $request->attributes->set('_controller', [ControllerTestService::class, 'action']); $resolver->getController($request); } public function testExceptionWhenUsingRemovedControllerService() { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Controller "app.my_controller" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?'); $container = $this->createMock(Container::class); $container->expects($this->once()) ->method('has') ->with('app.my_controller') ->willReturn(false) ; $container->expects($this->atLeastOnce()) ->method('getRemovedIds') ->with() ->willReturn(['app.my_controller' => true]) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); $request->attributes->set('_controller', 'app.my_controller'); $resolver->getController($request); } public static function getUndefinedControllers(): array { $tests = parent::getUndefinedControllers(); $tests[0] = ['foo', \InvalidArgumentException::class, 'Controller "foo" does neither exist as service nor as class']; $tests[1] = ['oof::bar', \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class']; $tests[2] = [['oof', 'bar'], \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class']; $tests[] = [ [ControllerTestService::class, 'action'], \InvalidArgumentException::class, 'Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', ]; $tests[] = [ ControllerTestService::class.'::action', \InvalidArgumentException::class, 'Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', ]; $tests[] = [ InvokableControllerService::class, \InvalidArgumentException::class, 'Controller "Symfony\Component\HttpKernel\Tests\Controller\InvokableControllerService" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', ]; return $tests; } protected function createControllerResolver(LoggerInterface $logger = null, ContainerInterface $container = null) { if (!$container) { $container = $this->createMockContainer(); } return new ContainerControllerResolver($container, $logger); } protected function createMockContainer() { return $this->createMock(ContainerInterface::class); } } class InvokableControllerService { public function __construct($bar) // mandatory argument to prevent automatic instantiation { } public function __invoke() { } } class ControllerTestService { public function __construct($foo) { } public function action() { } }