diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 9e15b68cec1a..181229cba6dd 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -656,8 +656,8 @@ public function getRedirectCode(string $routeKey): int * $route->resource('users'); * }); * - * @param string $name The name to group/prefix the routes with. - * @param array|(callable(self): void) ...$params + * @param string $name The name to group/prefix the routes with. + * @param array|(callable(static): void) ...$params * * @return void */ diff --git a/tests/_support/Router/RouteCollectionSubclass.php b/tests/_support/Router/RouteCollectionSubclass.php new file mode 100644 index 000000000000..c2623111046f --- /dev/null +++ b/tests/_support/Router/RouteCollectionSubclass.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Router; + +use CodeIgniter\Router\RouteCollection; + +final class RouteCollectionSubclass extends RouteCollection +{ +} diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 9ceec705cf6b..d5a5dab8a9a3 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -27,6 +27,7 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use Tests\Support\Controllers\Hello; +use Tests\Support\Router\RouteCollectionSubclass; /** * @internal @@ -314,6 +315,38 @@ static function ($routes): void { $this->assertSame($expected, $routes->getRoutes()); } + public function testGroupingPassesSubclassToNestedCallbacks(): void + { + $modules = new Modules(); + $modules->enabled = false; + $config = new Routing(); + $config->defaultNamespace = '\\'; + $routes = new RouteCollectionSubclass(service('locator'), $modules, $config); + $routes->setHTTPVerb(Method::GET); + + $routes->group('admin', ['namespace' => 'Admin', 'filter' => ['csrf']], function (RouteCollectionSubclass $group) use ($routes): void { + $this->assertSame($routes, $group); + + $group->group('profile', ['filter' => ['honeypot']], function (RouteCollectionSubclass $nested) use ($routes): void { + $this->assertSame($routes, $nested); + $nested->get('show', 'Profile::show'); + }); + + $group->get('dashboard', 'Dashboard::index'); + }); + + $routes->get('home', 'Home::index'); + + $this->assertSame([ + 'admin/profile/show' => '\\Admin\\Profile::show', + 'admin/dashboard' => '\\Admin\\Dashboard::index', + 'home' => '\\Home::index', + ], $routes->getRoutes(Method::GET)); + $this->assertSame(['csrf', 'honeypot'], $routes->getFiltersForRoute('admin/profile/show')); + $this->assertSame(['csrf'], $routes->getFiltersForRoute('admin/dashboard')); + $this->assertFalse($routes->isFiltered('home')); + } + public function testGroupGetsSanitized(): void { $routes = $this->getCollector(); diff --git a/user_guide_src/source/changelogs/v4.7.6.rst b/user_guide_src/source/changelogs/v4.7.6.rst index 8739e9546d4c..29f2d64723b2 100644 --- a/user_guide_src/source/changelogs/v4.7.6.rst +++ b/user_guide_src/source/changelogs/v4.7.6.rst @@ -33,6 +33,9 @@ Bugs Fixed ********** - **Commands:** Fixed a bug where generator commands did not sort the imports of a template with CRLF line endings. +- **Routing:** Corrected the PHPDoc callback type of ``RouteCollection::group()`` + to preserve the concrete collection type, allowing callbacks typed to a + ``RouteCollection`` subclass to pass static analysis. - **Format:** Fixed ``XMLFormatter`` so that an array key that becomes empty after sanitization no longer triggers a ``ValueError``; the fallback tag name ``item`` is used instead. Values that cannot be converted to a string, such as objects