web-base/Core/Objects/Router/Router.class.php

179 lines
4.4 KiB
PHP
Raw Normal View History

2022-06-01 09:47:31 +02:00
<?php
2022-11-18 18:06:46 +01:00
namespace Core\Objects\Router;
2022-06-01 09:47:31 +02:00
2022-11-18 18:06:46 +01:00
use Core\Driver\Logger\Logger;
use Core\Objects\Context;
2022-11-27 12:33:27 +01:00
use Core\Objects\DatabaseEntity\Route;
2022-06-01 09:47:31 +02:00
class Router {
2022-06-20 19:52:31 +02:00
private Context $context;
2022-06-01 09:47:31 +02:00
private Logger $logger;
2022-11-27 12:33:27 +01:00
private ?Route $activeRoute;
2022-08-20 22:17:17 +02:00
private ?string $requestedUri;
2022-06-01 09:47:31 +02:00
protected array $routes;
protected array $statusCodeRoutes;
2022-06-20 19:52:31 +02:00
public function __construct(Context $context) {
$this->context = $context;
2022-06-01 09:47:31 +02:00
$this->routes = [];
$this->statusCodeRoutes = [];
2022-08-20 22:17:17 +02:00
$this->activeRoute = null;
$this->requestedUri = null;
$this->context->router = $this;
2022-06-01 09:47:31 +02:00
2022-06-20 19:52:31 +02:00
$sql = $context->getSQL();
if ($sql) {
$this->addRoute(new ApiRoute());
2022-06-20 19:52:31 +02:00
$this->logger = new Logger("Router", $sql);
} else {
$this->logger = new Logger("Router");
}
2022-06-01 09:47:31 +02:00
}
2022-11-27 12:33:27 +01:00
public function getActiveRoute(): ?Route {
2022-08-20 22:17:17 +02:00
return $this->activeRoute;
}
public function getRequestedUri(): ?string {
return $this->requestedUri;
}
2024-04-11 17:51:50 +02:00
public function run(string $url, array &$pathParams): ?Route {
2022-06-01 09:47:31 +02:00
// TODO: do we want a global try cache and return status page 500 on any error?
2022-08-20 22:17:17 +02:00
$this->requestedUri = $url;
2022-06-01 09:47:31 +02:00
$url = strtok($url, "?");
foreach ($this->routes as $route) {
2024-04-11 17:51:50 +02:00
$match = $route->match($url);
if ($match !== false) {
2022-08-20 22:17:17 +02:00
$this->activeRoute = $route;
2024-04-11 17:51:50 +02:00
$pathParams = $match;
return $this->activeRoute;
2022-06-01 09:47:31 +02:00
}
}
2024-04-11 17:51:50 +02:00
return null;
2022-06-01 09:47:31 +02:00
}
public function returnStatusCode(int $code, array $params = []): string {
http_response_code($code);
$params["status_code"] = $code;
$params["status_description"] = HTTP_STATUS_DESCRIPTIONS[$code] ?? "Unknown Error";
$route = $this->statusCodeRoutes[strval($code)] ?? null;
if ($route) {
return $route->call($this, $params);
} else {
2022-11-18 18:06:46 +01:00
$req = new \Core\API\Template\Render($this->context);
2022-06-01 09:47:31 +02:00
$res = $req->execute(["file" => "error_document.twig", "parameters" => $params]);
if ($res) {
return $req->getResult()["html"];
} else {
$description = htmlspecialchars($params["status_description"]);
return "<b>$code - $description</b>";
}
}
}
public function addRoute(Route $route): void {
2022-08-20 22:17:17 +02:00
if (preg_match("/^\/(\d+)$/", $route->getPattern(), $re)) {
$this->statusCodeRoutes[$re[1]] = $route;
2022-06-01 09:47:31 +02:00
}
2022-08-20 22:17:17 +02:00
$this->routes[] = $route;
2022-06-01 09:47:31 +02:00
}
public function writeCache(string $file): bool {
$routes = "";
2022-11-18 18:06:46 +01:00
$uses = [
"Core\Objects\Context",
"Core\Objects\Router\Router",
];
2022-06-01 09:47:31 +02:00
foreach ($this->routes as $route) {
2022-06-01 11:20:24 +02:00
// do not generate cache for static api route
if ($route instanceof ApiRoute) {
continue;
}
2022-11-18 18:06:46 +01:00
$class = $route->getClass();
2022-06-01 09:47:31 +02:00
$constructor = $route->generateCache();
2022-11-18 18:06:46 +01:00
$uses[] = $class->getName();
2022-06-01 09:47:31 +02:00
$routes .= "\n \$this->addRoute($constructor);";
}
2022-11-18 18:06:46 +01:00
$uses = implode("\n", array_map(function ($use) { return "use $use;"; }, array_unique($uses)));
2022-06-01 09:47:31 +02:00
$date = (new \DateTime())->format("Y/m/d H:i:s");
$code = "<?php
/**
* DO NOT EDIT!
* This file is automatically generated by the RoutesAPI on $date.
*/
2022-12-04 13:21:40 +01:00
namespace Site\Cache;
2022-11-18 18:06:46 +01:00
$uses
2022-06-01 09:47:31 +02:00
class RouterCache extends Router {
2022-06-20 19:52:31 +02:00
public function __construct(Context \$context) {
parent::__construct(\$context);$routes
2022-06-01 09:47:31 +02:00
}
}
";
2023-01-09 15:59:53 +01:00
$directory = dirname($file);
if (!is_dir($directory)) {
if (!mkdir($directory, 775, true)) {
$this->logger->severe("Could not create directory: $directory");
return false;
}
}
2022-06-01 09:47:31 +02:00
if (@file_put_contents($file, $code) === false) {
$this->logger->severe("Could not write Router cache file: $file");
return false;
}
return true;
}
2022-06-20 19:52:31 +02:00
public function getContext(): Context {
return $this->context;
2022-06-01 09:47:31 +02:00
}
public function getLogger(): Logger {
return $this->logger;
}
public static function cleanURL(string $url, bool $cleanGET = true): string {
// strip GET parameters
if ($cleanGET) {
if (($index = strpos($url, "?")) !== false) {
$url = substr($url, 0, $index);
}
}
// strip document reference part
if (($index = strpos($url, "#")) !== false) {
$url = substr($url, 0, $index);
}
// strip leading slash
return preg_replace("/^\/+/", "", $url);
}
2022-08-20 22:17:17 +02:00
public function getRoutes(bool $includeStatusRoutes = false): array {
if (!$includeStatusRoutes && !empty($this->statusCodeRoutes)) {
return array_filter($this->routes, function ($route) {
return !in_array($route, $this->statusCodeRoutes);
});
}
return $this->routes;
}
2022-06-01 09:47:31 +02:00
}