Completed
Push — 6.0 ( 740410...ebf27b )
by liu
05: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 1
    public function multi(bool $multi)
80
    {
81 1
        $this->multi = $multi;
82 1
        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
        if ($this->multi) {
181 6
            $this->parseMultiApp();
182
        }
183
184
        // 设置开启事件机制
185 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

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

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

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