Completed
Branch master (bb320a)
by Pierre
03:04 queued 48s
created

TKernel::setActionAnnotations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.0416

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 2
b 0
f 0
nc 3
nop 0
dl 0
loc 7
ccs 5
cts 6
cp 0.8333
crap 3.0416
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
            $this->actionAnnotations = (false === $refMethod)
0 ignored issues
show
Documentation Bug introduced by
It seems like false === $refMethod ? '...Method->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...
267
                ? ''
268 1
                : $refMethod->getDocComment();
269
        }
270
    }
271
272
    /**
273
     * return action docblock as string
274
     *
275
     * @return string
276
     */
277 1
    protected function getActionAnnotations(): string
278
    {
279 1
        return $this->actionAnnotations;
280
    }
281
282
    /**
283
     * return true if action is valid
284
     *
285
     * @return boolean
286
     */
287 5
    protected function isValidAction(): bool
288
    {
289 5
        return in_array($this->action, $this->actions);
290
    }
291
292
    /**
293
     * instanciate controller for a classname
294
     *
295
     * @return void
296
     */
297 4
    protected function setController()
298
    {
299 4
        $this->controller = new $this->className($this->container);
300
    }
301
302
    /**
303
     * set relflector on class name
304
     *
305
     */
306 8
    protected function setReflector()
307
    {
308 8
        $this->reflector = new \ReflectionClass($this->className);
309
    }
310
311
    /**
312
     * return reflexion class on current classname
313
     *
314
     * @return ReflectionClass
315
     */
316 1
    protected function getReflector(): ReflectionClass
317
    {
318 1
        return $this->reflector;
319
    }
320
321
    /**
322
     * set controller action from router groups and request method
323
     *
324
     * @param array $routerGroups
325
     * @param string $reqMethod
326
     * @return void
327
     */
328 8
    protected function setAction(array $routerGroups, string $reqMethod)
329
    {
330 8
        if ($reqMethod == Request::METHOD_OPTIONS) {
331 1
            $this->action = Kernel::_PREFLIGHT;
332 1
            return;
333
        }
334 8
        $this->action = isset($routerGroups[1])
335 7
            ? strtolower($routerGroups[1])
336 2
            : '';
337
    }
338
339
    /**
340
     * return core controller action
341
     *
342
     * @return string
343
     */
344 1
    protected function getAction(): string
345
    {
346 1
        return $this->action;
347
    }
348
349
    /**
350
     * return true if request methof is OPTIONS
351
     *
352
     * @return boolean
353
     */
354 1
    protected function isPreflight(string $reqMethod): bool
355
    {
356 1
        return $reqMethod == Request::METHOD_OPTIONS;
357
    }
358
359
    /**
360
     * set public final actions from controller class name
361
     *
362
     */
363 8
    protected function setActions()
364
    {
365 8
        $methods = $this->getFinalMethods();
366 8
        $methodsName = array_map(function ($method) {
367 8
            return $method->name;
368 8
        }, $methods);
369 8
        $this->actions = array_merge($methodsName, [Kernel::_PREFLIGHT]);
370
    }
371
372
    /**
373
     * get final methods for the current classname
374
     *
375
     * @return array
376
     */
377 1
    protected function getFinalMethods(): array
378
    {
379 1
        return $this->getReflector()->getMethods(
380 1
            \ReflectionMethod::IS_FINAL
381
        );
382
    }
383
384
    /**
385
     * return public final actions from controller class name
386
     *
387
     */
388 4
    protected function getActions(): array
389
    {
390 4
        return $this->actions;
391
    }
392
393
    /**
394
     * set service container
395
     *
396
     */
397 1
    protected function setContainer()
398
    {
399 1
        $this->container = new \App\Container(
400 1
            $this->config->getSettings(Config::_SERVICES)
401
        );
402
    }
403
404
    /**
405
     * get service container
406
     *
407
     */
408 2
    protected function getContainer(): Container
409
    {
410 2
        return $this->container;
411
    }
