Skip to content

Commit

Permalink
Merge pull request #7653 from kenjis/refactor-extract-DefinedRouteCol…
Browse files Browse the repository at this point in the history
…lector

refactor: extract DefinedRouteCollector
  • Loading branch information
kenjis authored Jul 4, 2023
2 parents 6c09f35 + f5a2841 commit 8d9b176
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 49 deletions.
35 changes: 15 additions & 20 deletions system/Commands/Utilities/Routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 CodeIgniter\Router\DefinedRouteCollector;
use Config\Feature;
use Config\Routing;
use Config\Services;
Expand Down Expand Up @@ -115,29 +116,23 @@ public function run(array $params)
$uriGenerator = new SampleURIGenerator();
$filterCollector = new FilterCollector();

foreach ($methods as $method) {
$routes = $collection->getRoutes($method);
$definedRouteCollector = new DefinedRouteCollector($collection);

foreach ($routes as $route => $handler) {
if (is_string($handler) || $handler instanceof Closure) {
$sampleUri = $uriGenerator->get($route);
$filters = $filterCollector->get($method, $sampleUri);
foreach ($definedRouteCollector->collect() as $route) {
if (is_string($route['handler']) || $route['handler'] instanceof Closure) {
$sampleUri = $uriGenerator->get($route['route']);
$filters = $filterCollector->get($route['method'], $sampleUri);

if ($handler instanceof Closure) {
$handler = '(Closure)';
}

$routeName = $collection->getRoutesOptions($route)['as'] ?? '»';
$routeName = ($route['route'] === $route['name']) ? '»' : $route['name'];

$tbody[] = [
strtoupper($method),
$route,
$routeName,
$handler,
implode(' ', array_map('class_basename', $filters['before'])),
implode(' ', array_map('class_basename', $filters['after'])),
];
}
$tbody[] = [
strtoupper($route['method']),
$route['route'],
$routeName,
$route['handler'],
implode(' ', array_map('class_basename', $filters['before'])),
implode(' ', array_map('class_basename', $filters['after'])),
];
}
}

Expand Down
42 changes: 13 additions & 29 deletions system/Debug/Toolbar/Collectors/Routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace CodeIgniter\Debug\Toolbar\Collectors;

use CodeIgniter\Router\DefinedRouteCollector;
use Config\Services;
use ReflectionException;
use ReflectionFunction;
Expand Down Expand Up @@ -55,9 +56,6 @@ public function display(): array
$rawRoutes = Services::routes(true);
$router = Services::router(null, null, true);

// Matched Route
$route = $router->getMatchedRoute();

// Get our parameters
// Closure routes
if (is_callable($router->controllerName())) {
Expand Down Expand Up @@ -100,32 +98,18 @@ public function display(): array
];

// Defined Routes
$routes = [];
$methods = [
'get',
'head',
'post',
'patch',
'put',
'delete',
'options',
'trace',
'connect',
'cli',
];

foreach ($methods as $method) {
$raw = $rawRoutes->getRoutes($method);

foreach ($raw as $route => $handler) {
// filter for strings, as callbacks aren't displayable
if (is_string($handler)) {
$routes[] = [
'method' => strtoupper($method),
'route' => $route,
'handler' => $handler,
];
}
$routes = [];

$definedRouteCollector = new DefinedRouteCollector($rawRoutes);

foreach ($definedRouteCollector->collect() as $route) {
// filter for strings, as callbacks aren't displayable
if ($route['handler'] !== '(Closure)') {
$routes[] = [
'method' => strtoupper($route['method']),
'route' => $route['route'],
'handler' => $route['handler'],
];
}
}

Expand Down
69 changes: 69 additions & 0 deletions system/Router/DefinedRouteCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Router;

use Closure;
use Generator;

/**
* Collect all defined routes for display.
*/
final class DefinedRouteCollector
{
private RouteCollection $routeCollection;

public function __construct(RouteCollection $routes)
{
$this->routeCollection = $routes;
}

/**
* @phpstan-return Generator<array{method: string, route: string, name: string, handler: string}>
*/
public function collect(): Generator
{
$methods = [
'get',
'head',
'post',
'patch',
'put',
'delete',
'options',
'trace',
'connect',
'cli',
];

foreach ($methods as $method) {
$routes = $this->routeCollection->getRoutes($method);

foreach ($routes as $route => $handler) {
if (is_string($handler) || $handler instanceof Closure) {

if ($handler instanceof Closure) {
$handler = '(Closure)';
}

$routeName = $this->routeCollection->getRoutesOptions($route)['as'] ?? $route;

yield [
'method' => $method,
'route' => $route,
'name' => $routeName,
'handler' => $handler,
];
}
}
}
}
}
90 changes: 90 additions & 0 deletions tests/system/Router/DefinedRouteCollectorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Router;

use CodeIgniter\Config\Services;
use CodeIgniter\Test\CIUnitTestCase;
use Config\Modules;
use Config\Routing;

/**
* @internal
*
* @group Others
*/
final class DefinedRouteCollectorTest extends CIUnitTestCase
{
private function createRouteCollection(array $config = [], $moduleConfig = null): RouteCollection
{
$defaults = [
'Config' => APPPATH . 'Config',
'App' => APPPATH,
];
$config = array_merge($config, $defaults);

Services::autoloader()->addNamespace($config);

$loader = Services::locator();

if ($moduleConfig === null) {
$moduleConfig = new Modules();
$moduleConfig->enabled = false;
}

return (new RouteCollection($loader, $moduleConfig, new Routing()))->setHTTPVerb('get');
}

public function testCollect()
{
$routes = $this->createRouteCollection();
$routes->get('journals', 'Blogs');
$routes->get('product/(:num)', 'Catalog::productLookupByID/$1');
$routes->get('feed', static fn () => 'A Closure route.');
$routes->view('about', 'pages/about');

$collector = new DefinedRouteCollector($routes);

$definedRoutes = [];

foreach ($collector->collect() as $route) {
$definedRoutes[] = $route;
}

$expected = [
[
'method' => 'get',
'route' => 'journals',
'name' => 'journals',
'handler' => '\App\Controllers\Blogs',
],
[
'method' => 'get',
'route' => 'product/([0-9]+)',
'name' => 'product/([0-9]+)',
'handler' => '\App\Controllers\Catalog::productLookupByID/$1',
],
[
'method' => 'get',
'route' => 'feed',
'name' => 'feed',
'handler' => '(Closure)',
],
[
'method' => 'get',
'route' => 'about',
'name' => 'about',
'handler' => '(Closure)',
],
];
$this->assertSame($expected, $definedRoutes);
}
}

0 comments on commit 8d9b176

Please sign in to comment.