Passed
Pull Request — 8.0 (#3055)
by wj
02:23
created

Http   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Test Coverage

Coverage 65.66%

Importance

Changes 10
Bugs 0 Features 0
Metric Value
eloc 54
c 10
b 0
f 0
dl 0
loc 256
ccs 44
cts 67
cp 0.6566
rs 10
wmc 29

18 Methods

Rating   Name   Duplication   Size   Complexity  
A dispatchToRoute() 0 7 2
A getPath() 0 3 2
A __construct() 0 3 1
A getName() 0 3 2
A loadMiddleware() 0 4 2
A initialize() 0 4 2
A path() 0 8 2
A name() 0 4 1
A setBind() 0 4 1
A setRoutePath() 0 3 1
A getRoutePath() 0 3 1
A run() 0 18 2
A isBind() 0 3 1
A runWithRequest() 0 12 1
A loadRoutes() 0 16 5
A renderException() 0 3 1
A reportException() 0 3 1
A end() 0 9 1
1
<?php
2
3
// +----------------------------------------------------------------------
4
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
5
// +----------------------------------------------------------------------
6
// | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
7
// +----------------------------------------------------------------------
8
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
9
// +----------------------------------------------------------------------
10
// | Author: liu21st <[email protected]>
11
// +----------------------------------------------------------------------
12
declare(strict_types=1);
13
14
namespace think;
15
16
use think\event\HttpEnd;
17
use think\event\HttpRun;
18
use think\event\RouteLoaded;
19
use think\exception\Handle;
20
use Throwable;
21
22
/**
23
 * Web应用管理类
24
 * @package think
25
 */
26
class Http
27
{
28
    /**
29
     * 应用名称
30
     * @var string
31
     */
32
    protected $name;
33
34
    /**
35
     * 应用路径
36
     * @var string
37
     */
38
    protected $path;
39
40
    /**
41
     * 路由路径
42
     * @var string
43
     */
44
    protected $routePath;
45
46
    /**
47
     * 是否绑定应用
48
     * @var bool
49
     */
50
    protected $isBind = false;
51
52 9
    public function __construct(protected App $app)
53
    {
54 9
        $this->routePath = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR;
55
    }
56
57
    /**
58
     * 设置应用名称
59
     * @access public
60
     * @param string $name 应用名称
61
     * @return $this
62
     */
63
    public function name(string $name)
64
    {
65
        $this->name = $name;
66
        return $this;
67
    }
68
69
    /**
70
     * 获取应用名称
71
     * @access public
72
     * @return string
73
     */
74
    public function getName(): string
75
    {
76
        return $this->name ?: '';
77
    }
78
79
    /**
80
     * 设置应用目录
81
     * @access public
82
     * @param string $path 应用目录
83
     * @return $this
84
     */
85
    public function path(string $path)
86
    {
87
        if (str_ends_with($path, DIRECTORY_SEPARATOR)) {
88
            $path .= DIRECTORY_SEPARATOR;
89
        }
90
91
        $this->path = $path;
92
        return $this;
93
    }
94
95
    /**
96
     * 获取应用路径
97
     * @access public
98
     * @return string
99
     */
100
    public function getPath(): string
101
    {
102
        return $this->path ?: '';
103
    }
104
105
    /**
106
     * 获取路由目录
107
     * @access public
108
     * @return string
109
     */
110 3
    public function getRoutePath(): string
111
    {
112 3
        return $this->routePath;
113
    }
114
115
    /**
116
     * 设置路由目录
117
     * @access public
118
     * @param string $path 路由定义目录
119
     */
120
    public function setRoutePath(string $path): void
121
    {
122
        $this->routePath = $path;
123
    }
124
125
    /**
126
     * 设置应用绑定
127
     * @access public
128
     * @param bool $bind 是否绑定
129
     * @return $this
130
     */
131
    public function setBind(bool $bind = true)
132
    {
133
        $this->isBind = $bind;
134
        return $this;
135
    }
136
137
    /**
138
     * 是否绑定应用
139
     * @access public
140
     * @return bool
141
     */
142
    public function isBind(): bool
143
    {
144
        return $this->isBind;
145
    }
146
147
    /**
148
     * 执行应用程序
149
     * @access public
150
     * @param Request|null $request
151
     * @return Response
152
     */
153 6
    public function run(Request $request = null): Response
154
    {
155
        //初始化
156 6
        $this->initialize();
157
158
        //自动创建request对象
159 6
        $request = $request ?? $this->app->make('request', [], true);
160 6
        $this->app->instance('request', $request);
161
162
        try {
163 6
            $response = $this->runWithRequest($request);
164 3
        } catch (Throwable $e) {
165 3
            $this->reportException($e);
166
167 3
            $response = $this->renderException($request, $e);
168
        }
169
170 6
        return $response;
171
    }
172
173
    /**
174
     * 初始化
175
     */
176 6
    protected function initialize()
177
    {
178 6
        if (!$this->app->initialized()) {
179 6
            $this->app->initialize();
180
        }
181
    }
182
183
    /**
184
     * 执行应用程序
185
     * @param Request $request
186
     * @return mixed
187
     */
188 3
    protected function runWithRequest(Request $request)
189
    {
190
        // 加载全局中间件
191 3
        $this->loadMiddleware();
192
193
        // 监听HttpRun
194 3
        $this->app->event->trigger(HttpRun::class);
195
196 3
        return $this->app->middleware->pipeline()
197 3
            ->send($request)
198 3
            ->then(function ($request) {
199 3
                return $this->dispatchToRoute($request);
200 3
            });
201
    }
202
203 3
    protected function dispatchToRoute($request)
204
    {
205 3
        $withRoute = $this->app->config->get('app.with_route', true) ? function () {
206 3
            $this->loadRoutes();
207 3
        } : false;
208
209 3
        return $this->app->route->dispatch($request, $withRoute);
210
    }
211
212
    /**
213
     * 加载全局中间件
214
     */
215 3
    protected function loadMiddleware(): void
216
    {
217 3
        if (is_file($this->app->getBasePath() . 'middleware.php')) {
218 3
            $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
219
        }
220
    }
221
222
    /**
223
     * 加载路由
224
     * @access protected
225
     * @return void
226
     */
227 3
    protected function loadRoutes(): void
228
    {
229
        // 加载路由定义
230 3
        $routePath = $this->getRoutePath();
231
232 3
        if (is_dir($routePath)) {
233
            foreach (scandir($routePath) as $name) {
234
                if (!str_ends_with($name, '.php') || !is_file($routePath . $name)) {
235
                    continue;
236
                }
237
238
                include $routePath . $name;
239
            }
240
        }
241
242 3
        $this->app->event->trigger(RouteLoaded::class);
243
    }
244
245
    /**
246
     * Report the exception to the exception handler.
247
     *
248
     * @param Throwable $e
249
     * @return void
250
     */
251 3
    protected function reportException(Throwable $e)
252
    {
253 3
        $this->app->make(Handle::class)->report($e);
254
    }
255
256
    /**
257
     * Render the exception to a response.
258
     *
259
     * @param Request   $request
260
     * @param Throwable $e
261
     * @return Response
262
     */
263 3
    protected function renderException($request, Throwable $e)
264
    {
265 3
        return $this->app->make(Handle::class)->render($request, $e);
266
    }
267
268
    /**
269
     * HttpEnd
270
     * @param Response $response
271
     * @return void
272
     */
273 3
    public function end(Response $response): void
274
    {
275 3
        $this->app->event->trigger(HttpEnd::class, $response);
276
277
        //执行中间件
278 3
        $this->app->middleware->end($response);
279
280
        // 写入日志
281 3
        $this->app->log->save();
282
    }
283
}
284