Total Complexity | 47 |
Total Lines | 573 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like TKernel often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use TKernel, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | trait TKernel |
||
16 | { |
||
17 | |||
18 | /** |
||
19 | * app path |
||
20 | * |
||
21 | * @var string |
||
22 | */ |
||
23 | protected $path; |
||
24 | |||
25 | /** |
||
26 | * app environment |
||
27 | * |
||
28 | * @var string |
||
29 | */ |
||
30 | protected $env; |
||
31 | |||
32 | /** |
||
33 | * app config |
||
34 | * |
||
35 | * @var Config |
||
36 | */ |
||
37 | protected $config; |
||
38 | |||
39 | /** |
||
40 | * service container |
||
41 | * |
||
42 | * @var Container |
||
43 | */ |
||
44 | protected $container; |
||
45 | |||
46 | /** |
||
47 | * monolog logger |
||
48 | * |
||
49 | * @var Logger |
||
50 | */ |
||
51 | protected $logger; |
||
52 | |||
53 | /** |
||
54 | * app request |
||
55 | * |
||
56 | * @var Request |
||
57 | */ |
||
58 | protected $req; |
||
59 | |||
60 | /** |
||
61 | * app response |
||
62 | * |
||
63 | * @var Response |
||
64 | */ |
||
65 | protected $res; |
||
66 | |||
67 | /** |
||
68 | * app router |
||
69 | * |
||
70 | * @var Router |
||
71 | */ |
||
72 | protected $router; |
||
73 | |||
74 | /** |
||
75 | * ctrl class name |
||
76 | * |
||
77 | * @var string |
||
78 | */ |
||
79 | protected $className; |
||
80 | |||
81 | /** |
||
82 | * controller namespace |
||
83 | * |
||
84 | * @var string |
||
85 | */ |
||
86 | protected $nameSpace; |
||
87 | |||
88 | /** |
||
89 | * controller instance |
||
90 | * |
||
91 | * @var mixed |
||
92 | */ |
||
93 | protected $controller; |
||
94 | |||
95 | /** |
||
96 | * reflection class instance |
||
97 | * |
||
98 | * @var ReflectionClass |
||
99 | */ |
||
100 | protected $reflector; |
||
101 | |||
102 | /** |
||
103 | * controller actions |
||
104 | * |
||
105 | * @var array |
||
106 | */ |
||
107 | protected $actions; |
||
108 | |||
109 | /** |
||
110 | * controller action |
||
111 | * |
||
112 | * @var string |
||
113 | */ |
||
114 | protected $action; |
||
115 | |||
116 | /** |
||
117 | * action annotations |
||
118 | * |
||
119 | * @var string |
||
120 | */ |
||
121 | protected $actionAnnotations; |
||
122 | |||
123 | /** |
||
124 | * middlewares stack |
||
125 | * |
||
126 | * @var array |
||
127 | */ |
||
128 | protected $middlewares; |
||
129 | |||
130 | /** |
||
131 | * run error |
||
132 | * |
||
133 | * @var Boolean |
||
134 | */ |
||
135 | protected $error; |
||
136 | |||
137 | /** |
||
138 | * http status error code |
||
139 | * |
||
140 | * @var int |
||
141 | */ |
||
142 | protected $errorCode; |
||
143 | |||
144 | /** |
||
145 | * error message |
||
146 | * |
||
147 | * @var string |
||
148 | */ |
||
149 | protected $errorMsg; |
||
150 | |||
151 | /** |
||
152 | * return service container for service name |
||
153 | * |
||
154 | * @param string $serviceName |
||
155 | * @throws Exception |
||
156 | * @return object |
||
157 | */ |
||
158 | public function getService(string $serviceName) |
||
159 | { |
||
160 | return $this->container->getService($serviceName); |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * init kernel |
||
165 | * |
||
166 | * @param string $env |
||
167 | * @param string $path |
||
168 | * @return void |
||
169 | */ |
||
170 | protected function init(string $env, string $path) |
||
171 | { |
||
172 | $this->env = $env; |
||
173 | $this->path = $path; |
||
174 | $this->error = true; |
||
175 | $this->errorCode = Response::HTTP_NOT_FOUND; |
||
176 | $this->errorMsg = 'Not Found'; |
||
177 | $this->setPath($path); |
||
178 | $this->setConfig(); |
||
179 | $this->setContainer(); |
||
180 | $this->setRequest(); |
||
181 | $this->setResponse(); |
||
182 | $this->setLogger(); |
||
183 | $this->setRouter(); |
||
184 | $this->className = ''; |
||
185 | $this->actions = []; |
||
186 | $this->action = ''; |
||
187 | $this->actionAnnotations = ''; |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * execute controller action in middleware core closure |
||
192 | * |
||
193 | * @return void |
||
194 | */ |
||
195 | protected function execute(...$args) |
||
212 | } |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * invoke action from a controller an return exec code. |
||
217 | * for testing purpose return retValue if false |
||
218 | * |
||
219 | * @param boolean $forceRetValue |
||
220 | * @return mixed |
||
221 | */ |
||
222 | protected function invokeAction(...$args) |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * return controller instance |
||
229 | * |
||
230 | * @return mixed |
||
231 | */ |
||
232 | protected function getController() |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * set middlewares from config then run before/after layers around core |
||
239 | * |
||
240 | */ |
||
241 | protected function setMiddleware() |
||
242 | { |
||
243 | $middlwaresClasses = $this->config->getSettings( |
||
244 | Config::_MIDDLEWARES |
||
245 | ); |
||
246 | foreach ($middlwaresClasses as $className => $middlewareParams) { |
||
247 | $this->middlewares[$className] = new $className; |
||
248 | } |
||
249 | (new Middleware())->layer($this->middlewares)->peel( |
||
250 | $this->container, |
||
251 | function ($container) { |
||
252 | $this->execute(null); |
||
253 | return $container; |
||
254 | } |
||
255 | ); |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * set action annotations for runnig action |
||
260 | * |
||
261 | */ |
||
262 | protected function setActionAnnotations() |
||
263 | { |
||
264 | if ($this->isValidAction()) { |
||
265 | $this->actionAnnotations = $this->reflector |
||
|
|||
266 | ->getMethod($this->action) |
||
267 | ->getDocComment(); |
||
268 | } |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * return action docblock as string |
||
273 | * |
||
274 | * @return string |
||
275 | */ |
||
276 | protected function getActionAnnotations(): string |
||
277 | { |
||
278 | return $this->actionAnnotations; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * return true if action is valid |
||
283 | * |
||
284 | * @return boolean |
||
285 | */ |
||
286 | protected function isValidAction(): bool |
||
287 | { |
||
288 | return in_array($this->action, $this->actions); |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * instanciate controller for a classname |
||
293 | * |
||
294 | * @return void |
||
295 | */ |
||
296 | protected function setController() |
||
297 | { |
||
298 | $this->controller = new $this->className($this->container); |
||
299 | } |
||
300 | |||
301 | /** |
||
302 | * set relflector on class name |
||
303 | * |
||
304 | */ |
||
305 | protected function setReflector() |
||
306 | { |
||
307 | $this->reflector = new \ReflectionClass($this->className); |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * return reflexion class on current classname |
||
312 | * |
||
313 | * @return ReflectionClass |
||
314 | */ |
||
315 | protected function getReflector(): ReflectionClass |
||
316 | { |
||
317 | return $this->reflector; |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * set controller action from router groups and request method |
||
322 | * |
||
323 | * @param array $routerGroups |
||
324 | * @param string $reqMethod |
||
325 | * @return void |
||
326 | */ |
||
327 | protected function setAction(array $routerGroups, string $reqMethod) |
||
328 | { |
||
329 | if ($reqMethod == Request::METHOD_OPTIONS) { |
||
330 | $this->action = Kernel::_PREFLIGHT; |
||
331 | return; |
||
332 | } |
||
333 | $this->action = isset($routerGroups[1]) |
||
334 | ? strtolower($routerGroups[1]) |
||
335 | : ''; |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * return core controller action |
||
340 | * |
||
341 | * @return string |
||
342 | */ |
||
343 | protected function getAction(): string |
||
344 | { |
||
345 | return $this->action; |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * return true if request methof is OPTIONS |
||
350 | * |
||
351 | * @return boolean |
||
352 | */ |
||
353 | protected function isPreflight(string $reqMethod): bool |
||
354 | { |
||
355 | return $reqMethod == Request::METHOD_OPTIONS; |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * set public final actions from controller class name |
||
360 | * |
||
361 | */ |
||
362 | protected function setActions() |
||
363 | { |
||
364 | $methods = $this->getFinalMethods(); |
||
365 | $methodsName = array_map(function ($method) { |
||
366 | return $method->name; |
||
367 | }, $methods); |
||
368 | $this->actions = array_merge($methodsName, [Kernel::_PREFLIGHT]); |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * get final methods for the current classname |
||
373 | * |
||
374 | * @return array |
||
375 | */ |
||
376 | protected function getFinalMethods(): array |
||
377 | { |
||
378 | return $this->getReflector()->getMethods( |
||
379 | \ReflectionMethod::IS_FINAL |
||
380 | ); |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * return public final actions from controller class name |
||
385 | * |
||
386 | */ |
||
387 | protected function getActions(): array |
||
388 | { |
||
389 | return $this->actions; |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * set service container |
||
394 | * |
||
395 | */ |
||
396 | protected function setContainer() |
||
397 | { |
||
398 | $this->container = new \App\Container( |
||
399 | $this->config->getSettings(Config::_SERVICES) |
||
400 | ); |
||
401 | } |
||
402 | |||
403 | /** |
||
404 | * get service container |
||
405 | * |
||
406 | */ |
||
407 | protected function getContainer(): Container |
||
408 | { |
||
409 | return $this->container; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * set request |
||
414 | * |
||
415 | */ |
||
416 | protected function setRequest() |
||
417 | { |
||
418 | $this->req = $this->getService(\App\Http\Request::class); |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * return request |
||
423 | * |
||
424 | */ |
||
425 | protected function getRequest(): Request |
||
426 | { |
||
427 | return $this->req; |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * set response |
||
432 | * |
||
433 | */ |
||
434 | protected function setResponse() |
||
435 | { |
||
436 | $this->res = $this->getService(\App\Http\Response::class); |
||
437 | } |
||
438 | |||
439 | /** |
||
440 | * return reponse |
||
441 | * |
||
442 | */ |
||
443 | protected function getResponse(): Response |
||
444 | { |
||
445 | return $this->res; |
||
446 | } |
||
447 | |||
448 | /** |
||
449 | * set router |
||
450 | * |
||
451 | */ |
||
452 | protected function setRouter() |
||
453 | { |
||
454 | $this->router = $this->getService(\App\Http\Router::class); |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * return router |
||
459 | * |
||
460 | */ |
||
461 | protected function getRouter(): Router |
||
462 | { |
||
463 | return $this->router; |
||
464 | } |
||
465 | |||
466 | /** |
||
467 | * set controller class name |
||
468 | * |
||
469 | * @param array $routerGroups |
||
470 | */ |
||
471 | protected function setClassname(array $routerGroups) |
||
472 | { |
||
473 | $this->className = $this->nameSpace |
||
474 | . implode( |
||
475 | '\\', |
||
476 | array_map('ucfirst', explode('/', $routerGroups[0])) |
||
477 | ); |
||
478 | } |
||
479 | |||
480 | /** |
||
481 | * set controller class name |
||
482 | * |
||
483 | */ |
||
484 | protected function getClassname(): string |
||
485 | { |
||
486 | return $this->className; |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * set app config |
||
491 | * |
||
492 | */ |
||
493 | protected function setConfig() |
||
494 | { |
||
495 | $this->config = new Config( |
||
496 | $this->env, |
||
497 | $this->path . Kernel::PATH_CONFIG |
||
498 | ); |
||
499 | } |
||
500 | |||
501 | /** |
||
502 | * returns config |
||
503 | * |
||
504 | * @return Config |
||
505 | */ |
||
506 | protected function getConfig(): Config |
||
507 | { |
||
508 | return $this->config; |
||
509 | } |
||
510 | |||
511 | /** |
||
512 | * set app logger |
||
513 | * |
||
514 | */ |
||
515 | protected function setLogger() |
||
531 | //\Monolog\ErrorHandler::register($this->logger); |
||
532 | } |
||
533 | |||
534 | /** |
||
535 | * return monolog logger with handlers set |
||
536 | * |
||
537 | * @return Logger |
||
538 | */ |
||
539 | protected function getLogger(): Logger |
||
540 | { |
||
541 | return $this->logger; |
||
542 | } |
||
543 | |||
544 | /** |
||
545 | * set app root path |
||
546 | * |
||
547 | */ |
||
548 | protected function setPath(string $path) |
||
549 | { |
||
550 | $this->path = $path; |
||
551 | } |
||
552 | |||
553 | /** |
||
554 | * return kernel run path |
||
555 | * |
||
556 | * @return string |
||
557 | */ |
||
558 | protected function getPath(): string |
||
561 | } |
||
562 | |||
563 | /** |
||
564 | * set kernel error |
||
565 | * |
||
566 | */ |
||
567 | protected function setError(bool $error) |
||
568 | { |
||
569 | $this->error = $error; |
||
570 | } |
||
571 | |||
572 | /** |
||
573 | * return kernel error |
||
574 | * |
||
575 | */ |
||
576 | protected function getError(): bool |
||
579 | } |
||
580 | |||
581 | /** |
||
582 | * return kernel error message |
||
583 | * |
||
584 | */ |
||
585 | protected function getErrorMsg(): string |
||
586 | { |
||
587 | return $this->errorMsg; |
||
588 | } |
||
589 | } |
||
590 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.