Completed
Push — master ( e221c0...5a5b2e )
by Matze
05:22
created

AppKernel   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 95.45%

Importance

Changes 10
Bugs 0 Features 3
Metric Value
wmc 14
c 10
b 0
f 3
lcom 1
cbo 7
dl 0
loc 142
ccs 42
cts 44
cp 0.9545
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A handle() 0 16 2
A handleRequest() 0 23 3
A prepareResponse() 0 12 3
A applyResponseMiddleware() 0 8 2
A applyExceptionMiddleware() 0 11 3
1
<?php
2
3
namespace BrainExe\Core\Application;
4
5
use BrainExe\Annotations\Annotations\Inject;
6
use BrainExe\Annotations\Annotations\Service;
7
use BrainExe\Core\Middleware\MiddlewareInterface;
8
use Throwable;
9
use Exception;
10
use Generator;
11
use Symfony\Component\HttpFoundation\JsonResponse;
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\Response;
14
use Symfony\Component\HttpKernel\HttpKernelInterface;
15
16
/**
17
 * @Service(public=true)
18
 */
19
class AppKernel implements HttpKernelInterface
20
{
21
22
    /**
23
     * @var ControllerResolver
24
     */
25
    private $resolver;
26
27
    /**
28
     * @var SerializedRouteCollection
29
     */
30
    private $routes;
31
32
    /**
33
     * @var UrlMatcher
34
     */
35
    private $urlMatcher;
36
37
    /**
38
     * @var MiddlewareInterface[]
39
     */
40
    private $middlewares;
41
42
    /**
43
     * @Inject({
44
     *     "@ControllerResolver",
45
     *     "@Core.RouteCollection",
46
     *     "@UrlMatcher",
47
     *     null
48
     * })
49
     * @param ControllerResolver $resolver
50
     * @param SerializedRouteCollection $routes
51
     * @param UrlMatcher $urlMatcher
52
     * @param MiddlewareInterface[] $middlewares
53
     */
54 3
    public function __construct(
55
        ControllerResolver $resolver,
56
        SerializedRouteCollection $routes,
57
        UrlMatcher $urlMatcher,
58
        array $middlewares
59
    ) {
60 3
        $this->resolver    = $resolver;
61 3
        $this->routes      = $routes;
62 3
        $this->urlMatcher  = $urlMatcher;
63 3
        $this->middlewares = $middlewares;
64 3
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 3
    public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
70
    {
71 3
        $response = null;
72
73
        try {
74 3
            $response = $this->handleRequest($request);
75 1
        } catch (Throwable $exception) {
76 1
            $response = $this->applyExceptionMiddleware($request, $exception);
0 ignored issues
show
Compatibility introduced by
$exception of type object<Throwable> is not a sub-type of object<Exception>. It seems like you assume a concrete implementation of the interface Throwable to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
77
        }
78
79 3
        $response = $this->prepareResponse($response);
80
81 3
        $this->applyResponseMiddleware($request, $response);
82
83 3
        return $response;
84
    }
85
86
    /**
87
     * @param Request $request
88
     * @return Response|mixed
89
     */
90 3
    private function handleRequest(Request $request)
91
    {
92
        // match route and set attributes in request object
93 3
        $attributes = $this->urlMatcher->match($request);
94 2
        $request->attributes->replace($attributes);
95
96 2
        $routeName = $attributes['_route'];
97 2
        $route     = $this->routes->get($routeName);
98
99 2
        foreach ($this->middlewares as $middleware) {
100 2
            $response = $middleware->processRequest($request, $route);
101 2
            if ($response) {
102
                // e.g. RedirectResponse or rendered error page
103 2
                return $response;
104
            }
105
        }
106
107
        /** @var callable $callable */
108 1
        $callable  = $this->resolver->getController($request);
109 1
        $arguments = $this->resolver->getArguments($request, $callable);
110
111 1
        return $callable(...$arguments);
112
    }
113
114
    /**
115
     * @param Response|mixed $response
116
     * @return Response
117
     */
118 3
    private function prepareResponse($response) : Response
119
    {
120 3
        if ($response instanceof Generator) {
121
            $response = iterator_to_array($response);
122
        }
123
124 3
        if (!$response instanceof Response) {
125 1
            return new JsonResponse($response);
126
        }
127
128 2
        return $response;
129
    }
130
131
    /**
132
     * @param Request $request
133
     * @param Response $response
134
     */
135 3
    protected function applyResponseMiddleware(Request $request, Response $response)
136
    {
137 3
        $middlewareIdx = count($this->middlewares) - 1;
138 3
        for ($i = $middlewareIdx; $i >= 0; $i--) {
139 3
            $middleware = $this->middlewares[$i];
140 3
            $middleware->processResponse($request, $response);
141
        }
142 3
    }
143
144
    /**
145
     * @param Request $request
146
     * @param Exception $exception
147
     * @return Response|null
148
     */
149 1
    protected function applyExceptionMiddleware(Request $request, Exception $exception)
150
    {
151 1
        foreach ($this->middlewares as $middleware) {
152 1
            $response = $middleware->processException($request, $exception);
153 1
            if ($response !== null) {
154 1
                return $response;
155
            }
156
        }
157
158
        return null;
159
    }
160
}
161