mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
API: Deprecate RequestFilter.
NEW: Allow application of HTTPMiddleware to Director. Director can now use the same HTTPMiddleware objects as the app object. They can be applied either globally or pre-rule.
This commit is contained in:
parent
26b9bf11ed
commit
b30f410ea0
@ -2,6 +2,8 @@
|
||||
Name: rootroutes
|
||||
---
|
||||
SilverStripe\Control\Director:
|
||||
middlewares:
|
||||
RequestProcessor: 'SilverStripe\Control\RequestProcessor'
|
||||
rules:
|
||||
'': SilverStripe\Control\Controller
|
||||
---
|
||||
|
@ -131,24 +131,12 @@ class Director implements TemplateGlobalProvider
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-request
|
||||
$output = RequestProcessor::singleton()->preRequest($request);
|
||||
if ($output === false) {
|
||||
return new HTTPResponse(_t(__CLASS__.'.INVALID_REQUEST', 'Invalid request'), 400);
|
||||
}
|
||||
|
||||
// Generate output
|
||||
$result = static::handleRequest($request);
|
||||
|
||||
// Save session data. Note that save() will start/resume the session if required.
|
||||
$request->getSession()->save();
|
||||
|
||||
// Post-request handling
|
||||
$postRequest = RequestProcessor::singleton()->postRequest($request, $result);
|
||||
if ($postRequest === false) {
|
||||
return new HTTPResponse(_t(__CLASS__ . '.REQUEST_ABORTED', 'Request aborted'), 500);
|
||||
}
|
||||
|
||||
// Return
|
||||
return $result;
|
||||
}
|
||||
@ -351,6 +339,14 @@ class Director implements TemplateGlobalProvider
|
||||
{
|
||||
$rules = Director::config()->uninherited('rules');
|
||||
|
||||
// Get global middlewares
|
||||
$middlewares = Director::config()->uninherited('middlewares') ?: [];
|
||||
|
||||
// Default handler - mo URL rules matched, so return a 404 error.
|
||||
$handler = function () {
|
||||
return new HTTPResponse('No URL rule was matched', 404);
|
||||
};
|
||||
|
||||
foreach ($rules as $pattern => $controllerOptions) {
|
||||
// Normalise route rule
|
||||
if (is_string($controllerOptions)) {
|
||||
@ -361,6 +357,18 @@ class Director implements TemplateGlobalProvider
|
||||
}
|
||||
}
|
||||
|
||||
// Add controller-specific middlewares
|
||||
if (isset($controllerOptions['Middlewares'])) {
|
||||
// Force to array
|
||||
if (!is_array($controllerOptions['Middlewares'])) {
|
||||
$controllerOptions['Middlewares'] = [$controllerOptions['Middlewares']];
|
||||
}
|
||||
$middlewares = array_merge($middlewares, $controllerOptions['Middlewares']);
|
||||
}
|
||||
|
||||
// Remove null middlewares (may be included due to limitatons of config yml)
|
||||
$middlewares = array_filter($middlewares);
|
||||
|
||||
// Match pattern
|
||||
$arguments = $request->match($pattern, true);
|
||||
if ($arguments !== false) {
|
||||
@ -373,28 +381,71 @@ class Director implements TemplateGlobalProvider
|
||||
$request->shift($controllerOptions['_PopTokeniser']);
|
||||
}
|
||||
|
||||
// Handle redirection
|
||||
// Handler for redirection
|
||||
if (isset($arguments['Redirect'])) {
|
||||
// Redirection
|
||||
$response = new HTTPResponse();
|
||||
$response->redirect(static::absoluteURL($arguments['Redirect']));
|
||||
return $response;
|
||||
$handler = function () use ($arguments) {
|
||||
// Redirection
|
||||
$response = new HTTPResponse();
|
||||
$response->redirect(static::absoluteURL($arguments['Redirect']));
|
||||
return $response;
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the controller name
|
||||
$controller = $arguments['Controller'];
|
||||
$controllerObj = Injector::inst()->create($controller);
|
||||
|
||||
try {
|
||||
return $controllerObj->handleRequest($request);
|
||||
} catch (HTTPResponse_Exception $responseException) {
|
||||
return $responseException->getResponse();
|
||||
}
|
||||
// Handler for calling a controller
|
||||
$handler = function ($request) use ($controllerObj) {
|
||||
try {
|
||||
return $controllerObj->handleRequest($request);
|
||||
} catch (HTTPResponse_Exception $responseException) {
|
||||
return $responseException->getResponse();
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No URL rules matched, so return a 404 error.
|
||||
return new HTTPResponse('No URL rule was matched', 404);
|
||||
// Call the handler with the given middlewares
|
||||
return self::callWithMiddlewares(
|
||||
$request,
|
||||
$middlewares,
|
||||
$handler
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the given request handler with the given middlewares
|
||||
* Middlewares are specified as Injector service names
|
||||
*
|
||||
* @param $request The request to pass to the handler
|
||||
* @param $middlewareNames The services names of the middlewares to apply
|
||||
* @param $handler The request handler
|
||||
*/
|
||||
protected static function callWithMiddlewares(HTTPRequest $request, array $middlewareNames, callable $handler)
|
||||
{
|
||||
$next = $handler;
|
||||
|
||||
if ($middlewareNames) {
|
||||
$middlewares = array_map(
|
||||
function ($name) {
|
||||
return Injector::inst()->get($name);
|
||||
},
|
||||
$middlewareNames
|
||||
);
|
||||
|
||||
// Reverse middlewares
|
||||
/** @var HTTPMiddleware $middleware */
|
||||
foreach (array_reverse($middlewares) as $middleware) {
|
||||
$next = function ($request) use ($middleware, $next) {
|
||||
return $middleware->process($request, $next);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,11 +3,13 @@
|
||||
namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
|
||||
/**
|
||||
* Represents a request processer that delegates pre and post request handling to nested request filters
|
||||
* Middleware that provides back-support for the deprecated RequestFilter API.
|
||||
* You should use HTTPMiddleware directly instead.
|
||||
*/
|
||||
class RequestProcessor implements RequestFilter
|
||||
class RequestProcessor implements HTTPMiddleware
|
||||
{
|
||||
use Injectable;
|
||||
|
||||
@ -33,25 +35,34 @@ class RequestProcessor implements RequestFilter
|
||||
$this->filters = $filters;
|
||||
}
|
||||
|
||||
public function preRequest(HTTPRequest $request)
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function process(HTTPRequest $request, callable $delegate)
|
||||
{
|
||||
if ($this->filters) {
|
||||
Deprecation::notice(
|
||||
'4.0',
|
||||
'Deprecated RequestFilters are in use. Apply HTTPMiddleware to Director.middlewares instead.'
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$res = $filter->preRequest($request);
|
||||
if ($res === false) {
|
||||
return false;
|
||||
return new HTTPResponse(_t(__CLASS__.'.INVALID_REQUEST', 'Invalid request'), 400);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function postRequest(HTTPRequest $request, HTTPResponse $response)
|
||||
{
|
||||
$response = $delegate($request);
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$res = $filter->postRequest($request, $response);
|
||||
if ($res === false) {
|
||||
return false;
|
||||
return new HTTPResponse(_t(__CLASS__ . '.REQUEST_ABORTED', 'Request aborted'), 500);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user