103 lines
2.6 KiB
PHP
103 lines
2.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Core;
|
|
|
|
use App\Core\Database;
|
|
|
|
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 post(string $pattern, callable $handler): void
|
|
{
|
|
$this->routes[] = ['method' => 'POST', '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;
|
|
}
|
|
|
|
$this->redirectLegacyPath($path);
|
|
|
|
http_response_code(404);
|
|
view('pages/404', [
|
|
'title' => 'Страница не найдена - Рыбсток',
|
|
'breadcrumbs' => [
|
|
['title' => 'Главная', 'url' => '/'],
|
|
['title' => 'Страница не найдена'],
|
|
],
|
|
]);
|
|
}
|
|
|
|
private function redirectLegacyPath(string $path): void
|
|
{
|
|
try {
|
|
$statement = Database::pdo()->prepare(
|
|
'SELECT new_path, http_code
|
|
FROM redirects
|
|
WHERE old_path = :old_path
|
|
AND is_active = 1
|
|
LIMIT 1'
|
|
);
|
|
$statement->execute(['old_path' => $path]);
|
|
$redirect = $statement->fetch();
|
|
} catch (\Throwable) {
|
|
return;
|
|
}
|
|
|
|
if (!$redirect) {
|
|
return;
|
|
}
|
|
|
|
header('Location: ' . $redirect['new_path'], true, (int) $redirect['http_code']);
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* @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);
|
|
}
|
|
}
|