Skip to content

Commit 8192723

Browse files
authored
Merge pull request #409 from armanist/383-Refactor-Router-&-ModuleLoader-Introduce-Route-as-Single-Route-Entity-and-Decouple-Module-Loading
Refactor Router and ModuleLoader: Decouple module loading from route building
2 parents 5f481a5 + 7b0272a commit 8192723

10 files changed

Lines changed: 180 additions & 79 deletions

File tree

src/App/Traits/WebAppTrait.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Quantum\App\Exceptions\BaseException;
2424
use Quantum\Di\Exceptions\DiException;
2525
use Quantum\Module\ModuleLoader;
26+
use Quantum\Router\RouteBuilder;
2627
use DebugBar\DebugBarException;
2728
use Quantum\Environment\Server;
2829
use Quantum\Debugger\Debugger;
@@ -65,7 +66,6 @@ private function initializeDebugger()
6566
/**
6667
* Load modules
6768
* @throws ModuleException
68-
* @throws RouteException
6969
*/
7070
private function loadModules()
7171
{
@@ -74,8 +74,10 @@ private function loadModules()
7474
$modulesDependencies = $moduleLoader->loadModulesDependencies();
7575
Di::registerDependencies($modulesDependencies);
7676

77-
$modulesRoutes = $moduleLoader->loadModulesRoutes();
78-
Router::setRoutes($modulesRoutes);
77+
$builder = new RouteBuilder();
78+
$allRoutes = $builder->build($moduleLoader->loadModulesRoutes(), $moduleLoader->getModuleConfigs());
79+
80+
Router::setRoutes($allRoutes);
7981
}
8082

