113 lines
3.6 KiB
PHP
113 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace KTXC\Http\Middleware;
|
|
|
|
use KTXC\Http\Request\Request;
|
|
use KTXC\Http\Response\Response;
|
|
use Psr\Container\ContainerInterface;
|
|
|
|
/**
|
|
* Middleware pipeline - processes request through a stack of middleware
|
|
*/
|
|
class MiddlewarePipeline implements RequestHandlerInterface
|
|
{
|
|
/** @var array<string|MiddlewareInterface> */
|
|
private array $middleware = [];
|
|
|
|
private ?ContainerInterface $container = null;
|
|
|
|
public function __construct(?ContainerInterface $container = null)
|
|
{
|
|
$this->container = $container;
|
|
}
|
|
|
|
/**
|
|
* Add middleware to the pipeline
|
|
*
|
|
* @param string|MiddlewareInterface $middleware Middleware class name or instance
|
|
* @return self
|
|
*/
|
|
public function pipe(string|MiddlewareInterface $middleware): self
|
|
{
|
|
$this->middleware[] = $middleware;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Handle the request through the middleware pipeline
|
|
*
|
|
* @param Request $request
|
|
* @return Response
|
|
*/
|
|
public function handle(Request $request): Response
|
|
{
|
|
// Create a handler for the pipeline
|
|
$handler = $this->createHandler(0);
|
|
|
|
return $handler->handle($request);
|
|
}
|
|
|
|
/**
|
|
* Create a handler for a specific position in the pipeline
|
|
*
|
|
* @param int $index Current position in the middleware stack
|
|
* @return RequestHandlerInterface
|
|
*/
|
|
public function createHandler(int $index): RequestHandlerInterface
|
|
{
|
|
// If we've reached the end of the pipeline, return a default handler
|
|
if (!isset($this->middleware[$index])) {
|
|
return new class implements RequestHandlerInterface {
|
|
public function handle(Request $request): Response {
|
|
return new Response(Response::$statusTexts[Response::HTTP_NOT_FOUND], Response::HTTP_NOT_FOUND);
|
|
}
|
|
};
|
|
}
|
|
|
|
return new class($this->middleware[$index], $this, $index, $this->container) implements RequestHandlerInterface {
|
|
private string|MiddlewareInterface $middleware;
|
|
private MiddlewarePipeline $pipeline;
|
|
private int $index;
|
|
private ?ContainerInterface $container;
|
|
|
|
public function __construct(
|
|
string|MiddlewareInterface $middleware,
|
|
MiddlewarePipeline $pipeline,
|
|
int $index,
|
|
?ContainerInterface $container
|
|
) {
|
|
$this->middleware = $middleware;
|
|
$this->pipeline = $pipeline;
|
|
$this->index = $index;
|
|
$this->container = $container;
|
|
}
|
|
|
|
public function handle(Request $request): Response
|
|
{
|
|
// Resolve middleware instance if it's a class name
|
|
$middleware = $this->middleware;
|
|
|
|
if (is_string($middleware)) {
|
|
if ($this->container && $this->container->has($middleware)) {
|
|
$middleware = $this->container->get($middleware);
|
|
} else {
|
|
$middleware = new $middleware();
|
|
}
|
|
}
|
|
|
|
if (!$middleware instanceof MiddlewareInterface) {
|
|
throw new \RuntimeException(
|
|
sprintf('Middleware must implement %s', MiddlewareInterface::class)
|
|
);
|
|
}
|
|
|
|
// Create the next handler in the chain
|
|
$next = $this->pipeline->createHandler($this->index + 1);
|
|
|
|
// Process this middleware
|
|
return $middleware->process($request, $next);
|
|
}
|
|
};
|
|
}
|
|
}
|