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

Http::parseMultiApp()   D

Complexity

Conditions 19
Paths 51

Size

Total Lines 58
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 19.8227

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 19
eloc 40
c 5
b 0
f 0
nc 51
nop 1
dl 0
loc 58
ccs 33
cts 38
cp 0.8684
crap 19.8227
rs 4.5166

How to fix   Long Method    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\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