8183
/**

src/Console/Commands/OpenApiCommand.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Quantum\Libraries\Storage\FileSystem;
2323
use Quantum\Di\Exceptions\DiException;
2424
use Quantum\Module\ModuleLoader;
25+
use Quantum\Router\RouteBuilder;
2526
use Quantum\Console\QtCommand;
2627
use Quantum\Router\Router;
2728
use ReflectionException;
@@ -100,9 +101,12 @@ class OpenApiCommand extends QtCommand
100101
*/
101102
public function exec()
102103
{
103-
$modulesRoutes = ModuleLoader::getInstance()->loadModulesRoutes();
104+
$moduleLoader = ModuleLoader::getInstance();
104105

105-
Router::setRoutes($modulesRoutes);
106+
$builder = new RouteBuilder();
107+
$allRoutes = $builder->build($moduleLoader->loadModulesRoutes(), $moduleLoader->getModuleConfigs());
108+
109+
Router::setRoutes($allRoutes);
106110

107111
$this->fs = FileSystemFactory::get();
108112

src/Console/Commands/RouteListCommand.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
use Quantum\Module\Exceptions\ModuleException;
1818
use Quantum\Router\Exceptions\RouteException;
1919
use Symfony\Component\Console\Helper\Table;
20+
use Quantum\Router\RouteBuilder;
2021
use Quantum\Module\ModuleLoader;
2122
use Quantum\Console\QtCommand;
2223
use Quantum\Router\Router;
2324

2425
/**
25-
* Class ServeCommand
26+
* Class RouteListCommand
2627
* @package Quantum\Console
2728
*/
2829
class RouteListCommand extends QtCommand
@@ -53,9 +54,12 @@ class RouteListCommand extends QtCommand
5354
public function exec()
5455
{
5556
try {
56-
$modulesRoutes = ModuleLoader::getInstance()->loadModulesRoutes();
57+
$moduleLoader = ModuleLoader::getInstance();
5758

58-
Router::setRoutes($modulesRoutes);
59+
$builder = new RouteBuilder();
60+
$allRoutes = $builder->build($moduleLoader->loadModulesRoutes(), $moduleLoader->getModuleConfigs());
61+
62+
Router::setRoutes($allRoutes);
5963

6064
$routes = Router::getRoutes();
6165

src/Module/ModuleLoader.php

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use Quantum\App\Exceptions\BaseException;
2222
use Quantum\Libraries\Storage\FileSystem;
2323
use Quantum\Di\Exceptions\DiException;
24-
use Quantum\Router\Route;
2524
use ReflectionException;
2625
use Quantum\App\App;
2726
use Closure;
@@ -42,10 +41,8 @@ class ModuleLoader
4241
*/
4342
private static $moduleConfigs = [];
4443

45-
/**
46-
* @var array<Closure>
47-
*/
48-
private static $moduleRoutes = [];
44+
/** @var array<string, Closure> */
45+
private static $moduleRouteClosures = [];
4946

5047
/**
5148
* @var FileSystem
@@ -80,12 +77,6 @@ public static function getInstance(): ModuleLoader
8077
return self::$instance;
8178
}
8279

83-
/**
84-
* Load modules routes
85-
* @return array
86-
* @throws ModuleException
87-
* @throws RouteException
88-
*/
8980
public function loadModulesRoutes(): array
9081
{
9182
if (empty(self::$moduleConfigs)) {
@@ -99,12 +90,33 @@ public function loadModulesRoutes(): array
9990
continue;
10091
}
10192

102-
$modulesRoutes = array_merge($modulesRoutes, $this->getModuleRoutes($module, new Route([$module => $options])));
93+
$modulesRoutes[$module] = $this->getModuleRouteDefinitions($module);
10394
}
10495

10596
return $modulesRoutes;
10697
}
10798

99+
private function getModuleRouteDefinitions(string $module): Closure
100+
{
101+
if (isset(self::$moduleRouteClosures[$module])) {
102+
return self::$moduleRouteClosures[$module];
103+
}
104+
105+
$moduleRoutesPath = modules_dir() . DS . $module . DS . 'routes' . DS . 'routes.php';
106+
107+
if (!$this->fs->exists($moduleRoutesPath)) {
108+
throw ModuleException::moduleRoutesNotFound($module);
109+
}
110+
111+
$closure = $this->fs->require($moduleRoutesPath, true);
112+
113+
if (!$closure instanceof Closure) {
114+
throw RouteException::notClosure();
115+
}
116+
117+
return self::$moduleRouteClosures[$module] = $closure;
118+
}
119+
108120
/**
109121
* @return array
110122
* @throws ModuleException
@@ -145,19 +157,6 @@ public function getModuleDependencies(string $module): array
145157
return self::$moduleDependencies[$module];
146158
}
147159

148-
/**
149-
* @return array
150-
* @throws ModuleException
151-
*/
152-
public function getModuleConfigs(): array
153-
{
154-
if (empty(self::$moduleConfigs)) {
155-
$this->loadModuleConfig();
156-
}
157-
158-
return self::$moduleConfigs;
159-
}
160-
161160
/**
162161
* @throws ModuleException
163162
*/
@@ -173,39 +172,24 @@ private function loadModuleConfig()
173172
}
174173

175174
/**
176-
* @param array $options
177-
* @return bool
178-
*/
179-
private function isModuleEnabled(array $options): bool
180-
{
181-
return $options['enabled'] ?? false;
182-
}
183-
184-
/**
185-
* @param string $module
186-
* @param Route $route
187175
* @return array
188176
* @throws ModuleException
189-
* @throws RouteException
190177
*/
191-
private function getModuleRoutes(string $module, Route $route): array
178+
public function getModuleConfigs(): array
192179
{
193-
$moduleRoutes = modules_dir() . DS . $module . DS . 'routes' . DS . 'routes.php';
194-
195-
if (!$this->fs->exists($moduleRoutes)) {
196-
throw ModuleException::moduleRoutesNotFound($module);
197-
}
198-
199-
if (empty(self::$moduleRoutes[$module])) {
200-
self::$moduleRoutes[$module] = $this->fs->require($moduleRoutes, true);
201-
}
202-
203-
if (!self::$moduleRoutes[$module] instanceof Closure) {
204-
throw RouteException::notClosure();
180+
if (empty(self::$moduleConfigs)) {
181+
$this->loadModuleConfig();
205182
}
206183

207-
self::$moduleRoutes[$module]($route);
184+
return self::$moduleConfigs;
185+
}
208186

209-
return $route->getRuntimeRoutes();
187+
/**
188+
* @param array $options
189+
* @return bool
190+
*/
191+
private function isModuleEnabled(array $options): bool
192+
{
193+
return (bool) ($options['enabled'] ?? false);
210194
}
211195
}

src/Router/Route.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,14 @@ class Route
7070
private $virtualRoutes = [];
7171

7272
/**
73-
* @param array $module
73+
* @param string $moduleName
74+
* @param array $moduleOptions
7475
*/
75-
public function __construct(array $module)
76+
public function __construct(string $moduleName, array $moduleOptions)
7677
{
7778
$this->virtualRoutes['*'] = [];
78-
$this->moduleName = key($module);
79-
$this->moduleOptions = $module[$this->moduleName];
79+
$this->moduleName = $moduleName;
80+
$this->moduleOptions = $moduleOptions;
8081
}
8182

8283
/**
@@ -95,7 +96,7 @@ public function add(string $route, string $method, ...$params): Route
9596
];
9697

9798
if (isset($this->moduleOptions['cacheable'])) {
98-
$this->currentRoute['cache_settings']['shouldCache'] = (bool)$this->moduleOptions['cacheable'];
99+
$this->currentRoute['cache_settings']['shouldCache'] = (bool) $this->moduleOptions['cacheable'];
99100
}
100101

101102
if (is_callable($params[0])) {

src/Router/RouteBuilder.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/**
4+
* Quantum PHP Framework
5+
*
6+
* An open source software development framework for PHP
7+
*
8+
* @package Quantum
9+
* @author Arman Ag. <arman.ag@softberg.org>
10+
* @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11+
* @link http://quantum.softberg.org/
12+
* @since 3.0.0
13+
*/
14+
15+
namespace Quantum\Router;
16+
17+
use Closure;
18+
19+
/**
20+
* Class RouteBuilder
21+
* @package Quantum\Router
22+
*/
23+
class RouteBuilder
24+
{
25+
/**
26+
* @param array<string, Closure> $moduleClosures moduleName => closure(Route $collector): void
27+
* @param array<string, array> $moduleConfigs moduleName => config options
28+
* @return array
29+
*/
30+
public function build(array $moduleClosures, array $moduleConfigs = []): array
31+
{
32+
$allRoutes = [];
33+
34+
foreach ($moduleClosures as $module => $closure) {
35+
$options = $moduleConfigs[$module] ?? [];
36+
37+
$routeCollector = new Route($module, $options);
38+
39+
$closure($routeCollector);
40+
41+
foreach ($routeCollector->getRuntimeRoutes() as $runtimeRoute) {
42+
$allRoutes[] = $runtimeRoute;
43+
}
44+
}
45+
46+
return $allRoutes;
47+
}
48+
}

src/Router/Router.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ private function handleRoutePattern(array $route): array
204204
$routePattern = '(\/)?';
205205
$routeParams = [];
206206

207-
$lastIndex = (int)array_key_last($routeSegments);
207+
$lastIndex = (int) array_key_last($routeSegments);
208208

209209
foreach ($routeSegments as $index => $segment) {
210210
$segmentParam = $this->getSegmentParam($segment, $index, $lastIndex);

tests/Unit/Module/ModuleLoaderTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use Quantum\Tests\Unit\AppTestCase;
66
use Quantum\Module\ModuleLoader;
7-
use Quantum\Router\Router;
7+
use Closure;
88

99
class ModuleLoaderTest extends AppTestCase
1010
{
@@ -32,13 +32,13 @@ public function testLoadModulesRoutes()
3232
{
3333
$modulesRoutes = $this->moduleLoader->loadModulesRoutes();
3434

35-
Router::setRoutes($modulesRoutes);
35+
$this->assertNotEmpty($modulesRoutes);
3636

37-
$this->assertNotEmpty(Router::getRoutes());
37+
$this->assertIsArray($modulesRoutes);
3838

39-
$this->assertIsArray(Router::getRoutes());
39+
$this->assertArrayHasKey('Test', $modulesRoutes);
4040

41-
$this->assertCount(2, Router::getRoutes());
41+
$this->assertInstanceOf(Closure::class, $modulesRoutes['Test']);
4242
}
4343

4444
public function testLoadModulesDependencies()

0 commit comments

Comments
 (0)