70 lines
1.7 KiB
PHP
70 lines
1.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Core;
|
|
|
|
final class Router
|
|
{
|
|
/**
|
|
* @var array<int, array{method: string, pattern: string, handler: callable}>
|
|
*/
|
|
private array $routes = [];
|
|
|
|
public function get(string $pattern, callable $handler): void
|
|
{
|
|
$this->routes[] = ['method' => 'GET', 'pattern' => $pattern, 'handler' => $handler];
|
|
}
|
|
|
|
public function dispatch(string $method, string $uri): void
|
|
{
|
|
$path = parse_url($uri, PHP_URL_PATH) ?: '/';
|
|
$path = rtrim($path, '/') ?: '/';
|
|
|
|
foreach ($this->routes as $route) {
|
|
if ($route['method'] !== $method) {
|
|
continue;
|
|
}
|
|
|
|
$params = $this->match($route['pattern'], $path);
|
|
|
|
if ($params === null) {
|
|
continue;
|
|
}
|
|
|
|
($route['handler'])(...$params);
|
|
return;
|
|
}
|
|
|
|
http_response_code(404);
|
|
view('pages/404', [
|
|
'title' => 'Страница не найдена - Рыбсток',
|
|
'breadcrumbs' => [
|
|
['title' => 'Главная', 'url' => '/'],
|
|
['title' => 'Страница не найдена'],
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return array<int, string>|null
|
|
*/
|
|
private function match(string $pattern, string $path): ?array
|
|
{
|
|
$regex = preg_replace('#\{([a-zA-Z_][a-zA-Z0-9_]*)\}#', '([^/]+)', $pattern);
|
|
$regex = '#^' . rtrim((string) $regex, '/') . '$#u';
|
|
|
|
if ($pattern === '/') {
|
|
$regex = '#^/$#u';
|
|
}
|
|
|
|
if (!preg_match($regex, $path, $matches)) {
|
|
return null;
|
|
}
|
|
|
|
array_shift($matches);
|
|
|
|
return array_map('urldecode', $matches);
|
|
}
|
|
}
|