This document assumes you’ve installed hiraeth/bootstrap
or a combination of hiraeth/diactoros
and hiraeth/harmony
. If you haven’t your mileage may vary. See the installation docs for more information.
Hiraeth supports PSR-15 middleware implementing Psr\Http\Server\MiddlewareInterface
. In addition to being able to add middleware from third-party sources, a handful of middleware are installed/provided in hiraeth/bootstrap
out of the box:
Middleware | Description |
---|---|
client-ip | Provides accurate client IP as a Request attribute (client-ip ) |
encrypt-cookies | Encrypts cookies for added security |
session | Activates the user session and handles response cookies |
csrf-token | Validates csrf::token input field |
firewall | A simple IP based firewall |
templates | Renders templates directly (no routing / action) based URL path |
routing | Resolves and executes routes |
Creating a Middleware
Middleware needs to implement the Psr\Http\Server\MiddlewareInterface
namespace Acme\Middleware;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
use Psr\Http\Server\RequestHandlerInterface as Handler;
class Foo implements Middleware
{
public function process(Request $request, Handler $handler): Response
{
//
// Modify request or return response early.
//
$response = $handler->handle($request);
//
// Modify the response
//
return $response;
}
}
Registering Middleware
Middleware can be registered by adding a new configuration file in config/middleware
folder. The only required property is the class name. In this example, we’ll create config/middleware/foo.jin
:
[middleware]
;
; The middleware class to register
;
class = Acme\Middleware\Foo
Priorities
Since middlewares are registered in separate configuration files, they should have an explicit priority set if they need to occur at a specific point in the stack.:
[middleware]
;
; Where in the stack should this be run? Lower priority is first in,
; last out.
;
priority = 22
;
; The middleware class to register
;
class = Acme\Middleware\Foo
The default priority is 50 and the maximum used by official packages is 100 (the router).
If you are releasing a package that integrates with Hiraeth, it is suggested you use the following reference to determine an appropriate priority for your middleware. End-users can use this as a reference to get an idea where they may wish to place their own middleware with respect to others.
Priority | Description |
---|---|
0 - 10 | Error / exception handling middleware, request normalization, session handling. |
11 - 20 | Reserved for end-users. |
21 - 30 | Early returners like redirectors, IP based firewalls, etc. |
31 - 40 | Reserved for end-users. |
41 - 50 | Authentication, content security, etc. |
51 - 60 | Reserved for end-users. |
61 - 70 | Content modifiers, compression, etc. |
71 - 80 | Reserved for end-users. |
81 - 90 | Content response handlers |
91 - 99 | Reserved for end-users. |
Disabling Middleware
If you need to disable a middleware quickly, then the easiest way is simply to add a disabled
property to the configuration and set the value to TRUE
.
[middleware]
;
; Whether or not this middleware is disabled
;
disabled = true
;
; Where in the stack should this be run? Lower priority is first in,
; last out.
;
priority = 22
;
; The middleware class to register
;
class = Acme\Middleware\Foo
Dependency Injection
Middleware classes will be constructed via Hiraeth’s dependency injector and will therefore be automatically and recursively injected with simple dependencies and dependencies for which there are already delegates/providers registered.
public function __construct(Acme\Foo\Service $service)
{
$this->service = $service;
}
If your middleware has complex dependencies or additional configuration options, you may want to write a delegate or provider to handle its construction and/or configuration. While many other registered services use [&.options]
key to enable passing options directly to the constructor, many middleware do not support constructor based option setting. For this reason, the delegate is fully responsible for getting and setting all configuration values.
The creation of these delegates is made a bit easier by extending Hiraeth\Middleware\AbstractDelegate
:
class MiddlewareDelegate extends Hiraeth\Middleware\AbstractDelegate
{
protected static $defaultOptions = [
'constructoption' => 10
'setteroption' => 'value'
];
public static function getClass(): string
{
return My\Middleware::class;
}
public function __invoke(Hiraeth\Application $app): object
{
$options = $this->getOptions();
$instance = new My\Middleware($options['constructoption']);
$instance->setOption($options['setteroption']);
return $instance;
}
}
Now you can add the options to your middleware config:
[middleware]
...
[&.options]
constructoption = 15
setteropation = 'customvalue'