Completed
Push — 6.0 ( e89165...09da7f )
by liu
06:38 queued 15s
created

Http   F

Complexity

Total Complexity 67

Size/Duplication

Total Lines 417
Duplicated Lines 0 %

Test Coverage

Coverage 89.93%

Importance

Changes 12
Bugs 0 Features 0
Metric Value
eloc 136
c 12
b 0
f 0
dl 0
loc 417
ccs 134
cts 149
cp 0.8993
rs 3.04
wmc 67

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 2
A dispatchToRoute() 0 7 2
A loadRoutes() 0 13 3
A renderException() 0 3 1
A loadMiddleware() 0 4 2
A getName() 0 3 2
A initialize() 0 4 2
A path() 0 8 2
A reportException() 0 3 1
A name() 0 4 1
A multi() 0 4 1
A __debugInfo() 0 7 1
D parseMultiApp() 0 58 19
B loadApp() 0 39 9
A isMulti() 0 3 1
A setApp() 0 12 3
A run() 0 15 2
A end() 0 9 1
A getRoutePath() 0 7 4
A getScriptName() 0 9 4
A isBindDomain() 0 3 1
A runWithRequest() 0 24 3

How to fix   Complexity   

Complex Class

Complex classes like Http often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Http, and based on these observations, apply Extract Interface, too.

1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use Closure;
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
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
25
 */
