Files
kiri-router/src/RouterCollector.php
T

246 lines
4.9 KiB
PHP
Raw Normal View History

2023-04-15 23:29:27 +08:00
<?php
2023-04-15 23:31:16 +08:00
namespace Kiri\Router;
2023-04-15 23:29:27 +08:00
use Closure;
use Exception;
use Kiri;
2023-04-15 23:31:16 +08:00
use Kiri\Router\Base\NotFoundController;
2023-04-15 23:29:27 +08:00
use ReflectionException;
use Throwable;
use Traversable;
2023-04-15 23:31:16 +08:00
use Kiri\Router\Base\Middleware;
use Kiri\Core\HashMap;
2023-04-15 23:29:27 +08:00
use Kiri\Annotation\Route\RequestMethod;
/**
*
*/
class RouterCollector implements \ArrayAccess, \IteratorAggregate
{
private array $_item = [];
public array $groupTack = [];
/**
2023-04-15 23:31:16 +08:00
* @var HashMap
2023-04-15 23:29:27 +08:00
*/
2023-04-15 23:31:16 +08:00
private HashMap $methods;
2023-04-15 23:29:27 +08:00
public function __construct()
{
2023-04-15 23:31:16 +08:00
$this->methods = new HashMap();
2023-04-15 23:29:27 +08:00
}
/**
* @return Traversable
*/
public function getIterator(): Traversable
{
return new \ArrayIterator($this->_item);
}
/**
* @param RequestMethod[] $method
* @param string $route
2023-04-15 23:31:16 +08:00
* @param string|Closure $closure
2023-04-15 23:29:27 +08:00
* @throws
*/
2023-04-15 23:31:16 +08:00
public function addRoute(array $method, string $route, string|Closure $closure)
2023-04-15 23:29:27 +08:00
{
try {
$route = $this->_splicing_routing($route);
2023-04-15 23:31:16 +08:00
$interpreter = Kiri::getDi()->get(ControllerInterpreter::class);
2023-04-15 23:29:27 +08:00
if ($closure instanceof Closure) {
2023-04-15 23:31:16 +08:00
$handler = $interpreter->addRouteByClosure($closure);
} else {
$handler = $this->resolve($closure, $interpreter);
2023-04-15 23:29:27 +08:00
}
foreach ($method as $value) {
2023-04-15 23:31:16 +08:00
if ($value instanceof RequestMethod) {
$value = $value->getString();
}
$this->register($route, $value, $handler);
2023-04-15 23:29:27 +08:00
}
} catch (Throwable $throwable) {
2023-04-15 23:31:16 +08:00
error($throwable->getMessage(), [throwable($throwable)]);
2023-04-15 23:29:27 +08:00
}
}
/**
2023-04-15 23:31:16 +08:00
* @param string $closure
* @param ControllerInterpreter $interpreter
* @return Handler
2023-04-15 23:29:27 +08:00
* @throws ReflectionException
*/
2023-04-15 23:31:16 +08:00
private function resolve(string $closure, ControllerInterpreter $interpreter): Handler
2023-04-15 23:29:27 +08:00
{
2023-04-15 23:31:16 +08:00
[$className, $method] = explode('@', $closure);
2023-04-15 23:29:27 +08:00
2023-04-15 23:31:16 +08:00
$class = Kiri::getDi()->get($this->resetName($className));
2023-04-15 23:29:27 +08:00
2023-04-15 23:31:16 +08:00
return $interpreter->addRouteByString($class, $method);
2023-04-15 23:29:27 +08:00
}
/**
2023-04-15 23:31:16 +08:00
* @param string $className
* @return string
2023-04-15 23:29:27 +08:00
*/
2023-04-15 23:31:16 +08:00
private function resetName(string $className): string
2023-04-15 23:29:27 +08:00
{
2023-04-15 23:31:16 +08:00
$namespace = array_filter(array_column($this->groupTack, 'namespace'));
if (count($namespace) < 1) {
return $className;
2023-04-15 23:29:27 +08:00
}
2023-04-15 23:31:16 +08:00
return implode('\\', $namespace) . '\\' . $className;
2023-04-15 23:29:27 +08:00
}
/**
* @param string $path
2023-04-15 23:31:16 +08:00
* @param string $method
* @param Handler $handler
* @return void
2023-04-15 23:29:27 +08:00
* @throws ReflectionException
*/
2023-04-15 23:31:16 +08:00
public function register(string $path, string $method, Handler $handler): void
2023-04-15 23:29:27 +08:00
{
2023-04-15 23:31:16 +08:00
$hashMap = HashMap::Tree($this->methods, $method);
foreach (str_split($path, 4) as $item) {
if ($hashMap->has($item)) {
$hashMap = $hashMap->get($item);
} else {
$hashMap = new HashMap();
$hashMap->put($item, $hashMap);
2023-04-15 23:29:27 +08:00
}
}
2023-04-15 23:31:16 +08:00
$hashMap->put('handler', $handler);
$this->registerMiddleware($path);
2023-04-15 23:29:27 +08:00
}
/**
2023-04-15 23:31:16 +08:00
* @param string $path
2023-04-15 23:29:27 +08:00
* @return void
* @throws ReflectionException
* @throws Exception
*/
2023-04-15 23:31:16 +08:00
public function registerMiddleware(string $path): void
2023-04-15 23:29:27 +08:00
{
2023-04-15 23:31:16 +08:00
$middlewares = array_column($this->groupTack, 'middleware');
if (count($middlewares) > 0) {
$manager = Kiri::getDi()->get(Middleware::class);
foreach ($middlewares as $middleware) {
if (is_string($middleware)) {
$middleware = [$middleware];
2023-04-15 23:29:27 +08:00
}
2023-04-15 23:31:16 +08:00
foreach ($middleware as $value) {
$manager->addPathMiddleware($path, $value);
2023-04-15 23:29:27 +08:00
}
}
}
}
/**
* @param string $path
* @param string $method
2023-04-15 23:31:16 +08:00
* @return Handler|null
2023-04-15 23:29:27 +08:00
*/
2023-04-15 23:31:16 +08:00
public function query(string $path, string $method): ?Handler
2023-04-15 23:29:27 +08:00
{
2023-04-15 23:31:16 +08:00
if (!$this->methods->has($method)) {
return $this->NotFundHandler($path);
}
$parent = $this->methods->get($method);
foreach (str_split($path, 4) as $item) {
$parent = $parent->get($item);
if ($parent === null) {
return $this->NotFundHandler($path);
}
2023-04-15 23:29:27 +08:00
}
2023-04-15 23:31:16 +08:00
return $parent->get('handler');
2023-04-15 23:29:27 +08:00
}
/**
2023-04-15 23:31:16 +08:00
* @param string $path
* @return Handler
2023-04-15 23:29:27 +08:00
*/
2023-04-15 23:31:16 +08:00
private function NotFundHandler(string $path): Handler
2023-04-15 23:29:27 +08:00
{
2023-04-15 23:31:16 +08:00
return new Handler([NotFoundController::class, 'fail'], []);
2023-04-15 23:29:27 +08:00
}
/**
2023-04-15 23:31:16 +08:00
* @param string $route
* @return string
2023-04-15 23:29:27 +08:00
*/
2023-04-15 23:31:16 +08:00
protected function _splicing_routing(string $route): string
2023-04-15 23:29:27 +08:00
{
2023-04-15 23:31:16 +08:00
$route = ltrim($route, '/');
$prefix = array_column($this->groupTack, 'prefix');
if (empty($prefix = array_filter($prefix))) {
return '/' . $route;
2023-04-15 23:29:27 +08:00
}
2023-04-15 23:31:16 +08:00
return '/' . implode('/', $prefix) . '/' . $route;
2023-04-15 23:29:27 +08:00
}
/**
* @param mixed $offset
* @return bool
*/
public function offsetExists(mixed $offset): bool
{
// TODO: Implement offsetExists() method.
return isset($this->_item[$offset]);
}
/**
* @param mixed $offset
* @return Router|null
*/
public function offsetGet(mixed $offset): ?Router
{
if ($this->offsetExists($offset)) {
return $this->_item[$offset];
}
return null;
}
/**
* @param mixed $offset
* @param mixed $value
* @return void
*/
public function offsetSet(mixed $offset, mixed $value): void
{
// TODO: Implement offsetSet() method.
$this->_item[$offset] = $value;
}
/**
* @param mixed $offset
* @return void
*/
public function offsetUnset(mixed $offset): void
{
unset($this->_item[$offset]);
}
}