index/src/Routing/RouteInfo.php
2023-09-11 20:34:16 +00:00

110 lines
2.8 KiB
PHP

<?php
// RouteInfo.php
// Created: 2022-01-20
// Updated: 2023-09-11
namespace Index\Routing;
use InvalidArgumentException;
use UnexpectedValueException;
/**
* Represents a node in the router structure.
*
* @internal
*/
class RouteInfo {
private array $children = [];
private array $methods = [];
private array $middlewares = [];
private ?RouteInfo $dynamicChild = null;
private function getChild(string $path, ?string &$next = null): RouteInfo {
$parts = explode('/', $path, 2);
$name = '_' . $parts[0];
if(str_starts_with($parts[0], ':'))
$child = $this->dynamicChild ?? ($this->dynamicChild = new RouteInfo);
else
$child = $this->children[$name] ?? ($this->children[$name] = new RouteInfo);
$next = $parts[1] ?? '';
return $child;
}
/**
* @internal
*/
public function addMiddleware(string $path, callable $handler): void {
if($path === '') {
$this->middlewares[] = $handler;
return;
}
$this->getChild($path, $next)->addMiddleware($next, $handler);
}
/**
* @internal
*/
public function addMethod(string $method, string $path, callable $handler): void {
if($path === '') {
$this->methods[strtolower($method)] = $handler;
return;
}
$this->getChild($path, $next)->addMethod($method, $next, $handler);
}
/**
* @internal
*/
public function resolve(string $method, string $path, array $args = [], array $callables = []): RouteCallable {
if($path === '') {
$method = strtolower($method);
$handlers = [];
if(isset($this->methods[$method])) {
$handlers[] = $this->methods[$method];
} else {
if($method !== 'options') {
if(empty($this->methods))
throw new RoutePathNotFoundException;
throw new RouteMethodNotSupportedException;
}
}
return new RouteCallable(
array_merge($callables, $this->middlewares, $handlers),
$args
);
}
$parts = explode('/', $path, 2);
$name = $parts[0];
$mName = '_' . $name;
foreach($this->children as $cName => $cObj)
if($cName === $mName) {
$child = $cObj;
break;
}
if(!isset($child)) {
$args[] = $name;
$child = $this->dynamicChild;
}
if($child === null)
throw new RoutePathNotFoundException;
return $child->resolve(
$method,
$parts[1] ?? '',
$args,
array_merge($callables, $this->middlewares)
);
}
}