On this page
Executing and composing middleware
The easiest way to execute middleware is to write closures and attach them to a
Laminas\Stratigility\MiddlewarePipe
instance. You can nest MiddlewarePipe
instances to create groups of related middleware, and attach them using a base
path so they only execute if that path is matched.
$api = new MiddlewarePipe(); // API middleware collection
$api->pipe(/* ... */); // repeat as necessary
$app = new MiddlewarePipe(); // Middleware representing the application
$app->pipe(new PathMiddlewareDecorator('/api', $api)); // API middleware attached to the path "/api"
Request path changes when path matched
When you use the
PathMiddlewareDecorator
using a path (other than '' or '/'), the middleware it decorates is dispatched with a request that strips the matched segment(s) from the start of the path. Using the previous example, if the path/api/users/foo
is matched, the$api
middleware will receive a request with the path/users/foo
. This allows middleware segregated by path to be re-used without changes to its own internal routing.
Handling errors
While the above will give you a basic application, it has no error handling
whatsoever. We recommend adding an initial middleware layer using the
Laminas\Stratigility\Middleware\ErrorHandler
class:
use Laminas\Diactoros\Response;
use Laminas\Stratigility\Middleware\ErrorHandler;
$app->pipe(new ErrorHandler(new Response());
// Add more middleware...
You can learn how to customize the error handler to your needs in the chapter on error handlers.
Decorating the MiddlewarePipe
Another approach is to compose a Laminas\Stratigility\MiddlewarePipe
instance
within your own Psr\Http\Server\MiddlewareInterface
implementation, and
optionally implementing the RequestHandlerInterface
and/or pipe()
method.
In such a case, you might define the process()
method to perform any
additional logic you have, and then call on the decorated MiddlewarePipe
instance in order to iterate through your stack of middleware:
class CustomMiddleware implements MiddlewareInterface
{
private $pipeline;
public function __construct(MiddlewarePipe $pipeline)
{
$this->pipeline = $pipeline;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
// perform some work...
// delegate to parent
$this->pipeline->process($request, $handler);
// maybe do more work?
}
}
Another approach using this method would be to override the constructor to add in specific middleware, perhaps using configuration provided.
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Laminas\Stratigility\MiddlewarePipe;
class CustomMiddleware implements MiddlewareInterface
{
private $pipeline;
public function __construct(array $configuration, MiddlewarePipe $pipeline)
{
// do something with configuration ...
// attach some middleware ...
$pipeline->pipe(/* some middleware */);
$this->pipeline = $pipeline;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
/* ... */
}
}
These approaches are particularly suited for cases where you may want to implement a specific workflow for an application segment using existing middleware, but do not necessarily want that middleware applied to all requests in the application.