98 lines
3.0 KiB
PHP
98 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Core;
|
|
|
|
class Router
|
|
{
|
|
/** @var array<string, array<int, array{path:string,action:callable,middleware:array}>> */
|
|
private array $routes = [];
|
|
|
|
/** @var array<int, array<int, class-string>> */
|
|
private array $middlewareStack = [];
|
|
|
|
public function get(string $path, callable $action, array $middleware = []): void
|
|
{
|
|
$this->addRoute('GET', $path, $action, $middleware);
|
|
}
|
|
|
|
public function post(string $path, callable $action, array $middleware = []): void
|
|
{
|
|
$this->addRoute('POST', $path, $action, $middleware);
|
|
}
|
|
|
|
public function put(string $path, callable $action, array $middleware = []): void
|
|
{
|
|
$this->addRoute('PUT', $path, $action, $middleware);
|
|
}
|
|
|
|
public function delete(string $path, callable $action, array $middleware = []): void
|
|
{
|
|
$this->addRoute('DELETE', $path, $action, $middleware);
|
|
}
|
|
|
|
public function group(array $attributes, \Closure $callback): void
|
|
{
|
|
$groupMiddleware = $attributes['middleware'] ?? [];
|
|
$this->middlewareStack[] = $groupMiddleware;
|
|
$callback($this);
|
|
array_pop($this->middlewareStack);
|
|
}
|
|
|
|
/**
|
|
* @param array<int, class-string> $middleware
|
|
*/
|
|
private function addRoute(string $method, string $path, callable $action, array $middleware = []): void
|
|
{
|
|
$stackedMiddleware = [];
|
|
foreach ($this->middlewareStack as $group) {
|
|
$stackedMiddleware = array_merge($stackedMiddleware, $group);
|
|
}
|
|
$combinedMiddleware = array_merge($stackedMiddleware, $middleware);
|
|
|
|
$this->routes[$method][] = [
|
|
'path' => $path,
|
|
'action' => $action,
|
|
'middleware' => $combinedMiddleware,
|
|
];
|
|
}
|
|
|
|
public function dispatch(string $method, string $uri): Response
|
|
{
|
|
$uri = parse_url($uri, PHP_URL_PATH) ?? '/';
|
|
$routes = $this->routes[$method] ?? [];
|
|
|
|
foreach ($routes as $route) {
|
|
$pattern = '#^' . preg_replace('#\{(.*?)\}#', '(?P<$1>[^/]+)', $route['path']) . '$#';
|
|
if (preg_match($pattern, $uri, $matches)) {
|
|
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
|
|
$handler = $this->applyMiddleware($route['action'], $route['middleware']);
|
|
$result = $handler($params);
|
|
|
|
if ($result instanceof Response) {
|
|
return $result;
|
|
}
|
|
|
|
return new Response((string) $result);
|
|
}
|
|
}
|
|
|
|
return new Response('Not Found', 404);
|
|
}
|
|
|
|
/**
|
|
* @param callable $action
|
|
* @param array<int, class-string> $middleware
|
|
*/
|
|
private function applyMiddleware(callable $action, array $middleware): callable
|
|
{
|
|
return array_reduce(
|
|
array_reverse($middleware),
|
|
function ($next, $middlewareClass) {
|
|
$middlewareInstance = new $middlewareClass();
|
|
return fn(array $params) => $middlewareInstance->handle($params, $next);
|
|
},
|
|
$action
|
|
);
|
|
}
|
|
}
|