lighthouse/middleware

PSR-15 HTTP Middleware Pipeline for the Lighthouse framework

Installs: 11

Dependents: 1

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/lighthouse/middleware

v0.1.0 2025-12-17 14:03 UTC

This package is auto-updated.

Last update: 2025-12-17 18:27:54 UTC


README

A PSR-15 HTTP Middleware Pipeline for the Lighthouse framework.

Installation

composer require lighthouse/middleware

Requirements

  • PHP 8.2 or higher

Features

  • PSR-15 compliant middleware pipeline
  • Onion-style middleware processing
  • Callable middleware support
  • Request/response modification
  • Short-circuit capability

Quick Start

Basic Pipeline

use Lighthouse\Middleware\Pipeline;
use Lighthouse\Middleware\CallableMiddleware;
use Psr\Http\Server\RequestHandlerInterface;

$pipeline = new Pipeline();

// Add middleware
$pipeline->pipe(new LoggingMiddleware());
$pipeline->pipe(new AuthenticationMiddleware());
$pipeline->pipe(new RoutingMiddleware());

// Process request
$response = $pipeline->handle($request);

Callable Middleware

You can use closures instead of full middleware classes:

$pipeline->pipe(function ($request, $handler) {
    // Before: modify request
    $request = $request->withAttribute('start_time', microtime(true));
    
    // Call next middleware
    $response = $handler->handle($request);
    
    // After: modify response
    return $response->withHeader('X-Request-Time', microtime(true) - $request->getAttribute('start_time'));
});

Middleware Order (Onion Model)

Middleware is processed in order added, but responses flow back in reverse:

$pipeline->pipe($middleware1);  // Executes first, returns last
$pipeline->pipe($middleware2);  // Executes second, returns second-to-last
$pipeline->pipe($middleware3);  // Executes last, returns first

// Request flow:  middleware1 → middleware2 → middleware3 → handler
// Response flow: middleware1 ← middleware2 ← middleware3 ← handler

Short-Circuiting

Middleware can return early without calling the next handler:

$pipeline->pipe(function ($request, $handler) {
    if (!$this->isAuthenticated($request)) {
        // Return immediately, skip remaining middleware
        return new Response(401);
    }
    
    return $handler->handle($request);
});

Fallback Handler

Set a handler to use when no middleware generates a response:

use Lighthouse\Middleware\FallbackHandler;

// Throw exception (default)
$pipeline = new Pipeline();

// Return 404 response
$pipeline = new Pipeline(new FallbackHandler(
    fn() => new Response(404, body: 'Not Found')
));

// Or set later
$pipeline->fallback($customHandler);

Add Multiple Middleware

$pipeline->through([
    new CorsMiddleware(),
    new AuthMiddleware(),
    new RateLimitMiddleware(),
]);

Creating Middleware

Implement MiddlewareInterface:

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class TimingMiddleware implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        $start = microtime(true);
        
        $response = $handler->handle($request);
        
        $duration = microtime(true) - $start;
        
        return $response->withHeader('X-Response-Time', sprintf('%.3fms', $duration * 1000));
    }
}

API Reference

Pipeline

Method Description
pipe(MiddlewareInterface|callable $middleware) Add middleware to pipeline
through(array $middleware) Add multiple middleware
fallback(RequestHandlerInterface $handler) Set fallback handler
handle(ServerRequestInterface $request) Process request through pipeline
getMiddleware() Get middleware stack
clear() Remove all middleware

CallableMiddleware

Wraps a callable as MiddlewareInterface:

$middleware = new CallableMiddleware(
    fn($request, $handler) => $handler->handle($request)
);

NextHandler

Wraps a callable as RequestHandlerInterface:

$handler = new NextHandler(
    fn($request) => new Response(200)
);

FallbackHandler

Default handler when middleware stack is exhausted:

// Throws RuntimeException
$handler = new FallbackHandler();

// Returns custom response
$handler = new FallbackHandler(fn() => new Response(404));

Testing

composer test

License

MIT License. See LICENSE for details.

Part of the Lighthouse Framework

This package is part of the Lighthouse Framework, an educational PHP framework designed to teach how modern frameworks work internally.