412
413
    /**
414
     * set request
415
     *
416
     */
417 1
    protected function setRequest()
418
    {
419 1
        $this->req = $this->getService(\App\Http\Request::class);
420
    }
421
422
    /**
423
     * return request
424
     *
425
     */
426 1
    protected function getRequest(): Request
427
    {
428 1
        return $this->req;
429
    }
430
431
    /**
432
     * set response
433
     *
434
     */
435 1
    protected function setResponse()
436
    {
437 1
        $this->res = $this->getService(\App\Http\Response::class);
438
    }
439
440
    /**
441
     * return reponse
442
     *
443
     */
444 1
    protected function getResponse(): Response
445
    {
446 1
        return $this->res;
447
    }
448
449
    /**
450
     * set router
451
     *
452
     */
453 1
    protected function setRouter()
454
    {
455 1
        $this->router = $this->getService(\App\Http\Router::class);
456
    }
457
458
    /**
459
     * return router
460
     *
461
     */
462 1
    protected function getRouter(): Router
463
    {
464 1
        return $this->router;
465
    }
466
467
    /**
468
     * set controller class name
469
     *
470
     * @param array $routerGroups
471
     */
472 8
    protected function setClassname(array $routerGroups)
473
    {
474 8
        $this->className = $this->nameSpace
475 8
            . implode(
476 8
            '\\',
477 8
            array_map('ucfirst', explode('/', $routerGroups[0]))
478
        );
479
    }
480
481
    /**
482
     * set controller class name
483
     *
484
     */
485 4
    protected function getClassname(): string
486
    {
487 4
        return $this->className;
488
    }
489
490
    /**
491
     * set app config
492
     *
493
     */
494 1
    protected function setConfig()
495
    {
496 1
        $this->config = new Config(
497 1
            $this->env,
498 1
            $this->path . Kernel::PATH_CONFIG
499
        );
500
    }
501
502
    /**
503
     * returns config
504
     *
505
     * @return Config
506
     */
507 1
    protected function getConfig(): Config
508
    {
509 1
        return $this->config;
510
    }
511
512
    /**
513
     * set app logger
514
     *
515
     */
516 1
    protected function setLogger()
517
    {
518 1
        $this->logger = $this->getService(\Monolog\Logger::class);
519 1
        $handlers = $this->logger->getHandlers();
520 1
        foreach ($handlers as $handlder) {
521 1
            if ($handlder instanceof \Monolog\Handler\RotatingFileHandler) {
522 1
                $patchedHandlder = $handlder;
523 1
                $patchedHandlder->setFilenameFormat(
524 1
                    '{date}-{filename}',
525 1
                    'Y-m-d'
526
                );
527 1
                $this->logger->popHandler();
528 1
                $this->logger->pushHandler($patchedHandlder);
529
            }
530
        }
531 1
        unset($handlers);
532
        //\Monolog\ErrorHandler::register($this->logger);
533
    }
534
535
    /**
536
     * return monolog logger with handlers set
537
     *
538
     * @return Logger
539
     */
540 1
    protected function getLogger(): Logger
541
    {
542 1
        return $this->logger;
543
    }
544
545
    /**
546
     * set app root path
547
     *
548
     */
549 1
    protected function setPath(string $path)
550
    {
551 1
        $this->path = $path;
552
    }
553
554
    /**
555
     * return kernel run path
556
     *
557
     * @return string
558
     */
559 2
    protected function getPath(): string
560
    {
561 2
        return $this->path;
562
    }
563
564
    /**
565
     * set kernel error
566
     *
567
     */
568 2
    protected function setError(bool $error)
569
    {
570 2
        $this->error = $error;
571
    }
572
573
    /**
574
     * return kernel error
575
     *
576
     */
577 5
    protected function getError(): bool
578
    {
579 5
        return $this->error;
580
    }
581
582
    /**
583
     * return kernel error message
584
     *
585
     */
586 3
    protected function getErrorMsg(): string
587
    {
588 3
        return $this->errorMsg;
589
    }
590
}
591