26
class Http
27
{
28
29
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
30
     * @var App
31
     */
32
    protected $app;
33
34
    /**
35
     * 应用路径
36
     * @var string
37
     */
38
    protected $path;
39
40
    /**
41
     * 是否多应用模式
42
     * @var bool
43
     */
44
    protected $multi = false;
45
46
    /**
47
     * 是否域名绑定应用
48
     * @var bool
49
     */
50
    protected $bindDomain = false;
51
52
    /**
53
     * 应用名称
54
     * @var string
55
     */
56
    protected $name;
57
58 9
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
59
    {
60 9
        $this->app   = $app;
61 9
        $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
62 9
    }
63
64
    /**
65
     * 是否域名绑定应用
66
     * @access public
67
     * @return bool
68
     */
69 2
    public function isBindDomain(): bool
70
    {
71 2
        return $this->bindDomain;
72
    }
73
74
    /**
75
     * 设置应用模式
76
     * @access public
77
     * @param bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
78
     * @return $this
79
     */
80 7
    public function multi(bool $multi)
81
    {
82 7
        $this->multi = $multi;
83 7
        return $this;
84
    }
85
86
    /**
87
     * 是否为多应用模式
88
     * @access public
89
     * @return bool
90
     */
91 7
    public function isMulti(): bool
92
    {
93 7
        return $this->multi;
94
    }
95
96
    /**
97
     * 设置应用名称
98
     * @access public
99
     * @param string $name 应用名称
100
     * @return $this
101
     */
102 1
    public function name(string $name)
103
    {
104 1
        $this->name = $name;
105 1
        return $this;
106
    }
107
108
    /**
109
     * 获取应用名称
110
     * @access public
111
     * @return string
112
     */
113 5
    public function getName(): string
114
    {
115 5
        return $this->name ?: '';
116
    }
117
118
    /**
119
     * 设置应用目录
120
     * @access public
121
     * @param string $path 应用目录
122
     * @return $this
123
     */
124 1
    public function path(string $path)
125
    {
126 1
        if (substr($path, -1) != DIRECTORY_SEPARATOR) {
127 1
            $path .= DIRECTORY_SEPARATOR;
128
        }
129
130 1
        $this->path = $path;
131 1
        return $this;
132
    }
133
134
    /**
135
     * 执行应用程序
136
     * @access public
137
     * @param Request|null $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
138
     * @return Response
139
     */
140 8
    public function run(Request $request = null): Response
141
    {
142
        //自动创建request对象
143 8
        $request = $request ?? $this->app->make('request', [], true);
144 8
        $this->app->instance('request', $request);
145
146
        try {
147 8
            $response = $this->runWithRequest($request);
148 2
        } catch (Throwable $e) {
149 2
            $this->reportException($e);
150
151 2
            $response = $this->renderException($request, $e);
152
        }
153
154 8
        return $response->setCookie($this->app->cookie);
155
    }
156
157
    /**
158
     * 初始化
159
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
160 7
    protected function initialize()
161
    {
162 7
        if (!$this->app->initialized()) {
163 7
            $this->app->initialize();
164
        }
165 7
    }
166
167
    /**
168
     * 执行应用程序
169
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
170
     * @return mixed
171
     */
172 7
    protected function runWithRequest(Request $request)
173
    {
174 7
        $this->initialize();
175
176
        // 加载全局中间件
177 7
        $this->loadMiddleware();
178
179 7
        $autoMulti = $this->app->config->get('app.auto_multi_app', false);
180
181 7
        if ($this->multi || $autoMulti) {
182 6
            $this->multi(true);
183 6
            $this->parseMultiApp($autoMulti);
184
        }
185
186
        // 设置开启事件机制
187 6
        $this->app->event->withEvent($this->app->config->get('app.with_event', true));
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get('app.with_event', true) can also be of type array; however, parameter $event of think\Event::withEvent() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

187
        $this->app->event->withEvent(/** @scrutinizer ignore-type */ $this->app->config->get('app.with_event', true));
Loading history...
188
189
        // 监听HttpRun
190 6
        $this->app->event->trigger(HttpRun::class);
191
192 6
        return $this->app->middleware->pipeline()
193 6
            ->send($request)
194
            ->then(function ($request) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
195 6
                return $this->dispatchToRoute($request);
196 6
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
197
    }
198
199 6
    protected function dispatchToRoute($request)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function dispatchToRoute()
Loading history...
200
    {
201
        $withRoute = $this->app->config->get('app.with_route', true) ? function () {
202 6
            $this->loadRoutes();
203 6
        } : null;
204
205 6
        return $this->app->route->dispatch($request, $withRoute);
206
    }
207
208
    /**
209
     * 加载全局中间件
210
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
211 7
    protected function loadMiddleware(): void
212
    {
213 7
        if (is_file($this->app->getBasePath() . 'middleware.php')) {
214 7
            $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
215
        }
216 7
    }
217
218
    /**
219
     * 加载路由
220
     * @access protected
221
     * @return void
222
     */
223 6
    protected function loadRoutes(): void
224
    {
225
        // 加载路由定义
226 6
        $routePath = $this->getRoutePath();
227
228 6
        if (is_dir($routePath)) {
229 1
            $files = glob($routePath . '*.php');
230 1
            foreach ($files as $file) {
231
                include $file;
232
            }
233
        }
234
235 6
        $this->app->event->trigger(RouteLoaded::class);
236 6
    }
237
238
    /**
239
     * 获取路由目录
240
     * @access protected
241
     * @return string
242
     */
243 6
    protected function getRoutePath(): string
244
    {
245 6
        if ($this->isMulti() && is_dir($this->app->getAppPath() . 'route')) {
246
            return $this->app->getAppPath() . 'route' . DIRECTORY_SEPARATOR;
247
        }
248
249 6
        return $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR . ($this->isMulti() ? $this->getName() . DIRECTORY_SEPARATOR : '');
250
    }
251
252
    /**
253
     * Report the exception to the exception handler.
254
     *
255
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
256
     * @return void
257
     */
258 1
    protected function reportException(Throwable $e)
259
    {
260 1
        $this->app->make(Handle::class)->report($e);
261 1
    }
262
263
    /**
264
     * Render the exception to a response.
265
     *
266
     * @param Request   $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
267
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
268
     * @return Response
269
     */
270 1
    protected function renderException($request, Throwable $e)
271
    {
272 1
        return $this->app->make(Handle::class)->render($request, $e);
273
    }
274
275
    /**
276
     * 获取当前运行入口名称
277
     * @access protected
278
     * @codeCoverageIgnore
279
     * @return string
280
     */
281
    protected function getScriptName(): string
282
    {
283
        if (isset($_SERVER['SCRIPT_FILENAME'])) {
284
            $file = $_SERVER['SCRIPT_FILENAME'];
285
        } elseif (isset($_SERVER['argv'][0])) {
286
            $file = realpath($_SERVER['argv'][0]);
287
        }
288
289
        return isset($file) ? pathinfo($file, PATHINFO_FILENAME) : '';
290
    }
291
292
    /**
293
     * 解析多应用
294
     * @param bool $autoMulti 自动多应用
295
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
296 6
    protected function parseMultiApp(bool $autoMulti): void
297
    {
298 6
        if ($autoMulti) {
299
            // 自动多应用识别
300 5
            $this->bindDomain = false;
301 5
            $appName          = null;
302 5
            $this->name       = '';
303
304 5
            $bind = $this->app->config->get('app.domain_bind', []);
305
306 5
            if (!empty($bind)) {
307
                // 获取当前子域名
308 5
                $subDomain = $this->app->request->subDomain();
309 5
                $domain    = $this->app->request->host(true);
310
311 5
                if (isset($bind[$domain])) {
312 1
                    $appName          = $bind[$domain];
313 1
                    $this->bindDomain = true;
314 4
                } elseif (isset($bind[$subDomain])) {
315 1
                    $appName          = $bind[$subDomain];
316 1
                    $this->bindDomain = true;
317 3
                } elseif (isset($bind['*'])) {
318
                    $appName          = $bind['*'];
319
                    $this->bindDomain = true;
320
                }
321
            }
322
323 5
            if (!$this->bindDomain) {
324 3
                $path = $this->app->request->pathinfo();
325 3
                $map  = $this->app->config->get('app.app_map', []);
326 3
                $deny = $this->app->config->get('app.deny_app_list', []);
327 3
                $name = current(explode('/', $path));
328
329 3
                if (isset($map[$name])) {
330 1
                    if ($map[$name] instanceof Closure) {
331
                        $result  = call_user_func_array($map[$name], [$this]);
332
                        $appName = $result ?: $name;
333
                    } else {
334 1
                        $appName = $map[$name];
335
                    }
336 2
                } elseif ($name && (false !== array_search($name, $map) || in_array($name, $deny))) {
337 1
                    throw new HttpException(404, 'app not exists:' . $name);
0 ignored issues
show
Bug introduced by
The type think\HttpException was not found. Did you mean HttpException? If so, make sure to prefix the type with \.
Loading history...
338 1
                } elseif ($name && isset($map['*'])) {
339
                    $appName = $map['*'];
340
                } else {
341 1
                    $appName = $name;
342
                }
343
344 2
                if ($name) {
345 2
                    $this->app->request->setRoot('/' . $name);
346 4
                    $this->app->request->setPathinfo(strpos($path, '/') ? ltrim(strstr($path, '/'), '/') : '');
347
                }
348
            }
349
        } else {
350 1
            $appName = $this->name ?: $this->getScriptName();
351
        }
352
353 5
        $this->setApp($appName ?: $this->app->config->get('app.default_app', 'index'));
0 ignored issues
show
Bug introduced by
It seems like $appName ?: $this->app->....default_app', 'index') can also be of type array; however, parameter $appName of think\Http::setApp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

353
        $this->setApp(/** @scrutinizer ignore-type */ $appName ?: $this->app->config->get('app.default_app', 'index'));
Loading history...
354 5
    }
