Completed
Push — master ( bb320a...c73ce7 )
by Pierre
02:14
created

TKernel::setActionAnnotations()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 3
b 0
f 0
nc 5
nop 0
dl 0
loc 10
ccs 8
cts 9
cp 0.8889
crap 4.0218
rs 10
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 26
    public function getService(string $serviceName)
159
    {
160 26
        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 2
    protected function init(string $env, string $path)
171
    {
172 2
        $this->env = $env;
173 2
        $this->path = $path;
174 2
        $this->error = true;
175 2
        $this->errorCode = Response::HTTP_NOT_FOUND;
176 2
        $this->errorMsg = 'Not Found';
177 2
        $this->setPath($path);
178 2
        $this->setConfig();
179 2
        $this->setContainer();
180 2
        $this->setRequest();
181 2
        $this->setResponse();
182 2
        $this->setLogger();
183 2
        $this->setRouter();
184 2
        $this->className = '';
185 2
        $this->actions = [];
186 2
        $this->action = '';
187 2
        $this->actionAnnotations = '';
188
    }
189
190
    /**
191
     * execute controller action in middleware core closure
192
     *
193
     * @return void
194
     */
195 3
    protected function execute(...$args)
196
    {
197 3
        if ($this->isValidAction() && is_object($this->controller)) {
198 2
            $resExec = $this->invokeAction($args);
199 2
            $this->error = ($resExec === false);
200 2
            $this->errorCode = ($this->error)
201 1
                ? Response::HTTP_INTERNAL_SERVER_ERROR
202 1
                : Response::HTTP_OK;
203 2
            $this->errorMsg = sprintf(
204 2
                'Execute %s',
205 2
                ($this->error) ? 'failed' : 'successfully'
206
            );
207 2
            $this->logger->debug($this->errorMsg);
208
        } else {
209 1
            $this->error = true;
210 1
            $this->errorMsg = 'Unknown endpoint';
211 1
            $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 1
    protected function invokeAction(...$args)
223
    {
224 1
        return call_user_func_array([$this->controller, $this->action], $args);
225
    }
226
227
    /**
228
     * return controller instance
229
     *
230
     * @return mixed
231
     */
232 3
    protected function getController()
233
    {
234 3
        return $this->controller;
235
    }
236
237
    /**
238
     * set middlewares from config then run before/after layers around core
239
     *
240
     */
241 1
    protected function setMiddleware()
242
    {
243 1
        $middlwaresClasses = $this->config->getSettings(
244 1
            Config::_MIDDLEWARES
245
        );
246 1
        foreach ($middlwaresClasses as $className => $middlewareParams) {
247 1
            $this->middlewares[$className] = new $className;
248
        }
249 1
        (new Middleware())->layer($this->middlewares)->peel(
250 1
            $this->container,
251 1
            function ($container) {
252 1
                $this->execute(null);
253 1
                return $container;
254 1
            }
255
        );
256
    }
257
258
    /**
259
     * set action annotations for runnig action
260
     *
261
     */
262 1
    protected function setActionAnnotations()
263
    {
264 1
        if ($this->isValidAction()) {
265 1
            $refMethod = $this->reflector->getMethod($this->action);
266 1
            $docComment = $refMethod->getDocComment();
267 1
            $hasComment = (false === $refMethod && false === $docComment);
268 1
            $this->actionAnnotations = ($hasComment)
0 ignored issues
show
Documentation Bug introduced by
It seems like $hasComment ? '' : $docComment 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...
269
                ? ''
270 1
                : $docComment;
271 1
            unset($refMethod, $docComment, $hasComment);
272
        }
273
    }
274
275
    /**
276
     * return action docblock as string
277
     *
278
     * @return string
279
     */
280 1
    protected function getActionAnnotations(): string
281
    {
282 1
        return $this->actionAnnotations;
283
    }
284
285
    /**
286
     * return true if action is valid
287
     *
288
     * @return boolean
289
     */
290 5
    protected function isValidAction(): bool
291
    {
292 5
        return in_array($this->action, $this->actions);
293
    }
294
295
    /**
296
     * instanciate controller for a classname
297
     *
298
     * @return void
299
     */
300 4
    protected function setController()
301
    {
302 4
        $this->controller = new $this->className($this->container);
303
    }
304
305
    /**
306
     * set relflector on class name
307
     *
308
     */
309 8
    protected function setReflector()
310
    {
311 8
        $this->reflector = new \ReflectionClass($this->className);
312
    }
313
314
    /**
315
     * return reflexion class on current classname
316
     *
317
     * @return ReflectionClass
318
     */
319 1
    protected function getReflector(): ReflectionClass
320
    {
321 1
        return $this->reflector;
322
    }
323
324
    /**
325
     * set controller action from router groups and request method
326
     *
327
     * @param array $routerGroups
328
     * @param string $reqMethod
329
     * @return void
330
     */
331 8
    protected function setAction(array $routerGroups, string $reqMethod)
332
    {
333 8
        if ($reqMethod == Request::METHOD_OPTIONS) {
334 1
            $this->action = Kernel::_PREFLIGHT;
335 1
            return;
336
        }
337 8
        $this->action = isset($routerGroups[1])
338 7
            ? strtolower($routerGroups[1])
339 2
            : '';
340
    }
341
342
    /**
343
     * return core controller action
344
     *
345
     * @return string
346
     */
347 1
    protected function getAction(): string
348
    {
349 1
        return $this->action;
350
    }
351
352
    /**
353
     * return true if request methof is OPTIONS
354
     *
355
     * @return boolean
356
     */
357 1
    protected function isPreflight(string $reqMethod): bool
358
    {
359 1
        return $reqMethod == Request::METHOD_OPTIONS;
360
    }
361
362
    /**
363
     * set public final actions from controller class name
364
     *
365
     */
366 8
    protected function setActions()
367
    {
368 8
        $methods = $this->getFinalMethods();
369 8
        $methodsName = array_map(function ($method) {
370 8
            return $method->name;
371 8
        }, $methods);
372 8
        $this->actions = array_merge($methodsName, [Kernel::_PREFLIGHT]);
373
    }
374
375
    /**
376
     * get final methods for the current classname
377
     *
378
     * @return array
379
     */
380 1
    protected function getFinalMethods(): array
381
    {
382 1
        return $this->getReflector()->getMethods(
383 1
            \ReflectionMethod::IS_FINAL
384
        );
385
    }
386
387
    /**
388
     * return public final actions from controller class name
389
     *
390
     */
391 4
    protected function getActions(): array
392
    {
393 4
        return $this->actions;
394
    }
395
396
    /**
397
     * set service container
398
     *
399
     */
400 1
    protected function setContainer()
401
    {
402 1
        $this->container = new \App\Container(
403 1
            $this->config->getSettings(Config::_SERVICES)
404
        );
405
    }
406
407
    /**
408
     * get service container
409
     *
410
     */
411 2
    protected function getContainer(): Container
412
    {
413 2
        return $this->container;
414
    }
415
416
    /**
417
     * set request
418
     *
419
     */
420 1
    protected function setRequest()
421
    {
422 1
        $this->req = $this->getService(\App\Http\Request::class);
423
    }
424
425
    /**
426
     * return request
427
     *
428
     */
429 1
    protected function getRequest(): Request
430
    {
431 1
        return $this->req;
432
    }
433
434
    /**
435
     * set response
436
     *
437
     */
438 1
    protected function setResponse()
439
    {
440 1
        $this->res = $this->getService(\App\Http\Response::class);
441
    }
442
443
    /**
444
     * return reponse
445
     *
446
     */
447 1
    protected function getResponse(): Response
448
    {
449 1
        return $this->res;
450
    }
451
452
    /**
453
     * set router
454
     *
455
     */
456 1
    protected function setRouter()
457
    {
458 1
        $this->router = $this->getService(\App\Http\Router::class);
459
    }
460
461
    /**
462
     * return router
463
     *
464
     */
465 1
    protected function getRouter(): Router
466
    {
467 1
        return $this->router;
468
    }
469
470
    /**
471
     * set controller class name
472
     *
473
     * @param array $routerGroups
474
     */
475 8
    protected function setClassname(array $routerGroups)
476
    {
477 8
        $this->className = $this->nameSpace
478 8
            . implode(
479 8
                '\\',
480 8
                array_map('ucfirst', explode('/', $routerGroups[0]))
481
            );
482
    }
483
484
    /**
485
     * set controller class name
486
     *
487
     */
488 4
    protected function getClassname(): string
489
    {
490 4
        return $this->className;
491
    }
492
493
    /**
494
     * set app config
495
     *
496
     */
497 1
    protected function setConfig()
498
    {
499 1
        $this->config = new Config(
500 1
            $this->env,
501 1
            $this->path . Kernel::PATH_CONFIG
502
        );
503
    }
504
505
    /**
506
     * returns config
507
     *
508
     * @return Config
509
     */
510 1
    protected function getConfig(): Config
511
    {
512 1
        return $this->config;
513
    }
514
515
    /**
516
     * set app logger
517
     *
518
     */
519 1
    protected function setLogger()
520
    {
521 1
        $this->logger = $this->getService(\Monolog\Logger::class);
522 1
        $handlers = $this->logger->getHandlers();
523 1
        foreach ($handlers as $handlder) {
524 1
            if ($handlder instanceof \Monolog\Handler\RotatingFileHandler) {
525 1
                $patchedHandlder = $handlder;
526 1
                $patchedHandlder->setFilenameFormat(
527 1
                    '{date}-{filename}',
528 1
                    'Y-m-d'
529
                );
530 1
                $this->logger->popHandler();
531 1
                $this->logger->pushHandler($patchedHandlder);
532
            }
533
        }
534 1
        unset($handlers);
535
        //\Monolog\ErrorHandler::register($this->logger);
536
    }
537
538
    /**
539
     * return monolog logger with handlers set
540
     *
541
     * @return Logger
542
     */
543 1
    protected function getLogger(): Logger
544
    {
545 1
        return $this->logger;
546
    }
547
548
    /**
549
     * set app root path
550
     *
551
     */
552 1
    protected function setPath(string $path)
553
    {
554 1
        $this->path = $path;
555
    }
556
557
    /**
558
     * return kernel run path
559
     *
560
     * @return string
561
     */
562 2
    protected function getPath(): string
563
    {
564 2
        return $this->path;
565
    }
566
567
    /**
568
     * set kernel error
569
     *
570
     */
571 2
    protected function setError(bool $error)
572
    {
573 2
        $this->error = $error;
574
    }
575
576
    /**
577
     * return kernel error
578
     *
579
     */
580 5
    protected function getError(): bool
581
    {
582 5
        return $this->error;
583
    }
584
585
    /**
586
     * return kernel error message
587
     *
588
     */
589 3
    protected function getErrorMsg(): string
590
    {
591 3
        return $this->errorMsg;
592
    }
593
}
594