eee
This commit is contained in:
@@ -25,4 +25,21 @@ class DataGrip
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function reset(?string $type = null): void
|
||||||
|
{
|
||||||
|
if ($type === null) {
|
||||||
|
foreach ($this->servers as $server) {
|
||||||
|
if ($server instanceof RouterCollector) {
|
||||||
|
$server->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->servers[$type])) {
|
||||||
|
$this->servers[$type]->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ class Handler implements RequestHandlerInterface
|
|||||||
*/
|
*/
|
||||||
protected array $middlewares = [];
|
protected array $middlewares = [];
|
||||||
|
|
||||||
|
protected ?string $sourceFile = null;
|
||||||
|
|
||||||
|
protected string $sourceKind = 'attribute';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|Closure $handler
|
* @param array|Closure $handler
|
||||||
* @param array $parameters
|
* @param array $parameters
|
||||||
@@ -124,6 +128,30 @@ class Handler implements RequestHandlerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function setSourceFile(?string $sourceFile): void
|
||||||
|
{
|
||||||
|
$this->sourceFile = $sourceFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getSourceFile(): ?string
|
||||||
|
{
|
||||||
|
return $this->sourceFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function setSourceKind(string $sourceKind): void
|
||||||
|
{
|
||||||
|
$this->sourceKind = $sourceKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getSourceKind(): string
|
||||||
|
{
|
||||||
|
return $this->sourceKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServerRequestInterface $request
|
* @param ServerRequestInterface $request
|
||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ class OnRequest implements OnRequestInterface
|
|||||||
public RouterCollector $router;
|
public RouterCollector $router;
|
||||||
|
|
||||||
|
|
||||||
|
public DataGrip $dataGrip;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ExceptionHandlerInterface
|
* @var ExceptionHandlerInterface
|
||||||
*/
|
*/
|
||||||
@@ -59,6 +62,7 @@ class OnRequest implements OnRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function __construct(public ResponseInterface $response, DataGrip $dataGrip)
|
public function __construct(public ResponseInterface $response, DataGrip $dataGrip)
|
||||||
{
|
{
|
||||||
|
$this->dataGrip = $dataGrip;
|
||||||
$this->responseEmitter = $this->response->emmit;
|
$this->responseEmitter = $this->response->emmit;
|
||||||
$exception = \config('servers.request.exception');
|
$exception = \config('servers.request.exception');
|
||||||
if (!in_array(ExceptionHandlerInterface::class, class_implements($exception))) {
|
if (!in_array(ExceptionHandlerInterface::class, class_implements($exception))) {
|
||||||
@@ -82,6 +86,7 @@ class OnRequest implements OnRequestInterface
|
|||||||
/** @var CQ $PsrRequest */
|
/** @var CQ $PsrRequest */
|
||||||
Context::set(ResponseInterface::class, new ConstrictResponse($this->response->contentType));
|
Context::set(ResponseInterface::class, new ConstrictResponse($this->response->contentType));
|
||||||
$PsrRequest = Context::set(RequestInterface::class, CQ::builder($request));
|
$PsrRequest = Context::set(RequestInterface::class, CQ::builder($request));
|
||||||
|
$this->router = $this->dataGrip->get(ROUTER_TYPE_HTTP);
|
||||||
|
|
||||||
CoordinatorManager::utility(Coordinator::WORKER_START)->yield();
|
CoordinatorManager::utility(Coordinator::WORKER_START)->yield();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Kiri\Router;
|
||||||
|
|
||||||
|
class RouteArtifactState
|
||||||
|
{
|
||||||
|
public function store(string $type, array $artifact): void
|
||||||
|
{
|
||||||
|
$payload = [
|
||||||
|
'timestamp' => time(),
|
||||||
|
'type' => $type,
|
||||||
|
'artifact' => $artifact,
|
||||||
|
];
|
||||||
|
|
||||||
|
$directory = dirname($this->getFilePath($type));
|
||||||
|
if (!is_dir($directory)) {
|
||||||
|
mkdir($directory, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($this->getFilePath($type), json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load(string $type): array
|
||||||
|
{
|
||||||
|
$file = $this->getFilePath($type);
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode((string)file_get_contents($file), true);
|
||||||
|
if (!is_array($data)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_array($data['artifact'] ?? null) ? $data['artifact'] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $type): bool
|
||||||
|
{
|
||||||
|
return file_exists($this->getFilePath($type));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFilePath(string $type): string
|
||||||
|
{
|
||||||
|
$basePath = realpath($_SERVER['PWD'] ?? APP_PATH ?? getcwd()) ?: ($_SERVER['PWD'] ?? APP_PATH ?? getcwd());
|
||||||
|
$basePath = str_replace('\\', '/', $basePath);
|
||||||
|
$runtimePath = defined('APP_PATH')
|
||||||
|
? rtrim(str_replace('\\', '/', APP_PATH), '/') . '/storage/.kiri-route-artifacts/'
|
||||||
|
: sys_get_temp_dir() . '/kiri-route-artifacts/';
|
||||||
|
|
||||||
|
return $runtimePath . md5($basePath . '::' . $type) . '.json';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Kiri\Router;
|
||||||
|
|
||||||
|
class RouteEntry
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public readonly string $requestMethod,
|
||||||
|
public readonly string $path,
|
||||||
|
public readonly string $class,
|
||||||
|
public readonly string $method,
|
||||||
|
public readonly array $middlewares = [],
|
||||||
|
public readonly ?string $sourceFile = null,
|
||||||
|
public readonly string $sourceKind = 'attribute',
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+59
-17
@@ -4,10 +4,12 @@ declare(strict_types=1);
|
|||||||
namespace Kiri\Router;
|
namespace Kiri\Router;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Kiri\Di\HotReloadState;
|
||||||
use Kiri\Server\Events\OnWorkerStart;
|
use Kiri\Server\Events\OnWorkerStart;
|
||||||
use Kiri;
|
use Kiri;
|
||||||
use Kiri\Abstracts\CoordinatorManager;
|
use Kiri\Abstracts\CoordinatorManager;
|
||||||
use Kiri\Coordinator;
|
use Kiri\Coordinator;
|
||||||
|
use Kiri\Router\RouteArtifactState;
|
||||||
use Kiri\Router\Validator\ValidatorMiddleware;
|
use Kiri\Router\Validator\ValidatorMiddleware;
|
||||||
use Kiri\Router\Base\Middleware as MiddlewareManager;
|
use Kiri\Router\Base\Middleware as MiddlewareManager;
|
||||||
use Kiri\Router\Constrict\RequestMethod;
|
use Kiri\Router\Constrict\RequestMethod;
|
||||||
@@ -35,6 +37,8 @@ class Router
|
|||||||
*/
|
*/
|
||||||
private static string $type = ROUTER_TYPE_HTTP;
|
private static string $type = ROUTER_TYPE_HTTP;
|
||||||
|
|
||||||
|
private static ?string $currentSourceFile = null;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
@@ -187,13 +191,53 @@ class Router
|
|||||||
public function scan_build_route(): void
|
public function scan_build_route(): void
|
||||||
{
|
{
|
||||||
$coordinator = CoordinatorManager::utility(Coordinator::WORKER_START);
|
$coordinator = CoordinatorManager::utility(Coordinator::WORKER_START);
|
||||||
|
|
||||||
$this->read_dir_file(APP_PATH . 'routes');
|
|
||||||
|
|
||||||
$container = Kiri::getDi();
|
$container = Kiri::getDi();
|
||||||
|
$container->get(DataGrip::class)->reset(static::$type);
|
||||||
$scanner = $container->get(Kiri\Di\Scanner::class);
|
$scanner = $container->get(Kiri\Di\Scanner::class);
|
||||||
$scanner->scan(APP_PATH . 'app/');
|
$artifactState = $container->get(RouteArtifactState::class);
|
||||||
|
$scanConfig = array_merge(
|
||||||
|
config('servers.reload.scan', []),
|
||||||
|
config('site.scanner', [])
|
||||||
|
);
|
||||||
|
$scanner->setConfig($scanConfig);
|
||||||
|
|
||||||
|
$changedFiles = $container->get(HotReloadState::class)->consume();
|
||||||
|
$normalizedAppPath = str_replace('\\', '/', APP_PATH . 'app');
|
||||||
|
$normalizedRoutePath = str_replace('\\', '/', APP_PATH . 'routes');
|
||||||
|
$routeChanged = false;
|
||||||
|
$appChangedFiles = [];
|
||||||
|
|
||||||
|
foreach ($changedFiles as $changedFile) {
|
||||||
|
if (str_starts_with($changedFile, $normalizedRoutePath . '/')) {
|
||||||
|
$routeChanged = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($changedFile, $normalizedAppPath . '/')) {
|
||||||
|
$appChangedFiles[] = $changedFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$usedArtifact = false;
|
||||||
|
if (($scanConfig['cache_enabled'] ?? false) && !$routeChanged && $artifactState->has(static::$type)) {
|
||||||
|
$artifact = $artifactState->load(static::$type);
|
||||||
|
$router = $container->get(DataGrip::class)->get(static::$type);
|
||||||
|
$usedArtifact = $router->importArtifact($artifact, $appChangedFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$usedArtifact) {
|
||||||
|
$this->read_dir_file(APP_PATH . 'routes');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$routeChanged && !empty($appChangedFiles) && ($scanConfig['cache_enabled'] ?? false)) {
|
||||||
|
$scanner->scanFiles($appChangedFiles, APP_PATH . 'app/', null, !$usedArtifact);
|
||||||
|
} elseif (!$usedArtifact) {
|
||||||
|
$scanner->scan(APP_PATH . 'app/');
|
||||||
|
} else {
|
||||||
|
$scanner->scanFiles([], APP_PATH . 'app/', null, false);
|
||||||
|
}
|
||||||
$this->reset($container);
|
$this->reset($container);
|
||||||
|
$artifactState->store(static::$type, $container->get(DataGrip::class)->get(static::$type)->exportArtifact());
|
||||||
|
|
||||||
$coordinator->done();
|
$coordinator->done();
|
||||||
}
|
}
|
||||||
@@ -208,19 +252,8 @@ class Router
|
|||||||
public function reset(ContainerInterface $container): void
|
public function reset(ContainerInterface $container): void
|
||||||
{
|
{
|
||||||
$router = $container->get(DataGrip::class)->get(static::$type);
|
$router = $container->get(DataGrip::class)->get(static::$type);
|
||||||
foreach ($router->getMethods() as $name => $method) {
|
if ((bool)config('servers.reload.scan.prebuild_http_handlers', false)) {
|
||||||
$middlewares = $method->getMiddlewares();
|
$router->warmHttpHandlers();
|
||||||
|
|
||||||
foreach ($middlewares as $key => $middleware) {
|
|
||||||
$middlewares[$key] = di($middleware);
|
|
||||||
}
|
|
||||||
|
|
||||||
$requestHandler = new HttpRequestHandler($middlewares, $method);
|
|
||||||
$validator = MiddlewareManager::getValidator($method->getClass(), $method->getMethod());
|
|
||||||
if (!is_null($validator)) {
|
|
||||||
$requestHandler->withValidatorMiddleware(new ValidatorMiddleware(di(ResponseInterface::class), $method->getClass(), $method->getMethod()));
|
|
||||||
}
|
|
||||||
$router->setHttpHandler($name, $requestHandler);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,10 +286,19 @@ class Router
|
|||||||
private function resolve_file($files): void
|
private function resolve_file($files): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
static::$currentSourceFile = str_replace('\\', '/', realpath($files) ?: $files);
|
||||||
include "$files";
|
include "$files";
|
||||||
} catch (\Throwable $throwable) {
|
} catch (\Throwable $throwable) {
|
||||||
\Kiri::getLogger()->json_log($throwable);
|
\Kiri::getLogger()->json_log($throwable);
|
||||||
|
} finally {
|
||||||
|
static::$currentSourceFile = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function getCurrentSourceFile(): ?string
|
||||||
|
{
|
||||||
|
return static::$currentSourceFile;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+163
-5
@@ -14,6 +14,7 @@ use Throwable;
|
|||||||
use Traversable;
|
use Traversable;
|
||||||
use Kiri\Router\Base\Middleware;
|
use Kiri\Router\Base\Middleware;
|
||||||
use Kiri\Router\Format\ResponseFormat;
|
use Kiri\Router\Format\ResponseFormat;
|
||||||
|
use Kiri\Router\Validator\ValidatorMiddleware;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +43,7 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<string, Handler>
|
* @var array<string, Handler|RouteEntry>
|
||||||
*/
|
*/
|
||||||
private array $methods = [];
|
private array $methods = [];
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Handler[]
|
* @return array<string, Handler|RouteEntry>
|
||||||
*/
|
*/
|
||||||
public function getMethods(): array
|
public function getMethods(): array
|
||||||
{
|
{
|
||||||
@@ -77,6 +78,16 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function clear(): void
|
||||||
|
{
|
||||||
|
$this->_item = [];
|
||||||
|
$this->dump = [];
|
||||||
|
$this->groupTack = [];
|
||||||
|
$this->methods = [];
|
||||||
|
$this->httpHandler = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $method
|
* @param string $method
|
||||||
* @param HttpRequestHandler $handler
|
* @param HttpRequestHandler $handler
|
||||||
@@ -171,14 +182,26 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
if (is_string($closure[0])) {
|
if (is_string($closure[0])) {
|
||||||
$closure[0] = $container->get($closure[0]);
|
$closure[0] = $container->get($closure[0]);
|
||||||
}
|
}
|
||||||
return $interpreter->addRouteByString(... $closure);
|
$handler = $interpreter->addRouteByString(... $closure);
|
||||||
|
$sourceFile = Router::getCurrentSourceFile();
|
||||||
|
if ($sourceFile !== null) {
|
||||||
|
$handler->setSourceFile($sourceFile);
|
||||||
|
$handler->setSourceKind('route_file');
|
||||||
|
}
|
||||||
|
return $handler;
|
||||||
}
|
}
|
||||||
if (!str_contains($closure, '@')) {
|
if (!str_contains($closure, '@')) {
|
||||||
$closure .= '@';
|
$closure .= '@';
|
||||||
}
|
}
|
||||||
[$className, $method] = explode('@', $closure);
|
[$className, $method] = explode('@', $closure);
|
||||||
$class = $container->get($this->resetName($className));
|
$class = $container->get($this->resetName($className));
|
||||||
return $interpreter->addRouteByString($class, $method);
|
$handler = $interpreter->addRouteByString($class, $method);
|
||||||
|
$sourceFile = Router::getCurrentSourceFile();
|
||||||
|
if ($sourceFile !== null) {
|
||||||
|
$handler->setSourceFile($sourceFile);
|
||||||
|
$handler->setSourceKind('route_file');
|
||||||
|
}
|
||||||
|
return $handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -205,11 +228,99 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
*/
|
*/
|
||||||
public function register(string $path, string $method, Handler $handler): void
|
public function register(string $path, string $method, Handler $handler): void
|
||||||
{
|
{
|
||||||
|
if ($handler->getSourceFile() === null && $handler->getClass() !== null) {
|
||||||
|
$reflect = \Kiri::getDi()->getReflectionClass($handler->getClass());
|
||||||
|
$handler->setSourceFile($this->normalizePath((string)$reflect->getFileName()));
|
||||||
|
$handler->setSourceKind('attribute');
|
||||||
|
}
|
||||||
|
|
||||||
$this->methods[$method . '_' . $path] = $handler;
|
$this->methods[$method . '_' . $path] = $handler;
|
||||||
$handler->setMiddlewares($this->registerMiddleware($handler->getClass(), $handler->getMethod()));
|
$handler->setMiddlewares($this->registerMiddleware($handler->getClass(), $handler->getMethod()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function exportArtifact(): array
|
||||||
|
{
|
||||||
|
$entries = [];
|
||||||
|
$hasClosureRoutes = false;
|
||||||
|
|
||||||
|
foreach ($this->methods as $methodPath => $handler) {
|
||||||
|
if ($handler instanceof Handler && $handler->isClosure()) {
|
||||||
|
$hasClosureRoutes = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$requestMethod, $path] = explode('_', $methodPath, 2);
|
||||||
|
$class = $handler instanceof Handler ? $handler->getClass() : $handler->class;
|
||||||
|
$method = $handler instanceof Handler ? $handler->getMethod() : $handler->method;
|
||||||
|
$middlewares = $handler instanceof Handler ? $handler->getMiddlewares() : $handler->middlewares;
|
||||||
|
$sourceFile = $handler instanceof Handler ? $handler->getSourceFile() : $handler->sourceFile;
|
||||||
|
$sourceKind = $handler instanceof Handler ? $handler->getSourceKind() : $handler->sourceKind;
|
||||||
|
|
||||||
|
$entries[] = [
|
||||||
|
'request_method' => $requestMethod,
|
||||||
|
'path' => $path,
|
||||||
|
'class' => $class,
|
||||||
|
'method' => $method,
|
||||||
|
'middlewares' => $middlewares,
|
||||||
|
'source_file' => $sourceFile,
|
||||||
|
'source_kind' => $sourceKind,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'has_closure_routes' => $hasClosureRoutes,
|
||||||
|
'entries' => $entries,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function importArtifact(array $artifact, array $excludeSourceFiles = []): bool
|
||||||
|
{
|
||||||
|
if (($artifact['has_closure_routes'] ?? false) === true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries = $artifact['entries'] ?? null;
|
||||||
|
if (!is_array($entries)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$exclude = array_fill_keys(array_map([$this, 'normalizePath'], $excludeSourceFiles), true);
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
if (!is_array($entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceFile = $entry['source_file'] ?? null;
|
||||||
|
if (is_string($sourceFile) && isset($exclude[$this->normalizePath($sourceFile)])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$class = $entry['class'] ?? null;
|
||||||
|
$method = $entry['method'] ?? null;
|
||||||
|
$requestMethod = $entry['request_method'] ?? null;
|
||||||
|
$path = $entry['path'] ?? null;
|
||||||
|
|
||||||
|
if (!is_string($class) || !is_string($method) || !is_string($requestMethod) || !is_string($path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->methods[$requestMethod . '_' . $path] = new RouteEntry(
|
||||||
|
requestMethod: $requestMethod,
|
||||||
|
path: $path,
|
||||||
|
class: $class,
|
||||||
|
method: $method,
|
||||||
|
middlewares: is_array($entry['middlewares'] ?? null) ? $entry['middlewares'] : [],
|
||||||
|
sourceFile: is_string($sourceFile) ? $this->normalizePath($sourceFile) : null,
|
||||||
|
sourceKind: is_string($entry['source_kind'] ?? null) ? $entry['source_kind'] : 'attribute',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $class
|
* @param string $class
|
||||||
* @param string $method
|
* @param string $method
|
||||||
@@ -289,7 +400,12 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
*/
|
*/
|
||||||
public function query(string $path, string $method): HttpRequestHandler
|
public function query(string $path, string $method): HttpRequestHandler
|
||||||
{
|
{
|
||||||
return $this->httpHandler[$method . '_' . $path] ?? $this->not_found_handler();
|
$key = $method . '_' . $path;
|
||||||
|
if (!isset($this->httpHandler[$key]) && isset($this->methods[$key])) {
|
||||||
|
$this->httpHandler[$key] = $this->compileHandler($this->methods[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->httpHandler[$key] ?? $this->not_found_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -309,6 +425,14 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function warmHttpHandlers(): void
|
||||||
|
{
|
||||||
|
foreach ($this->methods as $name => $method) {
|
||||||
|
$this->httpHandler[$name] = $this->compileHandler($method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $route
|
* @param string $route
|
||||||
* @return string
|
* @return string
|
||||||
@@ -324,6 +448,40 @@ class RouterCollector implements \ArrayAccess, \IteratorAggregate
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function normalizePath(string $path): string
|
||||||
|
{
|
||||||
|
$resolved = realpath($path) ?: $path;
|
||||||
|
return str_replace('\\', '/', $resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function compileHandler(Handler|RouteEntry $method): HttpRequestHandler
|
||||||
|
{
|
||||||
|
if ($method instanceof RouteEntry) {
|
||||||
|
$controller = \Kiri::getDi()->get($method->class);
|
||||||
|
$handler = di(ControllerInterpreter::class)->addRouteByString($controller, $method->method);
|
||||||
|
$handler->setRequestMethod($method->requestMethod);
|
||||||
|
$handler->setMiddlewares($method->middlewares);
|
||||||
|
$handler->setSourceFile($method->sourceFile);
|
||||||
|
$handler->setSourceKind($method->sourceKind);
|
||||||
|
$method = $handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
$middlewares = $method->getMiddlewares();
|
||||||
|
foreach ($middlewares as $key => $middleware) {
|
||||||
|
$middlewares[$key] = di($middleware);
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestHandler = new HttpRequestHandler($middlewares, $method);
|
||||||
|
$validator = Middleware::getValidator($method->getClass(), $method->getMethod());
|
||||||
|
if ($validator !== null) {
|
||||||
|
$requestHandler->withValidatorMiddleware(new ValidatorMiddleware(di(\Psr\Http\Message\ResponseInterface::class), $method->getClass(), $method->getMethod()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requestHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed $offset
|
* @param mixed $offset
|
||||||
* @return bool
|
* @return bool
|
||||||
|
|||||||
Reference in New Issue
Block a user