Completed
Push — 6.0 ( a1c09e...949fb1 )
by liu
08:06
created

Http::loadApp()   B

Complexity

Conditions 11
Paths 49

Size

Total Lines 47
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 11.209

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 24
c 1
b 0
f 0
nc 49
nop 1
dl 0
loc 47
ccs 22
cts 25
cp 0.88
crap 11.209
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 9
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
58
    {
59 9
        $this->app   = $app;
60 9
        $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
61 9
    }
62
63
    /**
64
     * 是否域名绑定应用
65
     * @access public
66
     * @return bool
67
     */
68 2
    public function isBindDomain(): bool
69
    {
70 2
        return $this->bindDomain;
71
    }
72
73
    /**
74
     * 设置应用模式
75
     * @access public
76
     * @param bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
77
     * @return $this
78
     */
79 7
    public function multi(bool $multi)
80
    {
81 7
        $this->multi = $multi;
82 7
        return $this;
83
    }
84
85
    /**
86
     * 是否为多应用模式
87
     * @access public
88
     * @return bool
89
     */
90 7
    public function isMulti(): bool
91
    {
92 7
        return $this->multi;
93
    }
94
95
    /**
96
     * 设置应用名称
97
     * @access public
98
     * @param string $name 应用名称
99
     * @return $this
100
     */
101 1
    public function name(string $name)
102
    {
103 1
        $this->name = $name;
104 1
        return $this;
105
    }
106
107
    /**
108
     * 获取应用名称
109
     * @access public
110
     * @return string
111
     */
112 5
    public function getName(): string
113
    {
114 5
        return $this->name ?: '';
115
    }
116
117
    /**
118
     * 设置应用目录
119
     * @access public
120
     * @param string $path 应用目录
121
     * @return $this
122
     */
123 1
    public function path(string $path)
124
    {
125 1
        if (substr($path, -1) != DIRECTORY_SEPARATOR) {
126 1
            $path .= DIRECTORY_SEPARATOR;
127
        }
128
129 1
        $this->path = $path;
130 1
        return $this;
131
    }
132
133
    /**
134
     * 执行应用程序
135
     * @access public
136
     * @param Request|null $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
137
     * @return Response
138
     */
139 8
    public function run(Request $request = null): Response
140
    {
141
        //自动创建request对象
142 8
        $request = $request ?? $this->app->make('request', [], true);
143 8
        $this->app->instance('request', $request);
144
145
        try {
146 8
            $response = $this->runWithRequest($request);
147 2
        } catch (Throwable $e) {
148 2
            $this->reportException($e);
149
150 2
            $response = $this->renderException($request, $e);
151
        }
152
153 8
        return $response->setCookie($this->app->cookie);
154
    }
155
156
    /**
157
     * 初始化
158
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
159 7
    protected function initialize()
160
    {
161 7
        if (!$this->app->initialized()) {
162 7
            $this->app->initialize();
163
        }
164 7
    }
165
166
    /**
167
     * 执行应用程序
168
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
169
     * @return mixed
170
     */
171 7
    protected function runWithRequest(Request $request)
172
    {
173 7
        $this->initialize();
174
175
        // 加载全局中间件
176 7
        if (is_file($this->app->getBasePath() . 'middleware.php')) {
177 7
            $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
178
        }
179
180 7
        $autoMulti = $this->app->config->get('app.auto_multi_app', false);
181
182 7
        if ($this->multi || $autoMulti) {
183 6
            $this->multi(true);
184 6
            $this->parseMultiApp($autoMulti);
185
        }
186
187
        // 设置开启事件机制
188 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

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

333
        $this->loadApp(/** @scrutinizer ignore-type */ $appName ?: $this->app->config->get('app.default_app', 'index'));
Loading history...
334 5
    }
335
336
    /**
337
     * 加载应用文件
338
     * @param string $appName 应用名
339
     * @return void
340
     */
341 5
    protected function loadApp(string $appName): void
342
    {
343 5
        $this->name = $appName;
344 5
        $this->app->request->setApp($appName);
345 5
        $this->app->setAppPath($this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR);
346 5
        $this->app->setRuntimePath($this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR);
347
348
        //加载app文件
349 5
        if (is_dir($this->app->getAppPath())) {
350 1
            $appPath = $this->app->getAppPath();
351
352 1
            if (is_file($appPath . 'common.php')) {
353 1
                include_once $appPath . 'common.php';
354
            }
355
356 1
            $configPath = $this->app->getConfigPath();
357
358 1
            $files = [];
359
360 1
            if (is_dir($configPath . $appName)) {
361 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

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