summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Pott2015-08-07 17:53:53 +0100
committerAlex Pott2015-08-07 17:53:53 +0100
commitc176ab795e5f6ff499b43fdfe981f1eff64a880d (patch)
tree43bf10c7cff2dabc2b375fc3b384d2d11c3a2cbb
parent20533256d2c3ca00a636a63068023ac4342e9f1a (diff)
Issue #2497697 by marvin_B8, Crell, cilefen, joshi.rohit100, dawehner: PSR-7 support for ControllerResolver
-rw-r--r--core/core.services.yml2
-rw-r--r--core/lib/Drupal/Core/Controller/ControllerResolver.php28
-rw-r--r--core/lib/Drupal/Core/Menu/menu.api.php16
-rw-r--r--core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php42
4 files changed, 78 insertions, 10 deletions
diff --git a/core/core.services.yml b/core/core.services.yml
index ea1a56b..8fe29d2 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -596,7 +596,7 @@ services:
public: false
controller_resolver:
class: Drupal\Core\Controller\ControllerResolver
- arguments: ['@class_resolver']
+ arguments: ['@psr7.http_message_factory', '@class_resolver']
class_resolver:
class: Drupal\Core\DependencyInjection\ClassResolver
calls:
diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php
index bf58aff..a8f2b3c 100644
--- a/core/lib/Drupal/Core/Controller/ControllerResolver.php
+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -7,11 +7,13 @@
namespace Drupal\Core\Controller;
+use Drupal\Core\DependencyInjection\ClassResolverInterface;
use Drupal\Core\Routing\RouteMatch;
-use Psr\Log\LoggerInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver;
-use Drupal\Core\DependencyInjection\ClassResolverInterface;
/**
* ControllerResolver to enhance controllers beyond Symfony's basic handling.
@@ -38,12 +40,23 @@ class ControllerResolver extends BaseControllerResolver implements ControllerRes
protected $classResolver;
/**
+ * The PSR-7 converter.
+ *
+ * @var \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface
+ */
+ protected $httpMessageFactory;
+
+ /**
* Constructs a new ControllerResolver.
*
+ * @param \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface $http_message_factory
+ * The PSR-7 converter.
+ *
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
* The class resolver.
*/
- public function __construct(ClassResolverInterface $class_resolver) {
+ public function __construct(HttpMessageFactoryInterface $http_message_factory, ClassResolverInterface $class_resolver) {
+ $this->httpMessageFactory = $http_message_factory;
$this->classResolver = $class_resolver;
}
@@ -94,10 +107,10 @@ class ControllerResolver extends BaseControllerResolver implements ControllerRes
* A PHP callable.
*
* @throws \LogicException
- * If the controller cannot be parsed
+ * If the controller cannot be parsed.
*
* @throws \InvalidArgumentException
- * If the controller class does not exist
+ * If the controller class does not exist.
*/
protected function createController($controller) {
// Controller in the service:method notation.
@@ -135,7 +148,10 @@ class ControllerResolver extends BaseControllerResolver implements ControllerRes
elseif ($param->getClass() && $param->getClass()->isInstance($request)) {
$arguments[] = $request;
}
- elseif ($param->getClass() && ($param->getClass()->name == 'Drupal\Core\Routing\RouteMatchInterface' || is_subclass_of($param->getClass()->name, 'Drupal\Core\Routing\RouteMatchInterface'))) {
+ elseif ($param->getClass() && $param->getClass()->name === ServerRequestInterface::class) {
+ $arguments[] = $this->httpMessageFactory->createRequest($request);
+ }
+ elseif ($param->getClass() && ($param->getClass()->name == RouteMatchInterface::class || is_subclass_of($param->getClass()->name, RouteMatchInterface::class))) {
$arguments[] = RouteMatch::createFromRequest($request);
}
elseif ($param->isDefaultValueAvailable()) {
diff --git a/core/lib/Drupal/Core/Menu/menu.api.php b/core/lib/Drupal/Core/Menu/menu.api.php
index 8550fc5..a2e9bb0 100644
--- a/core/lib/Drupal/Core/Menu/menu.api.php
+++ b/core/lib/Drupal/Core/Menu/menu.api.php
@@ -122,6 +122,22 @@
* For example, the placeholder '{myvar}' in a route will become the $myvar
* parameter to the method.
*
+ * Additionally, if a parameter is typed to one of the following special classes
+ * the system will pass those values as well.
+ *
+ * - \Symfony\Component\HttpFoundation\Request: The raw Symfony request object.
+ * It is generally only useful if the controller needs access to the query
+ * parameters of the request. By convention, this parameter is usually named
+ * $request.
+ * - \Psr\Http\Message\ServerRequestInterface: The raw request, represented
+ * using the PSR-7 ServerRequest format. This object is derived as necessary
+ * from the Symfony request, so if either will suffice the Symfony request
+ * will be slightly more performant. By convention this parameter is usually
+ * named $request.
+ * - \Drupal\Core\Routing\RouteMatchInterface: The "route match" data from
+ * this request. This object contains various standard data derived from
+ * the request and routing process. Consult the interface for details.
+ *
* Most controllers will need to display some information stored in the Drupal
* database, which will involve using one or more Drupal services (see the
* @link container Services and container topic @endlink). In order to properly
diff --git a/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
index d015a31..dc8c8d1 100644
--- a/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
+++ b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
@@ -19,6 +19,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
+use Psr\Http\Message\ServerRequestInterface;
/**
* @coversDefaultClass \Drupal\Core\Controller\ControllerResolver
@@ -41,6 +43,13 @@ class ControllerResolverTest extends UnitTestCase {
protected $container;
/**
+ * The PSR-7 converter.
+ *
+ * @var \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface
+ */
+ protected $httpMessageFactory;
+
+ /**
* {@inheritdoc}
*/
protected function setUp() {
@@ -49,7 +58,8 @@ class ControllerResolverTest extends UnitTestCase {
$this->container = new ContainerBuilder();
$class_resolver = new ClassResolver();
$class_resolver->setContainer($this->container);
- $this->controllerResolver = new ControllerResolver($class_resolver);
+ $this->httpMessageFactory = new DiactorosFactory();
+ $this->controllerResolver = new ControllerResolver($this->httpMessageFactory, $class_resolver);
}
/**
@@ -61,7 +71,7 @@ class ControllerResolverTest extends UnitTestCase {
* @see \Drupal\Core\Controller\ControllerResolver::doGetArguments()
*/
public function testGetArguments() {
- $controller = function(EntityInterface $entity, $user, RouteMatchInterface $route_match) {
+ $controller = function(EntityInterface $entity, $user, RouteMatchInterface $route_match, ServerRequestInterface $psr_7) {
};
$mock_entity = $this->getMockBuilder('Drupal\Core\Entity\Entity')
->disableOriginalConstructor()
@@ -71,12 +81,13 @@ class ControllerResolverTest extends UnitTestCase {
'entity' => $mock_entity,
'user' => $mock_account,
'_raw_variables' => new ParameterBag(array('entity' => 1, 'user' => 1)),
- ));
+ ), array(), array(), array('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');
}
/**
@@ -219,6 +230,20 @@ class ControllerResolverTest extends UnitTestCase {
$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 {
@@ -231,6 +256,17 @@ class MockController {
}
}
+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) {