laminas/laminas-stratigility
Laminas Stratigility provides PSR-15 HTTP middleware tools, including a middleware pipeline and helpers for composing request handlers. Build reusable, interoperable middleware stacks for PHP applications and frameworks.
Installation:
composer require laminas/laminas-stratigility
Ensure your project uses PSR-7 (e.g., laminas/laminas-diactoros for HTTP messages).
First Use Case: Create a middleware pipeline for a simple route handler:
use Laminas\Stratigility\Middleware\MiddlewareInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface as PsrMiddlewareInterface;
// Define a middleware
class MyMiddleware implements PsrMiddlewareInterface {
public function process(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface {
$response->getBody()->write('Before ');
$response = $next($request, $response);
$response->getBody()->write(' After');
return $response;
}
}
// Dispatch the pipeline
$middleware = new MyMiddleware();
$pipe = new \Laminas\Stratigility\MiddlewarePipe();
$pipe->pipe($middleware);
$response = $pipe($request, $response);
Key Files:
Middleware Composition:
Chain middleware in a pipeline using MiddlewarePipe:
$pipe = new \Laminas\Stratigility\MiddlewarePipe();
$pipe->pipe(new AuthMiddleware());
$pipe->pipe(new LoggingMiddleware());
$pipe->pipe(new RouteMiddleware());
Conditional Middleware:
Use ConditionalMiddleware to add logic:
use Laminas\Stratigility\Middleware\ConditionalMiddleware;
$conditional = new ConditionalMiddleware(
fn($request) => $request->getUri()->getPath() === '/admin',
new AdminMiddleware()
);
$pipe->pipe($conditional);
Error Handling:
Wrap pipelines in ErrorHandlerMiddleware:
use Laminas\Stratigility\Middleware\ErrorHandlerMiddleware;
$errorHandler = new ErrorHandlerMiddleware(
new \Laminas\Stratigility\Error\ErrorResponseGenerator(),
new \Laminas\Stratigility\Error\WhoopsErrorHandler()
);
$pipe->pipe($errorHandler);
Route-Based Dispatching:
Use RouteMiddleware with a router (e.g., laminas/laminas-router):
use Laminas\Stratigility\Middleware\RouteMiddleware;
$router = new \Laminas\Router\Http\Segment();
$routeMiddleware = new RouteMiddleware($router);
$pipe->pipe($routeMiddleware);
Laravel-Specific:
Leverage laminas/laminas-stratigility with Laravel’s Http\Kernel by creating a custom middleware group:
// app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\VerifyCsrfToken::class,
\Laminas\Stratigility\Middleware\MiddlewarePipe::class, // Custom pipe
],
];
PSR-15 Compliance:
Ensure all middleware implement Psr\Http\Server\MiddlewareInterface for compatibility.
Testing: Mock middleware pipelines in tests:
$pipe = new \Laminas\Stratigility\MiddlewarePipe();
$pipe->pipe(new class implements PsrMiddlewareInterface {
public function process(ServerRequestInterface $request, ResponseInterface $response, callable $next) {
// Test logic
return $next($request, $response);
}
});
Middleware Order Matters: Pipelines execute middleware sequentially. Reordering can break functionality (e.g., auth before logging vs. logging before auth).
Error Handling Gaps:
Uncaught exceptions in middleware terminate the pipeline. Always wrap critical middleware in ErrorHandlerMiddleware:
$pipe->pipe(new ErrorHandlerMiddleware(...));
PSR-7 Version Conflicts:
Ensure your PSR-7 implementation (e.g., laminas-diactoros) matches laminas-stratigility's requirements (PSR-7 v1.1+ for v4.x).
Circular Dependencies:
Avoid recursive middleware calls (e.g., middleware A calling middleware B, which calls A again). Use MiddlewarePipe::getMiddlewareQueue() to inspect the pipeline.
Middleware Inspection: Dump the pipeline queue to debug order:
foreach ($pipe->getMiddlewareQueue() as $index => $middleware) {
echo "Middleware #$index: " . get_class($middleware) . "\n";
}
Response Logging: Log responses after each middleware for debugging:
$pipe->pipe(new class implements PsrMiddlewareInterface {
public function process(ServerRequestInterface $request, ResponseInterface $response, callable $next) {
$response = $next($request, $response);
error_log($response->getBody()->getContents());
return $response;
}
});
Custom Middleware:
Extend AbstractMiddleware for reusable base logic:
use Laminas\Stratigility\Middleware\AbstractMiddleware;
class BaseMiddleware extends AbstractMiddleware {
protected function process(ServerRequestInterface $request, ResponseInterface $response, callable $next) {
// Shared logic
return $next($request, $response);
}
}
Middleware Stacks:
Dynamically build pipelines from config (e.g., config/middleware.php):
return [
'web' => [
\App\Middleware\Auth::class,
\App\Middleware\Locale::class,
],
'api' => [
\App\Middleware\CORS::class,
\App\Middleware\RateLimit::class,
],
];
PSR-15 Middleware:
Convert PSR-15 middleware to laminas-stratigility format:
$psr15Middleware = new class implements PsrMiddlewareInterface {
public function process(ServerRequestInterface $request, ResponseInterface $response, callable $next) {
return $next($request, $response);
}
};
$pipe->pipe($psr15Middleware);
str_contains() or str_starts_with() for path matching in middleware (PHP 8.5 deprecates strstr() for this purpose).declare(strict_types=1);
class MyMiddleware implements PsrMiddlewareInterface { ... }
How can I help you explore Laravel packages today?