Silverstripe-framework: Global middleware + custom controller + Controller::curr() triggers `No current controller available`

Created on 4 Jul 2019  路  5Comments  路  Source: silverstripe/silverstripe-framework

Defining global middleware (as per the middlewares documentation) which invokes a controller that relies on Controller::curr() triggers error No current controller available


Version

  • silverstripe/framework 4.4.1

Example code

YAML

SilverStripe\Core\Injector\Injector:
  SilverStripe\Control\Director:
    properties:
      Middlewares:
        CustomMiddleware: %$App\Middleware\CustomMiddleware

CustomMiddleware.php

<?php

namespace App\Middleware;

use App\Control\CustomController;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\Middleware\HTTPMiddleware;

class CustomMiddleware implements HTTPMiddleware
{

    /**
     * @param HTTPRequest $request
     * @param callable $delegate
     * @return HTTPResponse
     */
    public function process(HTTPRequest $request, callable $delegate): HTTPResponse
    {
        return Injector::inst()->create(CustomController::class)->handleRequest($request);
    }
}

CustomController.php

<?php

namespace App\Control;

use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;

class CustomController extends Controller
{

    /**
     * {@inheritdoc}
     *
     * @throws \SilverStripe\Control\HTTPResponse_Exception
     */
    public function handleRequest(HTTPRequest $request)
    {
        // Throw an error exception
        $this->httpError(404);
    }

}

Trace

No current controller available 
Controller.php:556
SilverStripe\Control\Controller::curr() 
ErrorPage.php:106
SilverStripe\ErrorPage\ErrorPage::response_for(404) 
ErrorPageControllerExtension.php:29
SilverStripe\ErrorPage\ErrorPageControllerExtension->onBeforeHTTPError(404, SilverStripe\Control\NullHTTPRequest, , , , , ) 
Extensible.php:468
SilverStripe\View\ViewableData->extend(onBeforeHTTPError, 404, SilverStripe\Control\NullHTTPRequest, ) 
RequestHandler.php:524
SilverStripe\Control\RequestHandler->httpError(404) 
CustomController.php:19
feedback-requirecore-team

Most helpful comment

Sorry @jakxnz . I'm going to close this as expected behaviour. Feel free to discuss further and we can re-open if required.

All 5 comments

This is a valid state of the application. A controller is decided during the main application flow (the inner-most layer of the middleware stack). The controller is then unselected at the end of that flow. Having a controller available with Controller::curr would be a bug imo.

As an example of what could be done here - you could adjust the routing information in a middleware based on something in the request - meaning a middleware can help delegate the request to specific controllers - for instance a middleware than handles Accept headers, if you choose to handle different response content types with different controllers.

I'm not sure if that would work for you, but it may become available after you delegate the request to the Director.

E.g.:

// Controller::curr() unavailable
$result = $delegate($request);
$controller = Controller::curr(); // should be available here
// ... do something ...
return $result;

P.S. currently it appears that we actually do routing before passing control to the middlewares, so we could potentially pass that info as well (or initialise Controller::curr). However, from this issue description it's not exactly clear what are the potential use cases for that .

If the controller state persists after delegating the request, I would consider that a bug.

The controller should be de-allocated after handling the request: https://github.com/silverstripe/silverstripe-framework/blob/f842ee2eec984002fce944157837251fea193b20/src/Control/Controller.php#L219

Sorry @jakxnz . I'm going to close this as expected behaviour. Feel free to discuss further and we can re-open if required.

Was this page helpful?
0 / 5 - 0 ratings