HTTP Middleware
Table of Contents
- Introduction
- Manipulating the Request
- Manipulating the Response
- Global Middleware
- Route Middleware
- Middleware Parameters
Introduction
HTTP middleware are classes that sit in between the Kernel
and Controller
. They manipulate the request and response to do things like authenticate users or enforce CSRF protection for certain routes. They are executed in series in a pipeline.
Opulence uses dependency injection for type-hinted objects in a Middleware
constructor. So, if you need any objects in your handle()
method, just specify them in the constructor. Let's take a look at an example:
namespace Project\Application\Http\Middleware;
use Closure;
use Opulence\Http\Requests\Request;
use Opulence\Http\Responses\RedirectResponse;
use Opulence\Http\Responses\Response;
use Opulence\Routing\Middleware\IMiddleware;
use Project\Domain\Authentication\Authenticator;
class Authentication implements IMiddleware
{
private $authenticator = null;
// Inject any dependencies your middleware needs
public function __construct(Authenticator $authenticator)
{
$this->authenticator = $authenticator;
}
// $next consists of the next middleware in the pipeline
public function handle(Request $request, Closure $next) : Response
{
if (!$this->authenticator->isLoggedIn()) {
return new RedirectResponse('/login');
}
return $next($request);
}
}
Add this middleware to a route:
$router->post('/users/posts', "Project\\Application\\Http\\Controllers\\UserController@createPost", [
'middleware' => "Project\\Domain\\Authentication" // Could also be an array of middleware
]);
Now, the Authenticate
middleware will be run before the createPost()
method is called. If the user is not logged in, he'll be redirected to the login page.
Note: If middleware does not specifically call the
$next
closure, none of the middleware after it in the pipeline will be run.Note: To get the current
Route
(which is accessible throughRouter::getMatchedRoute()
), injectOpulence\Routing\Router
into the constructor.
Manipulating the Request
To manipulate the request before it gets to the controller, make changes to it before calling $next($request)
:
use Closure;
use Opulence\Http\Requests\Request;
use Opulence\Http\Responses\Response;
use Opulence\Routing\Middleware\IMiddleware;
class RequestManipulator implements IMiddleware
{
public function handle(Request $request, Closure $next) : Response
{
// Do our work before returning $next($request)
$request->getHeaders()->add('SOME_HEADER', 'foo');
return $next($request);
}
}
Manipulating the Response
To manipulate the response after the controller has done its work, do the following:
use Closure;
use DateTime;
use Opulence\Http\Requests\Request;
use Opulence\Http\Responses\Cookie;
use Opulence\Routing\Middleware\IMiddleware;
class ResponseManipulator implements IMiddleware
{
public function handle(Request $request, Closure $next) : Response
{
$response = $next($request);
// Make our changes
$cookie = new Cookie('my_cookie', 'foo', DateTime::createFromFormat('+1 week'));
$response->getHeaders()->setCookie($cookie);
return $response;
}
}
Global Middleware
Global middleware is middleware that is run on every route. To add middleware to the list of global middleware, add the fully-qualified middleware class' name to the array in config/http/middleware.php.
Route Middleware
To learn how to register middleware with routes, read the routing tutorial. You can also learn how to add middleware to route groups there.
Middleware Parameters
Occasionally, you'll find yourself wanting to pass in primitive values to middleware to indicate something such as a required role to see a page. In these cases, your middleware should extend Opulence\Routing\Middleware\ParameterizedMiddleware
:
use Closure;
use Opulence\Http\HttpException;
use Opulence\Http\Requests\Request;
use Opulence\Http\Responses\Response;
use Opulence\Routing\Middleware\ParameterizedMiddleware;
class RoleMiddleware extends ParameterizedMiddleware
{
private $user;
// Inject any dependencies your middleware needs
public function __construct(User $user)
{
$this->user = $user;
}
public function handle(Request $request, Closure $next) : Response
{
// Parameters are available via $this->getParameter()
// You may pass in a second parameter as the default value if the parameter
// was not found
if (!$this->user->hasRole($this->getParameter('role'))) {
throw new HttpException(403);
}
return $next($request);
}
}
To actually specify role
, use {Your middleware}::withParameters()
in your router configuration:
$options = [
'middleware' => [RoleMiddleware::withParameters(['role' => 'admin'])]
];
$router->get('/users', "MyController\\MyController@myMethod", $options);