Creating Middleware
Middleware piped to a MiddlewarePipe
MUST implement the
PSR-15 middleware interface.
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class MyMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
) : ResponseInterface {
// ... do something and return response
// or call request handler:
// return $handler->handle($request);
}
}
Anonymous middleware
For one-off middleware, particularly when debugging, you can use an anonymous
class to implement MiddlewareInterface
:
$pipeline->pipe(new class implements MiddlewareInterface {
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
$response = $handler->handle($request);
return $response->withHeader('X-Clacks-Overhead', 'GNU Terry Pratchett');
}
});
Callable middleware
Sometimes it's easier to eschew the MiddlewareInterface
, particularly when
creating a one-off middleware for debugging purposes. In those cases, you can
create a PHP callable that follows the same signature of
MiddlewareInterface::process()
, and wrap it in a
Laminas\Stratigility\Middleware\CallableMiddlewareDecorator
instance:
$pipeline->pipe(new CallableMiddlewareDecorator(function ($req, $handler) {
// do some work
$response = $handler->($req);
// do some work
return $response;
});
The typehints for the arguments are optional, but such callable middleware will
receive ServerRequestInterface
and RequestHandlerInterface
instances,
in that order.
You may also use the middleware()
utility function in place of new
CallableMiddlewareDecorator()
.
Double-Pass middleware
Prior to PSR-15, many PSR-7 frameworks and projects adopted a "double-pass" middleware definition:
function (
ServerRequestInterface $request,
ResponseInterface $response,
callable $next
) : ResponseInterface
where $next
had the signature:
function (
ServerRequestInterface $request,
ResponseInterface $response
) : ResponseInterface
The latter interface is the origin of the term "double-pass", as the
implementation passes not a single argument, but two. (The $response
argument
was often used as a response prototype for middleware that needed to return a
response.)
Laminas\Stratigility\Middleware\DoublePassMiddlewareDecorator
allows decorating
such middleware within a PSR-15 MiddlewareInterface
implementation, allowing
it to be used in your Stratigility application.
When using DoublePassMiddlewareDecorator
, internally it will decorate the
$handler
instance as a callable.
To use the decorator, pass it the double-pass middleware to decorate via the constructor:
$pipeline->pipe(new DoublePassMiddlewareDecorator($middleware));
If you are not using laminas-diactoros for your PSR-7 implementation, the decorator
also accepts a second argument, a PSR-7 ResponseInterface
prototype instance
to pass to the double-pass middleware:
$pipeline->pipe(new DoublePassMiddlewareDecorator(
$middleware,
$responsePrototype
));
You may also use the doublePassMiddleware()
utility function in place of new
DoublePassMiddlewareDecorator()
.
Beware of operating on the response
In many cases, poorly written double-pass middleware will manipulate the response provided to them and pass the manipulated version to
$next
.This is problematic if you mix standard PSR-15 and double-pass middleware, as the response instance is dropped when
$next
is called, as the decorator we provide will ignore the argument.If you notice such issues appearing, please report them to the project providing the double-pass middleware, and ask them to only operate on the returned response.