Test Failed
Push — master ( a29797...6ce97f )
by huang
06:37
created

Application::handleException()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.9256

Importance

Changes 0
Metric Value
cc 5
eloc 14
nc 16
nop 1
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
ccs 10
cts 15
cp 0.6667
crap 5.9256
1
<?php
2
/**
3
 * @author    jan huang <[email protected]>
4
 * @copyright 2016
5
 *
6
 * @see      https://www.github.com/janhuang
7
 * @see      https://fastdlabs.com
8
 */
9
10
namespace FastD;
11
12
use ErrorException;
13
use Exception;
14
use FastD\Config\Config;
15
use FastD\Container\Container;
16
use FastD\Container\ServiceProviderInterface;
17
use FastD\Http\HttpException;
18
use FastD\Http\Response;
19
use FastD\Http\ServerRequest;
20
use FastD\Logger\Logger;
21
use FastD\ServiceProvider\ConfigServiceProvider;
22
use Psr\Http\Message\ResponseInterface;
23
use Psr\Http\Message\ServerRequestInterface;
24
use Symfony\Component\Debug\Exception\FatalThrowableError;
25
use Throwable;
26
27
/**
28
 * Class Application.
29
 */
30
class Application extends Container
31
{
32
    const VERSION = 'v3.2.0';
33
34
    /**
35
     * @var Application
36
     */
37
    public static $app;
38
39
    /**
40
     * @var string
41
     */
42
    protected $path;
43
44
    /**
45
     * @var string
46
     */
47
    protected $name;
48
49
    /**
50
     * @var bool
51
     */
52
    protected $booted = false;
53
54
    /**
55
     * AppKernel constructor.
56
     *
57
     * @param $path
58
     */
59 37
    public function __construct($path)
60
    {
61 37
        $this->path = $path;
62
63 37
        static::$app = $this;
64
65 37
        $this->add('app', $this);
66
67 37
        $this->bootstrap();
68 37
    }
69
70
    /**
71
     * @return string
72
     */
73 37
    public function getName()
74
    {
75 37
        return $this->name;
76
    }
77
78
    /**
79
     * @return bool
80
     */
81 1
    public function isBooted()
82
    {
83 1
        return $this->booted;
84
    }
85
86
    /**
87
     * @return string
88
     */
89 37
    public function getPath()
90
    {
91 37
        return $this->path;
92
    }
93
94 37
    public function bootstrap()
95
    {
96 37
        if (!$this->booted) {
97 37
            $config = load($this->path.'/config/app.php');
98
99 37
            $this->name = $config['name'];
100
101 37
            $this->add('config', new Config($config));
102 37
            $this->add('logger', new Logger($this->name));
103
104 37
            $this->registerExceptionHandler();
105 37
            $this->registerServicesProviders($config['services']);
106 37
            unset($config);
107 37
            $this->booted = true;
108 37
        }
109 37
    }
110
111 37
    protected function registerExceptionHandler()
112
    {
113 37
        error_reporting(-1);
114
115 37
        set_exception_handler([$this, 'handleException']);
116
117 37
        set_error_handler(function ($level, $message, $file = '', $line = 0) {
118 9
            throw new ErrorException($message, 0, $level, $file, $line);
119 37
        });
120 37
    }
121
122
    /**
123
     * @param ServiceProviderInterface[] $services
124
     */
125 37
    protected function registerServicesProviders(array $services)
126
    {
127 37
        $this->register(new ConfigServiceProvider());
128 37
        foreach ($services as $service) {
129 37
            $this->register(new $service());
130 37
        }
131 37
    }
132
133
    /**
134
     * @param ServerRequestInterface $request
135
     *
136
     * @return Response
137
     */
138 14
    public function handleRequest(ServerRequestInterface $request)
139
    {
140 14
        $this->add('request', $request);
141
142
        try {
143 14
            $response = $this->get('dispatcher')->dispatch($request);
144 3
            logger()->log(Logger::INFO, $response->getStatusCode().' '.$response->getReasonPhrase(), [
145 3
                'method' => $request->getMethod(),
146 3
                'path' => $request->getUri()->getPath(),
147 3
            ]);
148 14
        } catch (Exception $exception) {
149 11
            $response = $this->handleException($exception);
150 11
        } catch (Throwable $exception) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
151
            $exception = new FatalThrowableError($exception);
152
            $response = $this->handleException($exception);
153
        }
154
155 14
        $this->add('response', $response);
156
157 14
        return $response;
158
    }
159
160
    /**
161
     * @param Response $response
162
     */
163 1
    public function handleResponse(Response $response)
164
    {
165 1
        $response->send();
166 1
    }
167
168
    /**
169
     * @param $e
170
     *
171
     * @return Response
172
     */
173 12
    public function handleException($e)
174
    {
175 12
        if (!$e instanceof Exception) {
176
            $e = new FatalThrowableError($e);
177
        }
178
179
        try {
180 12
            $trace = call_user_func(config()->get('exception.log'), $e);
181 12
        } catch (Exception $exception) {
182
            $trace = [
183
                'original' => explode("\n", $e->getTraceAsString()),
184
                'handler' => explode("\n", $exception->getTraceAsString()),
185
            ];
186
        }
187
188 12
        logger()->log(Logger::ERROR, $e->getMessage(), $trace);
189
190 12
        $statusCode = ($e instanceof HttpException) ? $e->getStatusCode() : $e->getCode();
191
192 12
        if (!array_key_exists($statusCode, Response::$statusTexts)) {
193 11
            $statusCode = 502;
194 11
        }
195
196 12
        return json(call_user_func(config()->get('exception.response'), $e), $statusCode);
197
    }
198
199
    /**
200
     * @return int
201
     */
202
    public function run()
203
    {
204
        $request = ServerRequest::createServerRequestFromGlobals();
205
206
        $response = $this->handleRequest($request);
207
208
        $this->handleResponse($response);
209
210
        return $this->shutdown($request, $response);
211
    }
212
213
    /**
214
     * @param ServerRequestInterface $request
215
     * @param ResponseInterface      $response
216
     *
217
     * @return int
218
     */
219 2
    public function shutdown(ServerRequestInterface $request, ResponseInterface $response)
220 1
    {
221 2
        $this->offsetUnset('request');
222 2
        $this->offsetUnset('response');
223 2
        $this->offsetUnset('exception');
224 2
        unset($request, $response);
225
226 2
        return 0;
227
    }
228
}
229