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; } } }