355
356
    /**
357
     * 设置应用
358
     * @param string $appName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
359
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
360 5
    protected function setApp(string $appName): void
361
    {
362 5
        $this->name = $appName;
363 5
        $this->app->request->setApp($appName);
364 5
        $this->app->setAppPath($this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR);
365 5
        $this->app->setRuntimePath($this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR);
366
367
        // 设置应用命名空间
368 5
        $this->app->setNamespace($this->app->config->get('app.app_namespace') ?: 'app\\' . $appName);
369
370
        //加载应用
371 5
        $this->loadApp($appName);
372 5
    }
373
374
    /**
375
     * 加载应用文件
376
     * @param string $appName 应用名
377
     * @return void
378
     */
379 5
    protected function loadApp(string $appName): void
380
    {
381
        //加载app文件
382 5
        if (is_dir($this->app->getAppPath())) {
383 1
            $appPath = $this->app->getAppPath();
384
385 1
            if (is_file($appPath . 'common.php')) {
386 1
                include_once $appPath . 'common.php';
387
            }
388
389 1
            $configPath = $this->app->getConfigPath();
390
391 1
            $files = [];
392
393 1
            if (is_dir($appPath . 'config')) {
394 1
                $files = array_merge($files, glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
0 ignored issues
show
Bug introduced by
It seems like glob($appPath . 'config'...s->app->getConfigExt()) can also be of type false; however, parameter $array2 of array_merge() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

394
                $files = array_merge($files, /** @scrutinizer ignore-type */ glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
Loading history...
395
            } elseif (is_dir($configPath . $appName)) {
396
                $files = array_merge($files, glob($configPath . $appName . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
397
            }
398
399 1
            foreach ($files as $file) {
400
                $this->app->config->load($file, pathinfo($file, PATHINFO_FILENAME));
401
            }
402
403 1
            if (is_file($appPath . 'event.php')) {
404 1
                $this->app->loadEvent(include $appPath . 'event.php');
405
            }
406
407 1
            if (is_file($appPath . 'middleware.php')) {
408 1
                $this->app->middleware->import(include $appPath . 'middleware.php');
409
            }
410
411 1
            if (is_file($appPath . 'provider.php')) {
412 1
                $this->app->bind(include $appPath . 'provider.php');
413
            }
414
        }
415
416
        // 加载应用默认语言包
417 5
        $this->app->loadLangPack($this->app->lang->defaultLangSet());
418 5
    }
419
420
    /**
421
     * HttpEnd
422
     * @param Response $response
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
423
     * @return void
424
     */
425 1
    public function end(Response $response): void
426
    {
427 1
        $this->app->event->trigger(HttpEnd::class, $response);
428
429
        //执行中间件
430 1
        $this->app->middleware->end($response);
431
432
        // 写入日志
433 1
        $this->app->log->save();
434 1
    }
435
436
    public function __debugInfo()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __debugInfo()
Loading history...
437
    {
438
        return [
439
            'path'       => $this->path,
440
            'multi'      => $this->multi,
441
            'bindDomain' => $this->bindDomain,
442
            'name'       => $this->name,
443
        ];
444
    }
445
}
446