Completed
Push — 6.0 ( b9ee63...b796be )
by liu
06:16
created

Http   F

Complexity

Total Complexity 70

Size/Duplication

Total Lines 414
Duplicated Lines 0 %

Test Coverage

Coverage 87.76%

Importance

Changes 9
Bugs 0 Features 0
Metric Value
eloc 140
dl 0
loc 414
ccs 129
cts 147
cp 0.8776
rs 2.8
c 9
b 0
f 0
wmc 70

19 Methods

Rating   Name   Duplication   Size   Complexity  
A loadRoutes() 0 13 3
A __construct() 0 4 2
A renderException() 0 3 1
A getName() 0 3 2
A initialize() 0 7 3
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 56 19
F loadApp() 0 69 17
A isMulti() 0 3 1
A run() 0 15 2
A end() 0 8 1
A getRoutePath() 0 7 4
A getScriptName() 0 9 4
A isBindDomain() 0 3 1
A runWithRequest() 0 22 4

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\RouteLoaded;
17
use think\exception\Handle;
18
use think\exception\HttpException;
19
use Throwable;
20
21
/**
22
 * Web应用管理类
23
 * @package think
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
24
 */
25
class Http
26
{
27
28
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
29
     * @var App
30
     */
31
    protected $app;
32
33
    /**
34
     * 应用路径
35
     * @var string
36
     */
37
    protected $path;
38
39
    /**
40
     * 是否多应用模式
41
     * @var bool
42
     */
43
    protected $multi = false;
44
45
    /**
46
     * 是否域名绑定应用
47
     * @var bool
48
     */
49
    protected $bindDomain = false;
50
51
    /**
52
     * 应用名称
53
     * @var string
54
     */
55
    protected $name;
56
57
    /**
58
     * 应用数据寄存器
59
     * @var array
60
     */
61
    protected $register = [];
62
63 9
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
64
    {
65 9
        $this->app   = $app;
66 9
        $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
67 9
    }
68
69
    /**
70
     * 是否域名绑定应用
71
     * @access public
72
     * @return bool
73
     */
74 2
    public function isBindDomain(): bool
75
    {
76 2
        return $this->bindDomain;
77
    }
78
79
    /**
80
     * 设置应用模式
81
     * @access public
82
     * @param bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
83
     * @return $this
84
     */
85 7
    public function multi(bool $multi)
86
    {
87 7
        $this->multi = $multi;
88 7
        return $this;
89
    }
90
91
    /**
92
     * 是否为多应用模式
93
     * @access public
94
     * @return bool
95
     */
96 7
    public function isMulti(): bool
97
    {
98 7
        return $this->multi;
99
    }
100
101
    /**
102
     * 设置应用名称
103
     * @access public
104
     * @param string $name 应用名称
105
     * @return $this
106
     */
107 1
    public function name(string $name)
108
    {
109 1
        $this->name = $name;
110 1
        return $this;
111
    }
112
113
    /**
114
     * 获取应用名称
115
     * @access public
116
     * @return string
117
     */
118 5
    public function getName(): string
119
    {
120 5
        return $this->name ?: '';
121
    }
122
123
    /**
124
     * 设置应用目录
125
     * @access public
126
     * @param string $path 应用目录
127
     * @return $this
128
     */
129 1
    public function path(string $path)
130
    {
131 1
        if (substr($path, -1) != DIRECTORY_SEPARATOR) {
132 1
            $path .= DIRECTORY_SEPARATOR;
133
        }
134
135 1
        $this->path = $path;
136 1
        return $this;
137
    }
138
139
    /**
140
     * 执行应用程序
141
     * @access public
142
     * @param Request|null $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
143
     * @return Response
144
     */
145 8
    public function run(Request $request = null): Response
146
    {
147
        //自动创建request对象
148 8
        $request = $request ?? $this->app->make('request', [], true);
149 8
        $this->app->instance('request', $request);
150
151
        try {
152 8
            $response = $this->runWithRequest($request);
153 2
        } catch (Throwable $e) {
154 2
            $this->reportException($e);
155
156 2
            $response = $this->renderException($request, $e);
157
        }
158
159 8
        return $response->setCookie($this->app->cookie);
160
    }
161
162
    /**
163
     * 初始化
164
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
165 7
    protected function initialize()
166
    {
167 7
        if (!$this->app->initialized()) {
168 7
            $this->app->initialize();
169
            // 加载全局中间件
170 7
            if (is_file($this->app->getBasePath() . 'middleware.php')) {
171 7
                $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
172
            }
173
        }
174 7
    }
175
176
    /**
177
     * 执行应用程序
178
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
179
     * @return mixed
180
     */
181 7
    protected function runWithRequest(Request $request)
182
    {
183 7
        $this->initialize();
184
185 7
        $autoMulti = $this->app->config->get('app.auto_multi_app', false);
186
187 7
        if ($this->multi || $autoMulti) {
188 6
            $this->multi(true);
189 6
            $this->parseMultiApp($autoMulti);
190
        }
191
192
        // 设置开启事件机制
193 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

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

338
        $this->loadApp(/** @scrutinizer ignore-type */ $appName ?: $this->app->config->get('app.default_app', 'index'));
Loading history...
339 5
    }
340
341
    /**
342
     * 加载应用文件
343
     * @param string $appName 应用名
344
     * @return void
345
     */
346 5
    protected function loadApp(string $appName): void
347
    {
348 5
        $this->name = $appName;
349 5
        $this->app->request->setApp($appName);
350 5
        $this->app->setAppPath($this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR);
351 5
        $this->app->setRuntimePath($this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR);
352
353
        //加载app文件
354 5
        if (!isset($this->register[$appName])) {
355 5
            if (is_dir($this->app->getAppPath())) {
356 1
                $appPath = $this->app->getAppPath();
357
358 1
                if (is_file($appPath . 'common.php')) {
359 1
                    include_once $appPath . 'common.php';
360
                }
361
362 1
                $configPath = $this->app->getConfigPath();
363
364 1
                $files = [];
365
366 1
                if (is_dir($configPath . $appName)) {
367 1
                    $files = array_merge($files, glob($configPath . $appName . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
0 ignored issues
show
Bug introduced by
It seems like glob($configPath . $appN...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

367
                    $files = array_merge($files, /** @scrutinizer ignore-type */ glob($configPath . $appName . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
Loading history...
368
                } elseif (is_dir($appPath . 'config')) {
369
                    $files = array_merge($files, glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
370
                }
371
372 1
                foreach ($files as $file) {
373
                    $name = pathinfo($file, PATHINFO_FILENAME);
374
375
                    $this->register[$appName]['config'][$name] = $this->app->config->load($file, $name, false);
376
                }
377
378 1
                if (is_file($appPath . 'event.php')) {
379 1
                    $this->register[$appName]['event'] = include $appPath . 'event.php';
380
                }
381
382 1
                if (is_file($appPath . 'middleware.php')) {
383 1
                    $this->register[$appName]['middleware'] = include $appPath . 'middleware.php';
384
                }
385
386 1
                if (is_file($appPath . 'provider.php')) {
387 1
                    $this->register[$appName]['provider'] = include $appPath . 'provider.php';
388
                }
389
            }
390
        }
391
392 5
        if (isset($this->register[$appName]['config'])) {
393
            foreach ($this->register[$appName]['config'] as $name => $config) {
394
                $this->app->config->set($config, $name);
395
            }
396
        }
397
398 5
        if (isset($this->register[$appName]['event'])) {
399 1
            $this->app->loadEvent($this->register[$appName]['event']);
400
        }
401
402 5
        if (isset($this->register[$appName]['middleware'])) {
403 1
            $this->app->middleware->import($this->register[$appName]['middleware']);
404
        }
405
406 5
        if (isset($this->register[$appName]['provider'])) {
407 1
            $this->app->bind($this->register[$appName]['provider']);
408
        }
409
410
        // 加载应用默认语言包
411 5
        $this->app->loadLangPack($this->app->lang->defaultLangSet());
412
413
        // 设置应用命名空间
414 5
        $this->app->setNamespace($this->app->config->get('app.app_namespace') ?: 'app\\' . $appName);
415 5
    }
416
417
    /**
418
     * HttpEnd
419
     * @param Response $response
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
420
     * @return void
421
     */
422 1
    public function end(Response $response): void
423
    {
424 1
        $this->app->event->trigger('HttpEnd', $response);
425
426
        // 写入日志
427 1
        $this->app->log->save();
428
        // 写入Session
429 1
        $this->app->session->save();
430 1
    }
431
432
    public function __debugInfo()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __debugInfo()
Loading history...
433
    {
434
        return [
435
            'path'       => $this->path,
436
            'multi'      => $this->multi,
437
            'bindDomain' => $this->bindDomain,
438
            'name'       => $this->name,
439
        ];
440
    }
441
}
442