Completed
Branch master (b52e58)
by Pierre
03:02 queued 37s
created

TKernel   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 573
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 122
c 1
b 0
f 0
dl 0
loc 573
rs 8.64
wmc 47

37 Methods

Rating   Name   Duplication   Size   Complexity  
A execute() 0 17 5
A init() 0 18 1
A getService() 0 3 1
A invokeAction() 0 3 1
A getController() 0 3 1
A setLogger() 0 16 3
A setRouter() 0 3 1
A setResponse() 0 3 1
A getRouter() 0 3 1
A getPath() 0 3 1
A isPreflight() 0 3 1
A setController() 0 3 1
A setRequest() 0 3 1
A getError() 0 3 1
A setError() 0 3 1
A getConfig() 0 3 1
A getResponse() 0 3 1
A setClassname() 0 6 1
A isValidAction() 0 3 1
A setAction() 0 9 3
A getLogger() 0 3 1
A getContainer() 0 3 1
A setReflector() 0 3 1
A setActionAnnotations() 0 6 2
A getActionAnnotations() 0 3 1
A getRequest() 0 3 1
A getActions() 0 3 1
A getFinalMethods() 0 4 1
A getClassname() 0 3 1
A getReflector() 0 3 1
A setActions() 0 7 1
A setPath() 0 3 1
A getErrorMsg() 0 3 1
A setMiddleware() 0 13 2
A setConfig() 0 5 1
A getAction() 0 3 1
A setContainer() 0 4 1

How to fix   Complexity   

Complex Class

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
2
3
namespace App\Reuse;
4
5
use App\Kernel;
6
use App\Config;
7
use App\Container;
8
use App\Http\Request;
9
use App\Http\Response;
10
use App\Http\Router;
11
use App\Http\Middleware;
12
use Monolog\Logger;
13
use \ReflectionClass;
14
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)
196
    {
197
        if ($this->isValidAction() && is_object($this->controller)) {
198
            $resExec = $this->invokeAction($args);
199
            $this->error = ($resExec === false);
200
            $this->errorCode = ($this->error)
201
                ? Response::HTTP_INTERNAL_SERVER_ERROR
202
                : Response::HTTP_OK;
203
            $this->errorMsg = sprintf(
204
                'Execute %s',
205
                ($this->error) ? 'failed' : 'successfully'
206
            );
207
            $this->logger->debug($this->errorMsg);
208
        } else {
209
            $this->error = true;
210
            $this->errorMsg = 'Unknown endpoint';
211
            $this->errorCode = Response::HTTP_BAD_REQUEST;
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)
223
    {
224
        return call_user_func_array([$this->controller, $this->action], $args);
225
    }
226
227
    /**
228
     * return controller instance
229
     *
230
     * @return mixed
231
     */
232
    protected function getController()
233
    {
234
        return $this->controller;
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
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->reflector->getMet...ction)->getDocComment() can also be of type boolean. However, the property $actionAnnotations is declared as type string. Maybe add an additional type check?

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 the id property of an instance of the Account 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.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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()
516
    {
517
        $this->logger = $this->getService(\Monolog\Logger::class);
518
        $handlers = $this->logger->getHandlers();
519
        foreach ($handlers as $handlder) {
520
            if ($handlder instanceof \Monolog\Handler\RotatingFileHandler) {
521
                $patchedHandlder = $handlder;
522
                $patchedHandlder->setFilenameFormat(
523
                    '{date}-{filename}',
524
                    'Y-m-d'
525
                );
526
                $this->logger->popHandler();
527
                $this->logger->pushHandler($patchedHandlder);
528
            }
529
        }
530
        unset($handlers);
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
559
    {
560
        return $this->path;
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
577
    {
578
        return $this->error;
579
    }
580
581
    /**
582
     * return kernel error message
583
     *
584
     */
585
    protected function getErrorMsg(): string
586
    {
587
        return $this->errorMsg;
588
    }
589
}
590