venom/src/Venom/Routing/Router.php

111 lines
3.3 KiB
PHP

<?php
namespace Venom\Routing;
use Exception;
class Router
{
protected string $id = 'defaultRouter';
protected int $version;
protected string $prefix = '';
protected array $routes = [];
public function __construct(string $id, int $version, string $prefix = '')
{
$this->id = $id;
$this->version = $version;
$this->prefix = $prefix;
}
public function addRoutes(array $routes): void
{
$this->routes = $routes;
}
public function addRoute(string $path, array $route): void
{
$this->routes[$path] = $route;
}
/*
* return matched route or null
*/
public function findRoute($url, $method): ?array
{
$url = $this->removeIfFirst($url, $this->prefix);
// check if full match... this can easily done if the url isset select the empty!
$method = strtoupper($method);
$route = $this->getRouteByName($url, $method);
if ($route !== null) {
return $route;
}
$url = $this->removeIfFirst($url, '/');
$baseRoute = $this->getNearestBaseRoute(explode("/", $url));
if ($baseRoute !== null) {
$count = count($baseRoute['params']);
return $this->getRouteByName($baseRoute['url'], $method, $count, $baseRoute['params']) ?? $this->getRouteByName($baseRoute['url'], $method);
}
return null;
}
private function removeIfFirst($rawString, $string)
{
if ($string !== '' && 0 === strpos($rawString, $string)) {
return substr($rawString, strlen($string));
}
return $rawString;
}
/* @todo implement Security Check if SecurityModule is used */
private function getRouteByName($url, $method, $subRoute = '*', $params = []): ?array
{
$routeAvailable = isset($this->routes[$url]);
$subRouteFound = isset($this->routes[$url]['routes'][$subRoute]);
$methodFound = isset($this->routes[$url]['routes'][$subRoute][$method]);
if ($routeAvailable && $subRouteFound && $methodFound) {
return [
'cl' => $this->routes[$url]['cl'],
'fnc' => $this->routes[$url]['routes'][$subRoute][$method],
'params' => $params
];
}
return null;
}
private function getNearestBaseRoute(array $params): ?array
{
$count = count($params);
$baseUrlArray = [];
$newParams = [];
foreach ($params as $value) {
$baseUrlArray[] = $value;
}
for ($i = 0; $i < $count; $i++) {
$newParams[] = array_pop($baseUrlArray);
$url = '/' . implode('/', $baseUrlArray);
if (isset($this->routes[$url])) {
return ['url' => $url, 'params' => $newParams];
}
}
return null;
}
public function tryFunctionCall(?array $aRoute): bool
{
if ($aRoute === null || !is_callable(array($aRoute['cl'], $aRoute['fnc']))) {
return false;
}
$route = new $aRoute['cl']();
try {
$fnc = $aRoute['fnc'];
$params = $aRoute['params'] ?? [];
$route->$fnc(...$params);
return true;
} catch (Exception $ex) {
return false;
}
}
}