Problem/Motivation

As of Symfony 2.7, it's possible to have Symfony auto-convert its Request object to a PSR-7 request object before passing it to the controller. The controller can request a RequestInterface object via type hinting and get that instead.

That's done in SensioFrameworkExtraBundle, which we're not using as we have our own extended ControllerResolver. Let's add the same functionality for symmetry with #2497693: Add PSR-7 to Symfony Response View listener. (Which does not block this issue.)

Proposed resolution

Enhance our ControllerResolver to allow passing a PSR-7 RequestInterface object to a controller, just like it can pass a Symfony Request object.

Remaining tasks

Do it.

User interface changes

None.

API changes

None.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task, it integrates Drupal a little bit more with PSR-7
Issue priority Normal, because not necessarily everyone profits
Disruption No disruption

Comments

marvin_b8’s picture

StatusFileSize
new2.87 KB

I'm not sure if this the best solution.

Crell’s picture

Hm, no, we would be modifying the ControllerResolver's getArguments() logic. I'd have to double check which classes that is right now as they've been refactored several times. :-) A ParamConverter is not the right place for this.

cilefen’s picture

@Crell If I understand the situation we would have to not type hint the request in function signatures in ControllerResolver but then check the request type in the function logic.

marvin_b8’s picture

Status: Active » Needs review
StatusFileSize
new3.29 KB

More like this ?

Status: Needs review » Needs work

The last submitted patch, 4: psr-7-controllerResolver-2497697-4.patch, failed testing.

Crell’s picture

#4 is more in the right direction, yes.

dawehner’s picture

Let's expand our unit test here :)

Crell’s picture

The blocking issue is in, so this can move forward.

cilefen’s picture

Status: Needs work » Needs review
StatusFileSize
new4.21 KB
cilefen’s picture

+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -135,6 +147,9 @@ protected function doGetArguments(Request $request, $controller, array $paramete
+        $arguments[] = $this->httpFoundationFactory->createRequest($request);

The problem here is that a Symfony Request is the wrong parameter type. We need a request of type Psr\Http\Message\ServerRequestInterface.

dawehner’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -135,6 +147,9 @@ protected function doGetArguments(Request $request, $controller, array $paramete
       }
+      elseif ($param->getClass() && $param->getClass()->name === 'Psr\Http\Message\ServerRequestInterface') {
+        $arguments[] = $this->httpFoundationFactory->createRequest($request);
+      }

I don't get it at all ... the point is to be able to pass along the server request to the controller, we don't need to convert anything.

marvin_b8’s picture

Status: Needs work » Needs review
StatusFileSize
new12.75 KB

Now with the right injecten and some unit tests.

dawehner’s picture

Status: Needs review » Needs work

OH I take back #11, that was BS.

  1. +++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
    @@ -60,7 +70,7 @@ public function getControllerFromDefinition($controller, $path = '') {
           elseif (method_exists($controller, '__invoke')) {
    -        return new $controller;
    +        return new $controller();
           }
    

    That change is wrong. The result of a controller should not be created in the controller resolver.

  2. +++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
    @@ -115,7 +125,7 @@ protected function createController($controller) {
     
    -    return array($controller, $method);
    +    return [$controller, $method];
       }
    
    @@ -124,7 +134,7 @@ protected function createController($controller) {
    -    $arguments = array();
    +    $arguments = [];
    

    I'd suggest you to not try to fix all those small things please. Please try to keep in mind that you should optimize for reviewability.

marvin_b8’s picture

StatusFileSize
new7.1 KB

So =)

marvin_b8’s picture

Status: Needs work » Needs review
dawehner’s picture

Issue summary: View changes

Thank you!

dawehner’s picture

Just a random nitpick :P

+++ b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
@@ -41,6 +43,13 @@ class ControllerResolverTest extends UnitTestCase {
+   * @var \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;

We don't use a semicolon at the end here

Crell’s picture

Status: Needs review » Needs work

I think all my comments on the latest patch are nits, so next patch is probably RTBC. Thanks, marvin!

  1. +++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
    @@ -135,6 +144,9 @@ protected function doGetArguments(Request $request, $controller, array $paramete
    +      elseif ($param->getClass() && $param->getClass()->name === 'Psr\Http\Message\ServerRequestInterface') {
    

    Because we have PHP 5.5 now, we can use ServerRequestInterface::class, with a use statement in the file header. That's easier to read and easier to write. :-)

  2. +++ b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
    @@ -71,12 +81,13 @@ public function testGetArguments() {
    +    $this->assertInstanceOf('Psr\Http\Message\ServerRequestInterface', $arguments[3], 'Ensure that the PSR-7 object is passed along as well');
    

    As above, we can use ::class now.

  3. +++ b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
    @@ -231,6 +256,16 @@ public function getControllerWithRequestAndRouteMatch(RouteMatchInterface $route
    +  public function getResult() {
    +    return 'This is a regular controller.';
    +  }
    +
    +  public function getControllerWithRequestAndRouteMatch(RouteMatchInterface $route_match, ServerRequestInterface $request) {
    +    return 'this is another example controller';
    +  }
    

    We don't technically support string returns from controllers at this point, so our test controllers shouldn't return them. I'd suggest just:

    return ['#markup' => 'This is a regular controller'];
    
  4. +++ b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
    @@ -231,6 +256,16 @@ public function getControllerWithRequestAndRouteMatch(RouteMatchInterface $route
    +}
     class MockContainerInjection implements ContainerInjectionInterface {
    

    Needs a linebreak between these two lines.

cilefen’s picture

Status: Needs work » Needs review
StatusFileSize
new3.81 KB
new7.15 KB
Crell’s picture

Status: Needs review » Reviewed & tested by the community

Go team!

dawehner’s picture

Yeah!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -38,12 +40,20 @@ class ControllerResolver extends BaseControllerResolver implements ControllerRes
    * @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) {

Need to document the new parameter and I think the new capability should be listed on the ControllerResolver as this is another added behaviour.

joshi.rohit100’s picture

Status: Needs work » Needs review
StatusFileSize
new7.27 KB
new567 bytes
Crell’s picture

Alex: Can you clarify what you mean by "new capability should be listed on the ControllerResolver"? You mean in Drupal\ControllerResolver's docblock?

alexpott’s picture

@Crell I think we should document PSR-7 support in menu.api.php

Crell’s picture

StatusFileSize
new9.32 KB
new3.38 KB

Turns out menu.api.php didn't document ANY of the non-placeholder parameters that are supported. So I added a block that notes all three.

I also switched the RouteMatchInterface line to use PHP 5.5 syntax for consistency (it was bugging me), and cleaned up the use statements in the file, because I was there.

Crell’s picture

StatusFileSize
new9.2 KB
new734 bytes

Crell-- for stupid editing mistakes.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

I really like the documentation. Its helpful. I was wondering whether we should rearrange things a bit.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Thanks for improving the documentation. Committed c176ab7 and pushed to 8.0.x. Thanks!

Thanks for adding the beta evaluation to the issue summary.

  • alexpott committed c176ab7 on 8.0.x
    Issue #2497697 by marvin_B8, Crell, cilefen, joshi.rohit100, dawehner:...
Crell’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.