Route middleware
chrisvanpatten opened this issue · 2 comments
Is it possible to register route middleware? I know it's possible to add the 'before' callback, but can these be chained?
I'd like to add an auth check (if user is logged out, redirect to login page) to a big group of routes, but still need to be able to use the 'before' callback for other purposes on some routes.
Thanks!
Well, it is not a Cortex feature and I think it's out of the scope of a router to make middlewares available.
With a little bit of code you can use Cortex with external libraries that provide middlewares.
To give you some directions, I think you can create you custom route class that accepts middlewares.
For example:
namespace Chris;
class MiddlewareQueryRoute extends \Brain\Cortex\Route\QueryRoute {
private $middlewares = [];
public function __construct($path, $queryBuilder, array $options = []) {
// store a "before" callback if it was already there
$before = empty($options['before']) ? null : $options['before'];
// then set before option to a function that 1st runs middlewares and
// after that runs the "before" callback if there was one
$options['before'] = function($vars, $wp, $template, $matches) use($before) {
$this->runMiddlewares($vars, $wp, $template, $matches);
is_callable($before) and $before($vars, $wp, $template, $matches);
};
parent::__construct($path, $queryBuilder, $options);
}
public function addMiddleware(callable $middleware) {
$this->middlewares[] = $middlewares;
return $this;
}
private function runMiddlewares($vars, $wp, $template, $matches) {
array_walk(
$this->middlewares,
function(callable $middleware) use($vars, $wp, $template, $matches) {
$middleware($vars, $wp, $template, $matches);
}
);
}
}
Having this class in place, you can create an instance of your route instead of Cortex QueryRoute
and use it to add middlewares, something like:
use Brain\Cortex\Route\RouteCollectionInterface as Routes;
use Chris\MiddlewareQueryRoute;
add_action('cortex.routes', function(Routes $routes) {
$path = '{type:[a-z]+}/latest';
$querybuilder = function(array $matches) {
return [ 'post_type' => $matches['type'] ];
};
$before = function($vars, $wp, $template, $matches) {
/* do something */
};
$route = new MiddlewareQueryRoute($path, $querybuilder, ['before' => $before])
->addMiddleware(function($vars, $wp, $template, $matches) {
/* do something */
})->addMiddleware(function($vars, $wp, $template, $matches) {
/* do something */
});
$routes->addRoute($route);
});
The "before" callback, if given, will be called after all the middleware callables have been ran.
Note that move from a code like this to a more sophisticated middleware implementation that makes use of, for example, "Relay" or any other middleware library out there, will not be that hard.
Brilliant, thank you!