1
0
Fork 0
Lightning-Tracker/src/Routing/Router.php

142 lines
3.7 KiB
PHP

<?php
declare(strict_types = 1);
namespace Routing;
use Exception;
use InvalidArgumentException;
use Pages\IController;
use Session\PermissionException;
use Session\Session;
final class Router{
private array $routes = [];
public function add(string $path, string $controller_name): void{
$components = explode('/', $path);
$route = &$this->routes;
$base_url_components = 0;
$base_url_found = false;
foreach($components as $component){
if (empty($component)){
continue;
}
if ($component === '&'){
if ($base_url_found){
throw new InvalidArgumentException("Route '$path' has multiple base URL indicators.");
}
$base_url_found = true;
continue;
}
if (!$base_url_found){
$base_url_components++;
}
if ($component[0] === ':'){
$name = substr($component, 1);
if (array_key_exists(':', $route)){
if ($route[':']['name'] !== $name){
throw new InvalidArgumentException("Route '$path' already has a parameter.");
}
}
else{
$route[':'] = [
'name' => $name,
'next' => [],
];
}
$route = &$route[':']['next'];
continue;
}
if (!array_key_exists($component, $route)){
$route[$component] = [];
}
$route = &$route[$component];
}
if (array_key_exists('/', $route)){
throw new InvalidArgumentException("Route '$path' already exists.");
}
if (!$base_url_found){
throw new InvalidArgumentException("Route '$path' is missing base URL indicator.");
}
$route['/'] = [
'ctrl' => $controller_name,
'base' => $base_url_components,
];
}
/**
* @param string $path
* @throws RouterException
*/
public function route(string $path): void{
$components = array_filter(explode('/', $path), static fn($component): bool => !empty($component));
$path = implode('/', $components);
$route = &$this->routes;
$params = [];
foreach($components as $component){
if (empty($component)){
continue;
}
if (array_key_exists($component, $route)){
$route = &$route[$component];
continue;
}
if (array_key_exists(':', $route)){
$info = &$route[':'];
$params[$info['name']] = $component;
$route = &$info['next'];
continue;
}
throw new RouterException("Page '$path' does not exist.", RouterException::STATUS_NOT_FOUND, null);
}
if (!array_key_exists('/', $route)){
throw new RouterException("Page '$path' does not exist.", RouterException::STATUS_NOT_FOUND, null);
}
$route_info = $route['/'];
$controller_name = $route_info['ctrl'];
$base_path = implode('/', array_slice($components, 0, $route_info['base']));
/** @noinspection PhpIncludeInspection */
require_once __DIR__.'/../Pages/Controllers/'.$controller_name.'.php';
$controller_name = strtr($controller_name, '/', '\\');
$controller_class = "\\Pages\\Controllers\\$controller_name";
/** @var IController $controller */
$controller = new $controller_class();
$req = new Request($path, $base_path, $params);
try{
$action = $controller->run($req, Session::get());
$action->execute();
}catch(PermissionException $e){
throw new RouterException($e->getMessage(), RouterException::STATUS_FORBIDDEN, $req, $e);
}catch(Exception $e){
throw new RouterException($e->getMessage(), RouterException::STATUS_SERVER_ERROR, $req, $e);
}
}
}
?>