ContainerControllerResolverTest.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpKernel\Tests\Controller;
  11. use Psr\Container\ContainerInterface;
  12. use Psr\Log\LoggerInterface;
  13. use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
  14. use Symfony\Component\DependencyInjection\Container;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
  17. class ContainerControllerResolverTest extends ControllerResolverTest
  18. {
  19. use ExpectDeprecationTrait;
  20. /**
  21. * @group legacy
  22. */
  23. public function testGetControllerServiceWithSingleColon()
  24. {
  25. $this->expectDeprecation('Since symfony/http-kernel 5.1: Referencing controllers with a single colon is deprecated. Use "foo::action" instead.');
  26. $service = new ControllerTestService('foo');
  27. $container = $this->createMockContainer();
  28. $container->expects($this->once())
  29. ->method('has')
  30. ->with('foo')
  31. ->willReturn(true);
  32. $container->expects($this->once())
  33. ->method('get')
  34. ->with('foo')
  35. ->willReturn($service)
  36. ;
  37. $resolver = $this->createControllerResolver(null, $container);
  38. $request = Request::create('/');
  39. $request->attributes->set('_controller', 'foo:action');
  40. $controller = $resolver->getController($request);
  41. $this->assertSame($service, $controller[0]);
  42. $this->assertSame('action', $controller[1]);
  43. }
  44. public function testGetControllerService()
  45. {
  46. $service = new ControllerTestService('foo');
  47. $container = $this->createMockContainer();
  48. $container->expects($this->once())
  49. ->method('has')
  50. ->with('foo')
  51. ->willReturn(true);
  52. $container->expects($this->once())
  53. ->method('get')
  54. ->with('foo')
  55. ->willReturn($service)
  56. ;
  57. $resolver = $this->createControllerResolver(null, $container);
  58. $request = Request::create('/');
  59. $request->attributes->set('_controller', 'foo::action');
  60. $controller = $resolver->getController($request);
  61. $this->assertSame($service, $controller[0]);
  62. $this->assertSame('action', $controller[1]);
  63. }
  64. public function testGetControllerInvokableService()
  65. {
  66. $service = new InvokableControllerService('bar');
  67. $container = $this->createMockContainer();
  68. $container->expects($this->once())
  69. ->method('has')
  70. ->with('foo')
  71. ->willReturn(true)
  72. ;
  73. $container->expects($this->once())
  74. ->method('get')
  75. ->with('foo')
  76. ->willReturn($service)
  77. ;
  78. $resolver = $this->createControllerResolver(null, $container);
  79. $request = Request::create('/');
  80. $request->attributes->set('_controller', 'foo');
  81. $controller = $resolver->getController($request);
  82. $this->assertSame($service, $controller);
  83. }
  84. public function testGetControllerInvokableServiceWithClassNameAsName()
  85. {
  86. $service = new InvokableControllerService('bar');
  87. $container = $this->createMockContainer();
  88. $container->expects($this->once())
  89. ->method('has')
  90. ->with(InvokableControllerService::class)
  91. ->willReturn(true)
  92. ;
  93. $container->expects($this->once())
  94. ->method('get')
  95. ->with(InvokableControllerService::class)
  96. ->willReturn($service)
  97. ;
  98. $resolver = $this->createControllerResolver(null, $container);
  99. $request = Request::create('/');
  100. $request->attributes->set('_controller', InvokableControllerService::class);
  101. $controller = $resolver->getController($request);
  102. $this->assertSame($service, $controller);
  103. }
  104. /**
  105. * @dataProvider getControllers
  106. */
  107. public function testInstantiateControllerWhenControllerStartsWithABackslash($controller)
  108. {
  109. $service = new ControllerTestService('foo');
  110. $class = ControllerTestService::class;
  111. $container = $this->createMockContainer();
  112. $container->expects($this->once())->method('has')->with($class)->willReturn(true);
  113. $container->expects($this->once())->method('get')->with($class)->willReturn($service);
  114. $resolver = $this->createControllerResolver(null, $container);
  115. $request = Request::create('/');
  116. $request->attributes->set('_controller', $controller);
  117. $controller = $resolver->getController($request);
  118. $this->assertInstanceOf(ControllerTestService::class, $controller[0]);
  119. $this->assertSame('action', $controller[1]);
  120. }
  121. public static function getControllers()
  122. {
  123. return [
  124. ['\\'.ControllerTestService::class.'::action'],
  125. ];
  126. }
  127. public function testExceptionWhenUsingRemovedControllerServiceWithClassNameAsName()
  128. {
  129. $this->expectException(\InvalidArgumentException::class);
  130. $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"?');
  131. $container = $this->createMock(Container::class);
  132. $container->expects($this->once())
  133. ->method('has')
  134. ->with(ControllerTestService::class)
  135. ->willReturn(false)
  136. ;
  137. $container->expects($this->atLeastOnce())
  138. ->method('getRemovedIds')
  139. ->with()
  140. ->willReturn([ControllerTestService::class => true])
  141. ;
  142. $resolver = $this->createControllerResolver(null, $container);
  143. $request = Request::create('/');
  144. $request->attributes->set('_controller', [ControllerTestService::class, 'action']);
  145. $resolver->getController($request);
  146. }
  147. public function testExceptionWhenUsingRemovedControllerService()
  148. {
  149. $this->expectException(\InvalidArgumentException::class);
  150. $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"?');
  151. $container = $this->createMock(Container::class);
  152. $container->expects($this->once())
  153. ->method('has')
  154. ->with('app.my_controller')
  155. ->willReturn(false)
  156. ;
  157. $container->expects($this->atLeastOnce())
  158. ->method('getRemovedIds')
  159. ->with()
  160. ->willReturn(['app.my_controller' => true])
  161. ;
  162. $resolver = $this->createControllerResolver(null, $container);
  163. $request = Request::create('/');
  164. $request->attributes->set('_controller', 'app.my_controller');
  165. $resolver->getController($request);
  166. }
  167. public static function getUndefinedControllers(): array
  168. {
  169. $tests = parent::getUndefinedControllers();
  170. $tests[0] = ['foo', \InvalidArgumentException::class, 'Controller "foo" does neither exist as service nor as class'];
  171. $tests[1] = ['oof::bar', \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class'];
  172. $tests[2] = [['oof', 'bar'], \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class'];
  173. $tests[] = [
  174. [ControllerTestService::class, 'action'],
  175. \InvalidArgumentException::class,
  176. '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?',
  177. ];
  178. $tests[] = [
  179. ControllerTestService::class.'::action',
  180. \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?',
  181. ];
  182. $tests[] = [
  183. InvokableControllerService::class,
  184. \InvalidArgumentException::class,
  185. '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?',
  186. ];
  187. return $tests;
  188. }
  189. protected function createControllerResolver(LoggerInterface $logger = null, ContainerInterface $container = null)
  190. {
  191. if (!$container) {
  192. $container = $this->createMockContainer();
  193. }
  194. return new ContainerControllerResolver($container, $logger);
  195. }
  196. protected function createMockContainer()
  197. {
  198. return $this->createMock(ContainerInterface::class);
  199. }
  200. }
  201. class InvokableControllerService
  202. {
  203. public function __construct($bar) // mandatory argument to prevent automatic instantiation
  204. {
  205. }
  206. public function __invoke()
  207. {
  208. }
  209. }
  210. class ControllerTestService
  211. {
  212. public function __construct($foo)
  213. {
  214. }
  215. public function action()
  216. {
  217. }
  218. }