container = new ContainerBuilder(); $class_resolver = new ClassResolver(); $class_resolver->setContainer($this->container); $this->httpMessageFactory = new DiactorosFactory(); $this->controllerResolver = new ControllerResolver($this->httpMessageFactory, $class_resolver); } /** * Tests getArguments(). * * Ensure that doGetArguments uses converted arguments if available. * * @see \Drupal\Core\Controller\ControllerResolver::getArguments() * @see \Drupal\Core\Controller\ControllerResolver::doGetArguments() */ public function testGetArguments() { $controller = function(EntityInterface $entity, $user, RouteMatchInterface $route_match, ServerRequestInterface $psr_7) { }; $mock_entity = $this->getMockBuilder('Drupal\Core\Entity\Entity') ->disableOriginalConstructor() ->getMock(); $mock_account = $this->getMock('Drupal\Core\Session\AccountInterface'); $request = new Request([], [], [ 'entity' => $mock_entity, 'user' => $mock_account, '_raw_variables' => new ParameterBag(['entity' => 1, 'user' => 1]), ], [], [], ['HTTP_HOST' => 'drupal.org']); $arguments = $this->controllerResolver->getArguments($request, $controller); $this->assertEquals($mock_entity, $arguments[0]); $this->assertEquals($mock_account, $arguments[1]); $this->assertEquals(RouteMatch::createFromRequest($request), $arguments[2], 'Ensure that the route match object is passed along as well'); $this->assertInstanceOf(ServerRequestInterface::class, $arguments[3], 'Ensure that the PSR-7 object is passed along as well'); } /** * Tests createController(). * * @dataProvider providerTestCreateController */ public function testCreateController($controller, $class, $output) { $this->container->set('some_service', new MockController()); $result = $this->controllerResolver->getControllerFromDefinition($controller); $this->assertCallableController($result, $class, $output); } /** * Provides test data for testCreateController(). */ public function providerTestCreateController() { return [ // Tests class::method. ['Drupal\Tests\Core\Controller\MockController::getResult', 'Drupal\Tests\Core\Controller\MockController', 'This is a regular controller.'], // Tests service:method. ['some_service:getResult', 'Drupal\Tests\Core\Controller\MockController', 'This is a regular controller.'], // Tests a class with injection. ['Drupal\Tests\Core\Controller\MockContainerInjection::getResult', 'Drupal\Tests\Core\Controller\MockContainerInjection', 'This used injection.'], // Tests a ContainerAware class. ['Drupal\Tests\Core\Controller\MockContainerAware::getResult', 'Drupal\Tests\Core\Controller\MockContainerAware', 'This is container aware.'], ]; } /** * Tests createController() with a non-existent class. */ public function testCreateControllerNonExistentClass() { $this->setExpectedException(\InvalidArgumentException::class); $this->controllerResolver->getControllerFromDefinition('Class::method'); } /** * Tests createController() with an invalid name. */ public function testCreateControllerInvalidName() { $this->setExpectedException(\LogicException::class); $this->controllerResolver->getControllerFromDefinition('ClassWithoutMethod'); } /** * Tests getController(). * * @dataProvider providerTestGetController */ public function testGetController($attributes, $class, $output = NULL) { $request = new Request([], [], $attributes); $result = $this->controllerResolver->getController($request); if ($class) { $this->assertCallableController($result, $class, $output); } else { $this->assertSame(FALSE, $result); } } /** * Provides test data for testGetController(). */ public function providerTestGetController() { return [ // Tests passing a controller via the request. [['_controller' => 'Drupal\Tests\Core\Controller\MockContainerAware::getResult'], 'Drupal\Tests\Core\Controller\MockContainerAware', 'This is container aware.'], // Tests a request with no controller specified. [[], FALSE] ]; } /** * Tests getControllerFromDefinition(). * * @dataProvider providerTestGetControllerFromDefinition */ public function testGetControllerFromDefinition($definition, $output) { $controller = $this->controllerResolver->getControllerFromDefinition($definition); $this->assertCallableController($controller, NULL, $output); } /** * Provides test data for testGetControllerFromDefinition(). */ public function providerTestGetControllerFromDefinition() { return [ // Tests a method on an object. [[new MockController(), 'getResult'], 'This is a regular controller.'], // Tests a function. ['phpversion', phpversion()], // Tests an object using __invoke(). [new MockInvokeController(), 'This used __invoke().'], // Tests a class using __invoke(). ['Drupal\Tests\Core\Controller\MockInvokeController', 'This used __invoke().'], ]; } /** * Tests getControllerFromDefinition() without a callable. */ public function testGetControllerFromDefinitionNotCallable() { $this->setExpectedException(\InvalidArgumentException::class); $this->controllerResolver->getControllerFromDefinition('Drupal\Tests\Core\Controller\MockController::bananas'); } /** * Asserts that the controller is callable and produces the correct output. * * @param callable $controller * A callable controller. * @param string|null $class * Either the name of the class the controller represents, or NULL if it is * not an object. * @param mixed $output * The output expected for this controller. */ protected function assertCallableController($controller, $class, $output) { if ($class) { $this->assertTrue(is_object($controller[0])); $this->assertInstanceOf($class, $controller[0]); } $this->assertTrue(is_callable($controller)); $this->assertSame($output, call_user_func($controller)); } /** * Tests getArguments with a route match and a request. * * @covers ::getArguments * @covers ::doGetArguments */ public function testGetArgumentsWithRouteMatchAndRequest() { $request = Request::create('/test'); $mock_controller = new MockController(); $arguments = $this->controllerResolver->getArguments($request, [$mock_controller, 'getControllerWithRequestAndRouteMatch']); $this->assertEquals([RouteMatch::createFromRequest($request), $request], $arguments); } /** * Tests getArguments with a route match and a PSR-7 request. * * @covers ::getArguments * @covers ::doGetArguments */ public function testGetArgumentsWithRouteMatchAndPsr7Request() { $request = Request::create('/test'); $mock_controller = new MockControllerPsr7(); $arguments = $this->controllerResolver->getArguments($request, [$mock_controller, 'getControllerWithRequestAndRouteMatch']); $this->assertEquals(RouteMatch::createFromRequest($request), $arguments[0], 'Ensure that the route match object is passed along as well'); $this->assertInstanceOf('Psr\Http\Message\ServerRequestInterface', $arguments[1], 'Ensure that the PSR-7 object is passed along as well'); } } class MockController { public function getResult() { return 'This is a regular controller.'; } public function getControllerWithRequestAndRouteMatch(RouteMatchInterface $route_match, Request $request) { return 'this is another example controller'; } } class MockControllerPsr7 { public function getResult() { return ['#markup' => 'This is a regular controller']; } public function getControllerWithRequestAndRouteMatch(RouteMatchInterface $route_match, ServerRequestInterface $request) { return ['#markup' => 'this is another example controller']; } } class MockContainerInjection implements ContainerInjectionInterface { protected $result; public function __construct($result) { $this->result = $result; } public static function create(ContainerInterface $container) { return new static('This used injection.'); } public function getResult() { return $this->result; } } class MockContainerAware implements ContainerAwareInterface { use ContainerAwareTrait; public function getResult() { return 'This is container aware.'; } } class MockInvokeController { public function __invoke() { return 'This used __invoke().'; } }