Test Failed
Pull Request — master (#67)
by
unknown
05:53
created

Application::handleRequest()   A

Complexity

Conditions 3
Paths 5

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3.0261

Importance

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