From 7d391843b5feb735a40d1092c1e9eb6cb54837a6 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:22:24 +0400 Subject: [PATCH 1/2] [#462] Normalize router helper surface through Request proxies Move router metadata access behind Request proxy methods, migrate core internal usages from router helpers to request()-> methods, and remove dead helper functions while keeping public helper wrappers for DX compatibility. Made-with: Cursor --- src/App/Adapters/WebAppAdapter.php | 2 +- src/App/Helpers/misc.php | 25 ----- src/Console/Commands/OpenApiCommand.php | 4 +- src/Http/Request.php | 2 +- src/Http/Traits/Request/Route.php | 126 ++++++++++++++++++++++++ src/Lang/Factories/LangFactory.php | 2 +- src/Lang/Translator.php | 2 +- src/Loader/Setup.php | 2 +- src/Middleware/MiddlewareManager.php | 7 +- src/Module/ModuleManager.php | 8 +- src/Paginator/Traits/PaginatorTrait.php | 2 +- src/Renderer/Adapters/HtmlAdapter.php | 2 +- src/Renderer/Adapters/TwigAdapter.php | 2 +- src/ResourceCache/ViewCache.php | 2 +- src/Router/Helpers/router.php | 88 +++-------------- src/Router/RouteBuilder.php | 17 ++-- src/View/View.php | 13 +-- tests/Unit/Http/RequestTest.php | 50 ++++++++++ 18 files changed, 225 insertions(+), 131 deletions(-) diff --git a/src/App/Adapters/WebAppAdapter.php b/src/App/Adapters/WebAppAdapter.php index a8c54af23..6a08a0b18 100644 --- a/src/App/Adapters/WebAppAdapter.php +++ b/src/App/Adapters/WebAppAdapter.php @@ -84,7 +84,7 @@ public function start(): ?int [$request, $response] = (new MiddlewareManager($matchedRoute))->applyMiddlewares(request(), response()); - if ($this->setupViewCache()->serveCachedView(route_uri() ?? '', $response)) { + if ($this->setupViewCache()->serveCachedView(request()->getUri() ?? '', $response)) { stop(); } diff --git a/src/App/Helpers/misc.php b/src/App/Helpers/misc.php index 7a90f487a..9cf63e53b 100644 --- a/src/App/Helpers/misc.php +++ b/src/App/Helpers/misc.php @@ -82,31 +82,6 @@ function is_debug_mode(): bool return filter_var(config()->get('app.debug'), FILTER_VALIDATE_BOOLEAN); } -/** - * Gets the caller class - */ -function get_caller_class(int $index = 2): ?string -{ - $caller = debug_backtrace(); - $caller = $caller[$index]; - - return $caller['class'] ?? null; -} - -/** - * Gets the caller function - */ -function get_caller_function(int $index = 2): ?string -{ - $trace = debug_backtrace(); - - if (!isset($trace[$index])) { - return null; - } - - return $trace[$index]['function']; -} - /** * Exports the variable * @param mixed $var diff --git a/src/Console/Commands/OpenApiCommand.php b/src/Console/Commands/OpenApiCommand.php index 856fb3e42..e8dc1c417 100644 --- a/src/Console/Commands/OpenApiCommand.php +++ b/src/Console/Commands/OpenApiCommand.php @@ -124,12 +124,12 @@ public function exec(): void return; } - if (route_group_exists('openapi', $module) && $this->fs->exists($modulePath . DS . 'resources' . DS . 'openApi' . DS . 'spec.json')) { + if (request()->routeGroupExists('openapi', $module) && $this->fs->exists($modulePath . DS . 'resources' . DS . 'openApi' . DS . 'spec.json')) { $this->error('The Open API specifications already installed for `' . ucfirst($module) . '` module'); return; } - if (!route_group_exists('openapi', $module)) { + if (!request()->routeGroupExists('openapi', $module)) { $routeContent = $this->fs->get($routes); if ($routeContent !== false) { diff --git a/src/Http/Request.php b/src/Http/Request.php index daa4e6b4d..c32a2d75f 100644 --- a/src/Http/Request.php +++ b/src/Http/Request.php @@ -193,7 +193,7 @@ public function getBaseUrl(bool $withModulePrefix = false): string { $baseUrl = config()->get('app.base_url'); - $prefix = route_prefix(); + $prefix = $this->getRoutePrefix(); $modulePrefix = ($withModulePrefix && !in_array($prefix, [null, '', '0'], true)) ? '/' . $prefix : ''; if ($baseUrl) { diff --git a/src/Http/Traits/Request/Route.php b/src/Http/Traits/Request/Route.php index 413b83ff5..f6cacedf9 100644 --- a/src/Http/Traits/Request/Route.php +++ b/src/Http/Traits/Request/Route.php @@ -16,7 +16,11 @@ namespace Quantum\Http\Traits\Request; +use Quantum\Router\Route as RouterRoute; +use Quantum\Router\RouteCollection; use Quantum\Router\MatchedRoute; +use Quantum\Di\Di; +use Closure; /** * Trait Route @@ -36,4 +40,126 @@ public function getMatchedRoute(): ?MatchedRoute return $this->route; } + /** + * @return array|null + */ + public function getCurrentMiddlewares(): ?array + { + return $this->route ? $this->route->getRoute()->getMiddlewares() : null; + } + + public function getCurrentModule(): ?string + { + return $this->route ? $this->route->getRoute()->getModule() : null; + } + + public function getCurrentController(): ?string + { + return $this->route ? $this->route->getRoute()->getController() : null; + } + + public function getCurrentAction(): ?string + { + return $this->route ? $this->route->getRoute()->getAction() : null; + } + + public function getRouteCallback(): ?Closure + { + return $this->route ? $this->route->getRoute()->getClosure() : null; + } + + public function getCurrentRoutePattern(): ?string + { + return $this->route ? $this->route->getRoute()->getPattern() : null; + } + + public function getCompiledRoutePattern(): string + { + return $this->route ? ($this->route->getRoute()->getCompiledPattern() ?? '') : ''; + } + + /** + * @return array + */ + public function getRouteParams(): array + { + return $this->route ? $this->route->getParams() : []; + } + + /** + * @return mixed|null + */ + public function getRouteParam(string $name) + { + $params = $this->getRouteParams(); + + return $params[$name] ?? null; + } + + /** + * @return array|null + */ + public function getRouteCacheSettings(): ?array + { + return $this->route ? $this->route->getRoute()->getCache() : null; + } + + public function getRouteName(): ?string + { + return $this->route ? $this->route->getRoute()->getName() : null; + } + + public function getRoutePrefix(): ?string + { + return $this->route ? $this->route->getRoute()->getPrefix() : null; + } + + public function findRouteByName(string $name, string $module): ?RouterRoute + { + if (!Di::isRegistered(RouteCollection::class)) { + return null; + } + + $collection = Di::get(RouteCollection::class); + + foreach ($collection->all() as $route) { + if ( + $route->getName() !== null && + strcasecmp($route->getName(), $name) === 0 && + strcasecmp((string) $route->getModule(), $module) === 0 + ) { + return $route; + } + } + + return null; + } + + public function routeGroupExists(string $name, string $module): bool + { + if (!Di::isRegistered(RouteCollection::class)) { + return false; + } + + $collection = Di::get(RouteCollection::class); + + foreach ($collection->all() as $route) { + if ( + $route->getGroup() !== null && + strcasecmp($route->getGroup(), $name) === 0 && + strcasecmp((string) $route->getModule(), $module) === 0 + ) { + return true; + } + } + + return false; + } + + public function getModuleBaseNamespace(): string + { + return environment()->isTesting() + ? 'Quantum\\Tests\\_root\\modules' + : 'Modules'; + } } diff --git a/src/Lang/Factories/LangFactory.php b/src/Lang/Factories/LangFactory.php index 7a4c0b7ea..9ecf74dc9 100644 --- a/src/Lang/Factories/LangFactory.php +++ b/src/Lang/Factories/LangFactory.php @@ -126,7 +126,7 @@ private function getLangFromUrlSegment(array $supported): ?string { $segmentIndex = (int) config()->get('lang.url_segment'); - if (!in_array(route_prefix(), [null, '', '0'], true) && $segmentIndex === 1) { + if (!in_array(request()->getRoutePrefix(), [null, '', '0'], true) && $segmentIndex === 1) { $segmentIndex++; } diff --git a/src/Lang/Translator.php b/src/Lang/Translator.php index be07408cd..e8f77cc3f 100644 --- a/src/Lang/Translator.php +++ b/src/Lang/Translator.php @@ -60,7 +60,7 @@ public function loadTranslations(): void $loaded = true; } - $moduleDir = modules_dir() . DS . current_module() . DS . 'resources' . DS . 'lang' . DS . $this->lang; + $moduleDir = modules_dir() . DS . request()->getCurrentModule() . DS . 'resources' . DS . 'lang' . DS . $this->lang; $moduleFiles = fs()->glob($moduleDir . DS . '*.php'); if (is_array($moduleFiles) && count($moduleFiles)) { diff --git a/src/Loader/Setup.php b/src/Loader/Setup.php index 1b8a76ac1..30bcc00ad 100644 --- a/src/Loader/Setup.php +++ b/src/Loader/Setup.php @@ -43,7 +43,7 @@ public function __construct(?string $pathPrefix = null, ?string $fileName = null $this->pathPrefix = $pathPrefix; $this->fileName = $fileName; $this->hierarchical = $hierarchical; - $this->module = $module ?: current_module(); + $this->module = $module ?: request()->getCurrentModule(); $this->exceptionMessage = $exceptionMessage ?: 'File `' . $pathPrefix . DS . $fileName . '` not found!'; } diff --git a/src/Middleware/MiddlewareManager.php b/src/Middleware/MiddlewareManager.php index 19e817771..a01d96376 100644 --- a/src/Middleware/MiddlewareManager.php +++ b/src/Middleware/MiddlewareManager.php @@ -21,6 +21,7 @@ use Quantum\Router\MatchedRoute; use Quantum\Http\Response; use Quantum\Http\Request; +use ReflectionException; /** * Class MiddlewareManager @@ -50,7 +51,7 @@ public function __construct(MatchedRoute $matchedRoute) /** * Apply Middlewares * @return array{0: Request, 1: Response} - * @throws MiddlewareException|BaseException + * @throws MiddlewareException|BaseException|ReflectionException */ public function applyMiddlewares(Request $request, Response $response): array { @@ -70,11 +71,11 @@ public function applyMiddlewares(Request $request, Response $response): array /** * Loads and gets the current middleware instance - * @throws MiddlewareException|BaseException + * @throws MiddlewareException|BaseException|ReflectionException */ private function getMiddleware(Request $request, Response $response): QtMiddleware { - $middlewareClass = module_base_namespace() . '\\' . $this->module . '\\Middlewares\\' . current($this->middlewares); + $middlewareClass = request()->getModuleBaseNamespace() . '\\' . $this->module . '\\Middlewares\\' . current($this->middlewares); if (!class_exists($middlewareClass)) { throw MiddlewareException::middlewareNotFound($middlewareClass); diff --git a/src/Module/ModuleManager.php b/src/Module/ModuleManager.php index df9fc92c0..e4a37eefa 100644 --- a/src/Module/ModuleManager.php +++ b/src/Module/ModuleManager.php @@ -181,6 +181,9 @@ private function copyDirectory(string $src, string $dst, bool $processTemplates, return $copiedFiles; } + /** + * @throws DiException|ReflectionException + */ private function processTemplates(string $srcPath, string &$dstPath): void { $dstPath = str_replace('.php.tpl', '.php', $dstPath); @@ -194,10 +197,13 @@ private function processTemplates(string $srcPath, string &$dstPath): void $this->fs->put($dstPath, $processedContent); } + /** + * @throws DiException|ReflectionException + */ private function replacePlaceholders(string $content): string { $placeholders = [ - '{{MODULE_NAMESPACE}}' => module_base_namespace() . '\\' . $this->getModuleName(), + '{{MODULE_NAMESPACE}}' => request()->getModuleBaseNamespace() . '\\' . $this->getModuleName(), '{{MODULE_NAME}}' => $this->getModuleName(), ]; diff --git a/src/Paginator/Traits/PaginatorTrait.php b/src/Paginator/Traits/PaginatorTrait.php index 460032a82..2748dedb7 100644 --- a/src/Paginator/Traits/PaginatorTrait.php +++ b/src/Paginator/Traits/PaginatorTrait.php @@ -219,7 +219,7 @@ public function getPagination(bool $withBaseUrl = false, ?int $pageItemsCount = */ protected function getUri(bool $withBaseUrl = false): string { - $routeUrl = preg_replace('/([?&](page|per_page)=\d+)/', '', route_uri() ?? ''); + $routeUrl = preg_replace('/([?&](page|per_page)=\d+)/', '', request()->getUri() ?? ''); $routeUrl = preg_replace('/&/', '?', $routeUrl ?? '', 1); $url = $routeUrl; diff --git a/src/Renderer/Adapters/HtmlAdapter.php b/src/Renderer/Adapters/HtmlAdapter.php index 6f20982dc..5a9d65425 100644 --- a/src/Renderer/Adapters/HtmlAdapter.php +++ b/src/Renderer/Adapters/HtmlAdapter.php @@ -83,7 +83,7 @@ public function render(string $view, array $params = []): string */ private function getViewFilePath(string $view): string { - $moduleViewPath = modules_dir() . DS . current_module() . DS . 'Views' . DS . $view . '.php'; + $moduleViewPath = modules_dir() . DS . request()->getCurrentModule() . DS . 'Views' . DS . $view . '.php'; $sharedViewPath = base_dir() . DS . 'shared' . DS . 'views' . DS . $view . '.php'; return $this->fs->exists($moduleViewPath) ? $moduleViewPath : $sharedViewPath; diff --git a/src/Renderer/Adapters/TwigAdapter.php b/src/Renderer/Adapters/TwigAdapter.php index 5c18dc0c3..93bdff515 100644 --- a/src/Renderer/Adapters/TwigAdapter.php +++ b/src/Renderer/Adapters/TwigAdapter.php @@ -76,7 +76,7 @@ public function render(string $view, array $params = []): string */ private function getLoader(string $view): FilesystemLoader { - $moduleViewPath = modules_dir() . DS . current_module() . DS . 'Views' . DS . $view . '.php'; + $moduleViewPath = modules_dir() . DS . request()->getCurrentModule() . DS . 'Views' . DS . $view . '.php'; $sharedViewPath = base_dir() . DS . 'shared' . DS . 'views' . DS . $view . '.php'; if ($this->fs->exists($moduleViewPath)) { diff --git a/src/ResourceCache/ViewCache.php b/src/ResourceCache/ViewCache.php index 41fdb9615..83c700ac1 100644 --- a/src/ResourceCache/ViewCache.php +++ b/src/ResourceCache/ViewCache.php @@ -183,7 +183,7 @@ private function getCacheDir(): string $viewCacheDir = base_dir() . DS . $configCacheDir . DS . 'views'; - if ($module = current_module()) { + if ($module = request()->getCurrentModule()) { $viewCacheDir = base_dir() . DS . $configCacheDir . DS . 'views' . DS . strtolower($module); } diff --git a/src/Router/Helpers/router.php b/src/Router/Helpers/router.php index beeba8096..d7dfc102b 100644 --- a/src/Router/Helpers/router.php +++ b/src/Router/Helpers/router.php @@ -13,7 +13,6 @@ */ use Quantum\Di\Exceptions\DiException; -use Quantum\Router\RouteCollection; use Quantum\Router\Route; use Quantum\Http\Request; use Quantum\Di\Di; @@ -25,9 +24,7 @@ */ function current_middlewares(): ?array { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getMiddlewares() : null; + return request()->getCurrentMiddlewares(); } /** @@ -41,9 +38,7 @@ function current_module(): ?string return null; } - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getModule() : null; + return request()->getCurrentModule(); } /** @@ -53,9 +48,7 @@ function current_module(): ?string */ function current_controller(): ?string { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getController() : null; + return request()->getCurrentController(); } /** @@ -65,9 +58,7 @@ function current_controller(): ?string */ function current_action(): ?string { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getAction() : null; + return request()->getCurrentAction(); } /** @@ -77,9 +68,7 @@ function current_action(): ?string */ function route_callback(): ?Closure { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getClosure() : null; + return request()->getRouteCallback(); } /** @@ -89,9 +78,7 @@ function route_callback(): ?Closure */ function current_route(): ?string { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getPattern() : null; + return request()->getCurrentRoutePattern(); } /** @@ -101,9 +88,7 @@ function current_route(): ?string */ function route_pattern(): string { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? ($matchedRoute->getRoute()->getCompiledPattern() ?? '') : ''; + return request()->getCompiledRoutePattern(); } /** @@ -113,9 +98,7 @@ function route_pattern(): string */ function route_params(): array { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getParams() : []; + return request()->getRouteParams(); } /** @@ -126,8 +109,7 @@ function route_params(): array */ function route_param(string $name) { - $params = route_params(); - return $params[$name] ?? null; + return request()->getRouteParam($name); } /** @@ -157,9 +139,7 @@ function route_uri(): ?string */ function route_cache_settings(): ?array { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getCache() : null; + return request()->getRouteCacheSettings(); } /** @@ -168,9 +148,7 @@ function route_cache_settings(): ?array */ function route_name(): ?string { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getName() : null; + return request()->getRouteName(); } /** @@ -179,9 +157,7 @@ function route_name(): ?string */ function route_prefix(): ?string { - $matchedRoute = request()->getMatchedRoute(); - - return $matchedRoute ? $matchedRoute->getRoute()->getPrefix() : null; + return request()->getRoutePrefix(); } /** @@ -190,23 +166,7 @@ function route_prefix(): ?string */ function find_route_by_name(string $name, string $module): ?Route { - if (!Di::isRegistered(RouteCollection::class)) { - return null; - } - - $collection = Di::get(RouteCollection::class); - - foreach ($collection->all() as $route) { - if ( - $route->getName() !== null && - strcasecmp($route->getName(), $name) === 0 && - strcasecmp((string) $route->getModule(), $module) === 0 - ) { - return $route; - } - } - - return null; + return request()->findRouteByName($name, $module); } /** @@ -215,23 +175,7 @@ function find_route_by_name(string $name, string $module): ?Route */ function route_group_exists(string $name, string $module): bool { - if (!Di::isRegistered(RouteCollection::class)) { - return false; - } - - $collection = Di::get(RouteCollection::class); - - foreach ($collection->all() as $route) { - if ( - $route->getGroup() !== null && - strcasecmp($route->getGroup(), $name) === 0 && - strcasecmp((string) $route->getModule(), $module) === 0 - ) { - return true; - } - } - - return false; + return request()->routeGroupExists($name, $module); } /** @@ -239,7 +183,5 @@ function route_group_exists(string $name, string $module): bool */ function module_base_namespace(): string { - return environment()->isTesting() - ? 'Quantum\\Tests\\_root\\modules' - : 'Modules'; + return request()->getModuleBaseNamespace(); } diff --git a/src/Router/RouteBuilder.php b/src/Router/RouteBuilder.php index 464ae1ee8..1c18e8187 100644 --- a/src/Router/RouteBuilder.php +++ b/src/Router/RouteBuilder.php @@ -17,6 +17,8 @@ namespace Quantum\Router; use Quantum\Router\Exceptions\RouteException; +use Quantum\Di\Exceptions\DiException; +use ReflectionException; use Closure; /** @@ -94,7 +96,7 @@ public function build(array $moduleRouteClosures, array $moduleConfigs): RouteCo * Define a route with multiple HTTP methods. * @param callable|string $handler * @param string|null $action - * @throws RouteException + * @throws RouteException|DiException|ReflectionException */ public function add(string $path, string $methods, $handler, string $action = null): self { @@ -110,7 +112,7 @@ public function add(string $path, string $methods, $handler, string $action = nu * Define a GET route. * @param callable|string $handler * @param string|null $action - * @throws RouteException + * @throws RouteException|DiException|ReflectionException */ public function get(string $path, $handler, string $action = null): self { @@ -121,7 +123,7 @@ public function get(string $path, $handler, string $action = null): self * Define a POST route. * @param callable|string $handler * @param string|null $action - * @throws RouteException + * @throws RouteException|DiException|ReflectionException */ public function post(string $path, $handler, string $action = null): self { @@ -132,7 +134,7 @@ public function post(string $path, $handler, string $action = null): self * Define a PUT route. * @param callable|string $handler * @param string|null $action - * @throws RouteException + * @throws RouteException|DiException|ReflectionException */ public function put(string $path, $handler, string $action = null): self { @@ -142,8 +144,7 @@ public function put(string $path, $handler, string $action = null): self /** * Define a DELETE route. * @param callable|string $handler - * @param string|null $action - * @throws RouteException + * @throws RouteException|DiException|ReflectionException */ public function delete(string $path, $handler, string $action = null): self { @@ -280,7 +281,7 @@ public function cacheable(bool $enabled, ?int $ttl = null): self * Create and register a Route instance. * @param array $methods * @param callable|string $handler - * @throws RouteException + * @throws RouteException|DiException|ReflectionException */ private function addRoute( array $methods, @@ -313,7 +314,7 @@ private function addRoute( } $handler = - module_base_namespace() + request()->getModuleBaseNamespace() . '\\' . $this->currentModule . '\\Controllers\\' diff --git a/src/View/View.php b/src/View/View.php index a0bc733f8..ed9d8b0d1 100644 --- a/src/View/View.php +++ b/src/View/View.php @@ -162,14 +162,7 @@ public function flushParams(): void /** * Renders the view. * @param array $params - * @throws AssetException - * @throws BaseException - * @throws ConfigException - * @throws DatabaseException - * @throws DiException - * @throws ReflectionException - * @throws SessionException - * @throws ViewException + * @throws ViewException|AssetException|SessionException|DatabaseException|ConfigException|BaseException|DiException|ReflectionException */ public function render(string $viewFile, array $params = []): ?string { @@ -196,7 +189,7 @@ public function render(string $viewFile, array $params = []): ?string $layoutContent = $this->renderFile($layoutFile); if ($this->viewCache->isEnabled()) { - $uri = route_uri(); + $uri = request()->getUri(); if ($uri !== null) { $layoutContent = $this->viewCache ->set($uri, $layoutContent) @@ -289,7 +282,7 @@ private function updateDebugger(string $viewFile): void { $routesCell = $this->debugger->getStoreCell(Debugger::ROUTES); $currentData = current($routesCell)[LogLevel::INFO] ?? []; - $additionalData = ['View' => current_module() . '/Views/' . $viewFile]; + $additionalData = ['View' => request()->getCurrentModule() . '/Views/' . $viewFile]; $mergedData = array_merge($currentData, $additionalData); $this->debugger->clearStoreCell(Debugger::ROUTES); $this->debugger->addToStoreCell(Debugger::ROUTES, LogLevel::INFO, $mergedData); diff --git a/tests/Unit/Http/RequestTest.php b/tests/Unit/Http/RequestTest.php index 35caf7c70..0c84da047 100644 --- a/tests/Unit/Http/RequestTest.php +++ b/tests/Unit/Http/RequestTest.php @@ -2,7 +2,11 @@ namespace Quantum\Tests\Unit\Http; +use Quantum\Router\RouteCollection; use Quantum\Tests\Unit\AppTestCase; +use Quantum\Router\MatchedRoute; +use Quantum\Router\Route; +use Quantum\Di\Di; class RequestTest extends AppTestCase { @@ -60,4 +64,50 @@ public function testGetCsrfToken(): void $this->assertNotNull($request->getCsrfToken()); } + + public function testRouteMetadataProxyMethods(): void + { + $route = new Route(['GET'], 'post/[uuid=:any]', 'PostController', 'show'); + $route + ->module('Web') + ->prefix('api') + ->group('content') + ->name('post.show') + ->addMiddlewares(['Auth']) + ->cache(true, 60) + ->setCompiledPattern('compiled-pattern'); + + request()->setMatchedRoute(new MatchedRoute($route, ['uuid' => 'abc-123'])); + + $this->assertSame(['Auth'], request()->getCurrentMiddlewares()); + $this->assertSame('Web', request()->getCurrentModule()); + $this->assertSame('PostController', request()->getCurrentController()); + $this->assertSame('show', request()->getCurrentAction()); + $this->assertSame('post/[uuid=:any]', request()->getCurrentRoutePattern()); + $this->assertSame('compiled-pattern', request()->getCompiledRoutePattern()); + $this->assertSame(['uuid' => 'abc-123'], request()->getRouteParams()); + $this->assertSame('abc-123', request()->getRouteParam('uuid')); + $this->assertSame(['enabled' => true, 'ttl' => 60], request()->getRouteCacheSettings()); + $this->assertSame('post.show', request()->getRouteName()); + $this->assertSame('api', request()->getRoutePrefix()); + } + + public function testRouteCollectionProxyMethods(): void + { + $route = new Route(['GET'], 'dashboard', 'DashboardController', 'index'); + $route->name('dashboard')->group('auth')->module('web'); + + $collection = Di::isRegistered(RouteCollection::class) + ? Di::get(RouteCollection::class) + : new RouteCollection(); + $collection->add($route); + + if (!Di::isRegistered(RouteCollection::class)) { + Di::set(RouteCollection::class, $collection); + } + + $this->assertInstanceOf(Route::class, request()->findRouteByName('dashboard', 'web')); + $this->assertTrue(request()->routeGroupExists('auth', 'web')); + $this->assertFalse(request()->routeGroupExists('guest', 'web')); + } } From b88a9079b26f957c88301f56b8088cc601dd2f16 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 22 Apr 2026 12:27:57 +0400 Subject: [PATCH 2/2] [#462] Normalize helper surface and fix router issues --- src/Http/Traits/Request/Route.php | 4 ++-- src/Router/Helpers/router.php | 10 +++------- tests/Unit/Http/RequestTest.php | 6 ++++++ tests/Unit/Router/Helpers/RouteHelpersTest.php | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Http/Traits/Request/Route.php b/src/Http/Traits/Request/Route.php index f6cacedf9..cafe22999 100644 --- a/src/Http/Traits/Request/Route.php +++ b/src/Http/Traits/Request/Route.php @@ -73,9 +73,9 @@ public function getCurrentRoutePattern(): ?string return $this->route ? $this->route->getRoute()->getPattern() : null; } - public function getCompiledRoutePattern(): string + public function getCompiledRoutePattern(): ?string { - return $this->route ? ($this->route->getRoute()->getCompiledPattern() ?? '') : ''; + return $this->route ? $this->route->getRoute()->getCompiledPattern() : null; } /** diff --git a/src/Router/Helpers/router.php b/src/Router/Helpers/router.php index d7dfc102b..fe7a73901 100644 --- a/src/Router/Helpers/router.php +++ b/src/Router/Helpers/router.php @@ -29,7 +29,6 @@ function current_middlewares(): ?array /** * Gets current route module - * @return string|null * @throws DiException|ReflectionException */ function current_module(): ?string @@ -43,7 +42,6 @@ function current_module(): ?string /** * Gets current route controller - * @return string|null * @throws DiException|ReflectionException */ function current_controller(): ?string @@ -53,7 +51,6 @@ function current_controller(): ?string /** * Gets current route action - * @return string|null * @throws DiException|ReflectionException */ function current_action(): ?string @@ -63,7 +60,6 @@ function current_action(): ?string /** * Gets current route callback - * @return Closure|null * @throws DiException|ReflectionException */ function route_callback(): ?Closure @@ -82,11 +78,10 @@ function current_route(): ?string } /** - * Gets current route complied pattern - * @return string + * Gets current route compiled pattern * @throws DiException|ReflectionException */ -function route_pattern(): string +function route_pattern(): ?string { return request()->getCompiledRoutePattern(); } @@ -180,6 +175,7 @@ function route_group_exists(string $name, string $module): bool /** * Gets the module base namespace depending on env + * @throws DiException|ReflectionException */ function module_base_namespace(): string { diff --git a/tests/Unit/Http/RequestTest.php b/tests/Unit/Http/RequestTest.php index 0c84da047..16aeea9b9 100644 --- a/tests/Unit/Http/RequestTest.php +++ b/tests/Unit/Http/RequestTest.php @@ -92,6 +92,12 @@ public function testRouteMetadataProxyMethods(): void $this->assertSame('api', request()->getRoutePrefix()); } + public function testCompiledRoutePatternReturnsNullWhenNoRouteMatched(): void + { + request()->setMatchedRoute(null); + $this->assertNull(request()->getCompiledRoutePattern()); + } + public function testRouteCollectionProxyMethods(): void { $route = new Route(['GET'], 'dashboard', 'DashboardController', 'index'); diff --git a/tests/Unit/Router/Helpers/RouteHelpersTest.php b/tests/Unit/Router/Helpers/RouteHelpersTest.php index b99d0a278..8e7e17913 100644 --- a/tests/Unit/Router/Helpers/RouteHelpersTest.php +++ b/tests/Unit/Router/Helpers/RouteHelpersTest.php @@ -26,7 +26,7 @@ public function testHelpersReturnDefaultsWhenNoRouteMatched(): void $this->assertNull(current_action()); $this->assertNull(route_callback()); $this->assertNull(current_route()); - $this->assertSame('', route_pattern()); + $this->assertNull(route_pattern()); $this->assertSame([], route_params()); $this->assertNull(route_param('id')); $this->assertNull(route_cache_settings());