HTTP Middleware

Table of Contents

  1. Introduction
  2. Manipulating the Request
  3. Manipulating the Response
  4. Global Middleware
  5. Route Middleware
  6. 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 through Router::getMatchedRoute()), inject Opulence\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);