92 lines
2.3 KiB
PHP
92 lines
2.3 KiB
PHP
<?php namespace SokoWeb\Routing;
|
|
|
|
use Closure;
|
|
use SokoWeb\Interfaces\Routing\IRoute;
|
|
use SokoWeb\Interfaces\Routing\IRouteCollection;
|
|
|
|
class RouteCollection implements IRouteCollection
|
|
{
|
|
private array $routes = [];
|
|
|
|
private array $searchTable = [
|
|
'get' => [],
|
|
'post' => []
|
|
];
|
|
|
|
private array $groupStack = [];
|
|
|
|
public function get(string $id, string $pattern, array $handler): void
|
|
{
|
|
$this->addRoute('get', $id, $pattern, $handler);
|
|
}
|
|
|
|
public function post(string $id, string $pattern, array $handler): void
|
|
{
|
|
$this->addRoute('post', $id, $pattern, $handler);
|
|
}
|
|
|
|
public function group(string $pattern, Closure $group): void
|
|
{
|
|
$this->groupStack[] = $pattern;
|
|
|
|
$group($this);
|
|
|
|
array_pop($this->groupStack);
|
|
}
|
|
|
|
public function getRoute(string $id): ?IRoute
|
|
{
|
|
if (!isset($this->routes[$id])) {
|
|
return null;
|
|
}
|
|
|
|
return $this->routes[$id];
|
|
}
|
|
|
|
public function match(string $method, string $uri): ?array
|
|
{
|
|
$path = $uri === '/' ? [] : explode('/', ltrim($uri, '/'));
|
|
$groupNumber = count($path);
|
|
|
|
// response to HEAD request with the GET content
|
|
if ($method === 'head') {
|
|
$method = 'get';
|
|
}
|
|
|
|
if (!isset($this->searchTable[$method][$groupNumber])) {
|
|
return null;
|
|
}
|
|
|
|
foreach ($this->searchTable[$method][$groupNumber] as $route) {
|
|
if (($parameters = $route->testAgainst($path)) !== null) {
|
|
return [$route, $parameters];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function addRoute(string $method, string $id, string $pattern, array $handler): void
|
|
{
|
|
if (isset($this->routes[$id])) {
|
|
throw new \Exception('Route already exists: ' . $id);
|
|
}
|
|
|
|
$pattern = array_merge($this->groupStack, $pattern === '' ? [] : explode('/', $pattern));
|
|
$route = new Route($id, $pattern, $handler);
|
|
|
|
$groupNumber = count($pattern);
|
|
|
|
$this->searchTable[$method][$groupNumber][] = $route;
|
|
|
|
while (preg_match('/^{\\w+\\?}$/', end($pattern)) === 1) {
|
|
$groupNumber--;
|
|
array_pop($pattern);
|
|
|
|
$this->searchTable[$method][$groupNumber][] = $route;
|
|
}
|
|
|
|
$this->routes[$id] = $route;
|
|
}
|
|
}
|