From d02735ea6ca9cc66945b15c5d8773a56128afd57 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 8 Apr 2023 12:48:08 +0900 Subject: [PATCH 1/6] feat: module routing for Auto Routing Improved --- app/Config/Routing.php | 13 ++++++++++ system/Router/AutoRouterImproved.php | 10 +++++++ .../system/Router/AutoRouterImprovedTest.php | 26 +++++++++++++++++-- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app/Config/Routing.php b/app/Config/Routing.php index 73d9a93f0f4b..e3183d2e8db8 100644 --- a/app/Config/Routing.php +++ b/app/Config/Routing.php @@ -97,4 +97,17 @@ class Routing extends BaseRouting * Default: false */ public bool $prioritize = false; + + /** + * Map of URI segments and namespaces. For Auto Routing (Improved). + * + * The key is the first URI segment. The value is the controller namespace. + * E.g., + * [ + * 'blog' => 'Acme\Blog\Controllers', + * ] + * + * @var array [ uri_segment => namespace ] + */ + public array $moduleRoutes = []; } diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 87409e78f107..0be6ed39e11c 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -13,6 +13,7 @@ use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Router\Exceptions\MethodNotFoundException; +use Config\Routing; use ReflectionClass; use ReflectionException; @@ -112,6 +113,15 @@ public function getRoute(string $uri): array { $segments = explode('/', $uri); + // Check for Module Routes. + if ($routingConfig = config(Routing::class)) { + if (array_key_exists($segments[0], $routingConfig->moduleRoutes)) { + $uriSegment = array_shift($segments); + + $this->namespace = rtrim($routingConfig->moduleRoutes[$uriSegment], '\\') . '\\'; + } + } + // WARNING: Directories get shifted out of the segments array. $nonDirSegments = $this->scanControllers($segments); diff --git a/tests/system/Router/AutoRouterImprovedTest.php b/tests/system/Router/AutoRouterImprovedTest.php index d6560e1eb9e6..75a5f49b8648 100644 --- a/tests/system/Router/AutoRouterImprovedTest.php +++ b/tests/system/Router/AutoRouterImprovedTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Router; +use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Router\Controllers\Dash_folder\Dash_controller; @@ -39,11 +40,11 @@ protected function setUp(): void $this->collection = new RouteCollection(Services::locator(), $moduleConfig, new Routing()); } - private function createNewAutoRouter(string $httpVerb = 'get'): AutoRouterImproved + private function createNewAutoRouter(string $httpVerb = 'get', $namespace = 'CodeIgniter\Router\Controllers'): AutoRouterImproved { return new AutoRouterImproved( [], - 'CodeIgniter\Router\Controllers', + $namespace, $this->collection->getDefaultController(), $this->collection->getDefaultMethod(), true, @@ -66,6 +67,27 @@ public function testAutoRouteFindsDefaultControllerAndMethodGet() $this->assertSame([], $params); } + public function testAutoRouteFindsModuleDefaultControllerAndMethodGet() + { + $config = config(Routing::class); + $config->moduleRoutes = [ + 'test' => 'CodeIgniter\Router\Controllers', + ]; + Factories::injectMock('config', Routing::class, $config); + + $this->collection->setDefaultController('Index'); + + $router = $this->createNewAutoRouter('get', 'App/Controllers'); + + [$directory, $controller, $method, $params] + = $router->getRoute('test'); + + $this->assertNull($directory); + $this->assertSame('\\' . Index::class, $controller); + $this->assertSame('getIndex', $method); + $this->assertSame([], $params); + } + public function testAutoRouteFindsDefaultControllerAndMethodPost() { $this->collection->setDefaultController('Index'); From 2ea49afdfc4b405721fe805954cc4d400bd293bc Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 8 Apr 2023 13:33:01 +0900 Subject: [PATCH 2/6] feat: add Module Routing to `spark routes` --- system/Commands/Utilities/Routes.php | 17 +++++++++++++++++ .../AutoRouterImproved/AutoRouteCollector.php | 18 ++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index 3b0112db828a..b40a1cbe41bb 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -18,6 +18,7 @@ use CodeIgniter\Commands\Utilities\Routes\AutoRouterImproved\AutoRouteCollector as AutoRouteCollectorImproved; use CodeIgniter\Commands\Utilities\Routes\FilterCollector; use CodeIgniter\Commands\Utilities\Routes\SampleURIGenerator; +use Config\Routing; use Config\Services; /** @@ -152,6 +153,22 @@ public function run(array $params) ); $autoRoutes = $autoRouteCollector->get(); + + // Check for Module Routes. + if ($routingConfig = config(Routing::class)) { + foreach ($routingConfig->moduleRoutes as $uri => $namespace) { + $autoRouteCollector = new AutoRouteCollectorImproved( + $namespace, + $collection->getDefaultController(), + $collection->getDefaultMethod(), + $methods, + $collection->getRegisteredControllers('*'), + $uri + ); + + $autoRoutes = array_merge($autoRoutes, $autoRouteCollector->get()); + } + } } else { $autoRouteCollector = new AutoRouteCollector( $collection->getDefaultNamespace(), diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php index f2de8e4b4a6d..f3b1c8169d3c 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php @@ -35,6 +35,11 @@ final class AutoRouteCollector */ private array $protectedControllers; + /** + * @var string URI prefix for Module Routing + */ + private string $prefix; + /** * @param string $namespace namespace to search */ @@ -43,13 +48,15 @@ public function __construct( string $defaultController, string $defaultMethod, array $httpMethods, - array $protectedControllers + array $protectedControllers, + string $prefix = '' ) { $this->namespace = $namespace; $this->defaultController = $defaultController; $this->defaultMethod = $defaultMethod; $this->httpMethods = $httpMethods; $this->protectedControllers = $protectedControllers; + $this->prefix = $prefix; } /** @@ -82,9 +89,16 @@ public function get(): array $routes = $this->addFilters($routes); foreach ($routes as $item) { + $route = $item['route'] . $item['route_params']; + if ($this->prefix !== '' && $route === '/') { + $route = $this->prefix; + } elseif ($this->prefix !== '') { + $route = $this->prefix . '/' . $route; + } + $tbody[] = [ strtoupper($item['method']) . '(auto)', - $item['route'] . $item['route_params'], + $route, '', $item['handler'], $item['before'], From 7f817fd435389cfd391ca50d91f5c20d232c9ae1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 8 Apr 2023 14:00:06 +0900 Subject: [PATCH 3/6] refactor: remove if --- system/Router/AutoRouterImproved.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 0be6ed39e11c..000afda126bd 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -114,12 +114,12 @@ public function getRoute(string $uri): array $segments = explode('/', $uri); // Check for Module Routes. - if ($routingConfig = config(Routing::class)) { - if (array_key_exists($segments[0], $routingConfig->moduleRoutes)) { - $uriSegment = array_shift($segments); - - $this->namespace = rtrim($routingConfig->moduleRoutes[$uriSegment], '\\') . '\\'; - } + if ( + ($routingConfig = config(Routing::class)) + && array_key_exists($segments[0], $routingConfig->moduleRoutes) + ) { + $uriSegment = array_shift($segments); + $this->namespace = rtrim($routingConfig->moduleRoutes[$uriSegment], '\\') . '\\'; } // WARNING: Directories get shifted out of the segments array. From e1a1f89be813b105eaf31b34129af8b5db05bd3d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 8 Apr 2023 14:07:07 +0900 Subject: [PATCH 4/6] refactor: by rector --- system/Commands/Utilities/Routes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index b40a1cbe41bb..83ca40a7c1bd 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -166,7 +166,7 @@ public function run(array $params) $uri ); - $autoRoutes = array_merge($autoRoutes, $autoRouteCollector->get()); + $autoRoutes = [...$autoRoutes, ...$autoRouteCollector->get()]; } } } else { From 9287cb0ca7123fea7f698e746622b97f6d666405 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 10 Apr 2023 10:35:04 +0900 Subject: [PATCH 5/6] docs: add docs --- user_guide_src/source/changelogs/v4.4.0.rst | 2 ++ user_guide_src/source/incoming/routing.rst | 26 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.4.0.rst b/user_guide_src/source/changelogs/v4.4.0.rst index 3c4fe991d3c6..29a8b030f9ba 100644 --- a/user_guide_src/source/changelogs/v4.4.0.rst +++ b/user_guide_src/source/changelogs/v4.4.0.rst @@ -88,6 +88,8 @@ Others the ``Content-Disposition: inline`` header to display the file in the browser. See :ref:`open-file-in-browser` for details. - **View:** Added optional 2nd parameter ``$saveData`` on ``renderSection()`` to prevent from auto cleans the data after displaying. See :ref:`View Layouts ` for details. +- **Auto Routing (Improved)**: Now you can route to Modules. + See :ref:`auto-routing-improved-module-routing` for details. - **Auto Routing (Improved)**: Now you can use URI without a method name like ``product/15`` where ``15`` is an arbitrary number. See :ref:`controller-default-method-fallback` for details. diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 066009beda65..b2bbde1aea66 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -716,6 +716,32 @@ In this example, if the user were to visit **example.com/products**, and a ``Pro .. note:: You cannot access the controller with the URI of the default method name. In the example above, you can access **example.com/products**, but if you access **example.com/products/listall**, it will be not found. +.. _auto-routing-improved-module-routing: + +Module Routing +============== + +.. versionadded:: 4.4.0 + +You can use auto routing even if you use :doc:`../general/modules` and place +the controllers in a different namespace. + +To route to a module, the ``$moduleRoutes`` property in **app/Config/Routing.php** +must be set:: + + public array $moduleRoutes = [ + 'blog' => 'Acme\Blog\Controllers', + ]; + +The key is the first URI segment for the module, and the value is the controller +namespace. In the above configuration, **http://localhost:8080/blog/foo/bar** +will be routed to ``Acme\Blog\Controllers\Foo::getBar()``. + +.. note:: If you define ``$moduleRoutes``, the routing for the module takes + precedence. In the above example, even if you have the ``App\Controllers\Blog`` + controller, **http://localhost:8080/blog** will be routed to the default + controller ``Acme\Blog\Controllers\Home``. + .. _auto-routing-legacy: Auto Routing (Legacy) From a72ea47e67714b390e739c39e09f51996e990972 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 10 Apr 2023 11:08:30 +0900 Subject: [PATCH 6/6] fix: `spark routes` filters output --- .../AutoRouterImproved/AutoRouteCollector.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php index f3b1c8169d3c..2b6096016f7e 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php @@ -90,6 +90,8 @@ public function get(): array foreach ($routes as $item) { $route = $item['route'] . $item['route_params']; + + // For module routing if ($this->prefix !== '' && $route === '/') { $route = $this->prefix; } elseif ($this->prefix !== '') { @@ -115,13 +117,22 @@ private function addFilters($routes) $filterCollector = new FilterCollector(true); foreach ($routes as &$route) { + $routePath = $route['route']; + + // For module routing + if ($this->prefix !== '' && $route === '/') { + $routePath = $this->prefix; + } elseif ($this->prefix !== '') { + $routePath = $this->prefix . '/' . $routePath; + } + // Search filters for the URI with all params $sampleUri = $this->generateSampleUri($route); - $filtersLongest = $filterCollector->get($route['method'], $route['route'] . $sampleUri); + $filtersLongest = $filterCollector->get($route['method'], $routePath . $sampleUri); // Search filters for the URI without optional params $sampleUri = $this->generateSampleUri($route, false); - $filtersShortest = $filterCollector->get($route['method'], $route['route'] . $sampleUri); + $filtersShortest = $filterCollector->get($route['method'], $routePath . $sampleUri); // Get common array elements $filters['before'] = array_intersect($filtersLongest['before'], $filtersShortest['before']);