1 | <?php |
||||
2 | /** |
||||
3 | * DronePHP (http://www.dronephp.com) |
||||
4 | * |
||||
5 | * @link http://github.com/Pleets/DronePHP |
||||
6 | * @copyright Copyright (c) 2016-2018 Pleets. (http://www.pleets.org) |
||||
7 | * @license http://www.dronephp.com/license |
||||
8 | * @author Darío Rivera <[email protected]> |
||||
9 | */ |
||||
10 | |||||
11 | namespace DroneTest\Util; |
||||
12 | |||||
13 | use Drone\Mvc\AbstractController; |
||||
14 | use Drone\Mvc\Exception\MethodExecutionNotAllowedException; |
||||
15 | use Drone\Mvc\Exception\RouteNotFoundException; |
||||
16 | use Drone\Mvc\ModuleFactory; |
||||
17 | use Drone\Mvc\Router; |
||||
18 | use PHPUnit\Framework\TestCase; |
||||
19 | |||||
20 | class RouterTest extends TestCase |
||||
21 | { |
||||
22 | /** |
||||
23 | * Tests if the router can create an instance of a class |
||||
24 | * |
||||
25 | * @return null |
||||
26 | */ |
||||
27 | public function testSimpleRouteMatch() |
||||
28 | { |
||||
29 | $router = new Router(); |
||||
30 | |||||
31 | $router->addRoute([ |
||||
32 | 'App1' => [ |
||||
33 | 'module' => 'App', |
||||
34 | 'controller' => 'Index', |
||||
35 | 'view' => 'home', |
||||
36 | ], |
||||
37 | ]); |
||||
38 | |||||
39 | $router->setIdentifiers('App', 'Index', 'home'); |
||||
40 | $router->match(); |
||||
41 | |||||
42 | $ctrl = $router->getController(); |
||||
43 | |||||
44 | $this->assertEquals("App\Index", get_class($ctrl)); |
||||
45 | } |
||||
46 | |||||
47 | /** |
||||
48 | * Tests if the router can create an instance of a class when the route does not exists |
||||
49 | * |
||||
50 | * @return null |
||||
51 | */ |
||||
52 | public function testSimpleRouteMatchFail() |
||||
53 | { |
||||
54 | $router = new Router(); |
||||
55 | |||||
56 | $router->addRoute([ |
||||
57 | 'App1' => [ |
||||
58 | 'module' => 'MyApp', |
||||
59 | 'controller' => 'IndexController', |
||||
60 | 'view' => 'home', |
||||
61 | ], |
||||
62 | ]); |
||||
63 | |||||
64 | $router->setIdentifiers('App', 'Index', 'home'); |
||||
65 | |||||
66 | $errorObject = null; |
||||
67 | |||||
68 | try { |
||||
69 | $router->match(); |
||||
70 | } catch (\Exception $e) { |
||||
71 | $errorObject = ($e instanceof RouteNotFoundException); |
||||
72 | } finally { |
||||
73 | $this->assertTrue($errorObject, $e->getMessage()); |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||||
74 | } |
||||
75 | } |
||||
76 | |||||
77 | /** |
||||
78 | * Tests if the router can create an instance of a class by a default route |
||||
79 | * |
||||
80 | * @return null |
||||
81 | */ |
||||
82 | public function testDefaultRouteMatch() |
||||
83 | { |
||||
84 | $router = new Router(); |
||||
85 | |||||
86 | $router->addRoute([ |
||||
87 | 'AppRoute1' => [ |
||||
88 | 'module' => 'App', |
||||
89 | 'controller' => 'Index', |
||||
90 | 'view' => 'home', |
||||
91 | ], |
||||
92 | ]); |
||||
93 | |||||
94 | $router->addRoute([ |
||||
95 | 'AppRoute2' => [ |
||||
96 | 'module' => 'App', |
||||
97 | 'controller' => 'Index2', |
||||
98 | 'view' => 'home', |
||||
99 | ], |
||||
100 | ]); |
||||
101 | |||||
102 | $router->setDefaults('App', 'Index', 'home'); |
||||
103 | $router->match(); |
||||
104 | $ctrl = $router->getController(); |
||||
105 | |||||
106 | $this->assertEquals("App\Index", get_class($ctrl)); |
||||
107 | |||||
108 | $router->setIdentifiers('App', 'Index2', 'home'); |
||||
109 | $router->match(); |
||||
110 | $ctrl = $router->getController(); |
||||
111 | |||||
112 | $this->assertEquals("App\Index2", get_class($ctrl)); |
||||
113 | } |
||||
114 | |||||
115 | /** |
||||
116 | * Tests if the router can create an instance of a class with non-default class name builder |
||||
117 | * |
||||
118 | * @return null |
||||
119 | */ |
||||
120 | public function testSimpleRouteMatchWithParticularName() |
||||
121 | { |
||||
122 | $router = new Router(); |
||||
123 | |||||
124 | $router->addRoute([ |
||||
125 | 'App3' => [ |
||||
126 | 'module' => 'App', |
||||
127 | 'controller' => 'Index', |
||||
128 | 'view' => 'about', |
||||
129 | ], |
||||
130 | ]); |
||||
131 | |||||
132 | $router->setIdentifiers('App', 'Index', 'about'); |
||||
133 | |||||
134 | $router->setClassNameBuilder(function ($module, $class) { |
||||
135 | return "\\$module\Controller\\$class"; |
||||
136 | }); |
||||
137 | |||||
138 | $router->match(); |
||||
139 | |||||
140 | $ctrl = $router->getController(); |
||||
141 | |||||
142 | $this->assertEquals("App\Controller\Index", get_class($ctrl)); |
||||
143 | } |
||||
144 | |||||
145 | /** |
||||
146 | * Tests method execution behaviour handled by the a module |
||||
147 | * |
||||
148 | * @return null |
||||
149 | */ |
||||
150 | public function testModuleAndControllerComposition() |
||||
151 | { |
||||
152 | $router = new Router(); |
||||
153 | |||||
154 | $router->addRoute([ |
||||
155 | 'App4' => [ |
||||
156 | 'module' => 'App', |
||||
157 | 'controller' => 'Index', |
||||
158 | 'view' => 'about', |
||||
159 | ], |
||||
160 | ]); |
||||
161 | |||||
162 | $router->setIdentifiers('App', 'Index', 'about'); |
||||
163 | |||||
164 | $router->setClassNameBuilder(function ($module, $class) { |
||||
165 | return "\\$module\Controller\\$class"; |
||||
166 | }); |
||||
167 | |||||
168 | $router->match(); |
||||
169 | |||||
170 | # inject the module dependency to the controller |
||||
171 | $router->getController()->setModule(ModuleFactory::create("App")); |
||||
0 ignored issues
–
show
Drone\Mvc\ModuleFactory::create('App') of type null is incompatible with the type Drone\Mvc\AbstractModule expected by parameter $module of Drone\Mvc\AbstractController::setModule() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() Are you sure the usage of
Drone\Mvc\ModuleFactory::create('App') targeting Drone\Mvc\ModuleFactory::create() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||
172 | |||||
173 | $this->assertNotTrue($router->getController()->getModule()->executionIsAllowed()); |
||||
0 ignored issues
–
show
Are you sure the usage of
$router->getController()...)->executionIsAllowed() targeting Drone\Mvc\AbstractModule::executionIsAllowed() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||
174 | |||||
175 | $errorObject = null; |
||||
176 | |||||
177 | try { |
||||
178 | $router->run(); |
||||
179 | } catch (\Exception $e) { |
||||
180 | $errorObject = ($e instanceof MethodExecutionNotAllowedException); |
||||
181 | } finally { |
||||
182 | $this->assertTrue($errorObject, $e->getMessage()); |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
183 | } |
||||
184 | |||||
185 | $router->getController()->getModule()->allowExecution(); |
||||
186 | |||||
187 | # returns the result of the method execution in the matched controller |
||||
188 | $result = $router->run(); |
||||
189 | |||||
190 | $expected = ["foo" => "bar"]; |
||||
191 | $this->assertSame($expected, $result); |
||||
192 | } |
||||
193 | } |
||||
194 | |||||
195 | /* |
||||
196 | |-------------------------------------------------------------------------- |
||||
197 | | Controller classes |
||||
198 | |-------------------------------------------------------------------------- |
||||
199 | | |
||||
200 | | This are simple controllers implementing AbstractController. |
||||
201 | | |
||||
202 | */ |
||||
203 | |||||
204 | namespace App; |
||||
205 | |||||
206 | use Drone\Mvc\AbstractController; |
||||
207 | |||||
208 | class Index extends AbstractController |
||||
209 | { |
||||
210 | public function home() |
||||
211 | { |
||||
212 | return []; |
||||
213 | } |
||||
214 | } |
||||
215 | |||||
216 | class Index2 extends AbstractController |
||||
217 | { |
||||
218 | public function home() |
||||
219 | { |
||||
220 | return []; |
||||
221 | } |
||||
222 | } |
||||
223 | |||||
224 | /* |
||||
225 | |-------------------------------------------------------------------------- |
||||
226 | | Another Controller class |
||||
227 | |-------------------------------------------------------------------------- |
||||
228 | | |
||||
229 | | This is a simple controller implementing AbstractController. In order to |
||||
230 | | build a framework behavior, we need all classes inside Controller namespace. |
||||
231 | | |
||||
232 | */ |
||||
233 | |||||
234 | namespace App\Controller; |
||||
235 | |||||
236 | use Drone\Mvc\AbstractController; |
||||
237 | |||||
238 | class Index extends AbstractController |
||||
239 | { |
||||
240 | public function about() |
||||
241 | { |
||||
242 | return ['foo' => 'bar']; |
||||
243 | } |
||||
244 | } |
||||
245 | |||||
246 | /* |
||||
247 | |-------------------------------------------------------------------------- |
||||
248 | | Module Class |
||||
249 | |-------------------------------------------------------------------------- |
||||
250 | | |
||||
251 | | Each module could have a Module class that handles method execution. It's |
||||
252 | | useful for execute some code before method execution or for stop it. |
||||
253 | | |
||||
254 | */ |
||||
255 | |||||
256 | namespace App; |
||||
257 | |||||
258 | use Drone\Mvc\AbstractModule; |
||||
259 | |||||
260 | class Module extends AbstractModule |
||||
261 | { |
||||
262 | public function init() |
||||
263 | { |
||||
264 | # disallowing method execution |
||||
265 | $this->disallowExecution(); |
||||
266 | } |
||||
267 | } |
||||
268 |