Passed
Push — 6.0 ( 07cfee...b31ecf )
by liu
03:02
created

Route::checkDomain()   F

Complexity

Conditions 14
Paths 324

Size

Total Lines 47
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 210

Importance

Changes 0
Metric Value
cc 14
eloc 23
nc 324
nop 0
dl 0
loc 47
ccs 0
cts 24
cp 0
crap 210
rs 3.8833
c 0
b 0
f 0

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
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
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\cache\Driver;
17
use think\exception\HttpResponseException;
18
use think\exception\RouteNotFoundException;
19
use think\route\Dispatch;
20
use think\route\dispatch\Url as UrlDispatch;
21
use think\route\Domain;
22
use think\route\Resource;
23
use think\route\Rule;
24
use think\route\RuleGroup;
25
use think\route\RuleItem;
26
use think\route\RuleName;
27
28
/**
29
 * 路由管理类
30
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
31
class Route
32
{
33
    /**
34
     * REST定义
35
     * @var array
36
     */
37
    protected $rest = [
38
        'index'  => ['get', '', 'index'],
39
        'create' => ['get', '/create', 'create'],
40
        'edit'   => ['get', '/<id>/edit', 'edit'],
41
        'read'   => ['get', '/<id>', 'read'],
42
        'save'   => ['post', '', 'save'],
43
        'update' => ['put', '/<id>', 'update'],
44
        'delete' => ['delete', '/<id>', 'delete'],
45
    ];
46
47
    /**
48
     * 配置参数
49
     * @var array
50
     */
51
    protected $config = [
52
        // pathinfo分隔符
53
        'pathinfo_depr'         => '/',
54
        // 是否开启路由延迟解析
55
        'url_lazy_route'        => false,
56
        // 是否强制使用路由
57
        'url_route_must'        => false,
58
        // 合并路由规则
59
        'route_rule_merge'      => false,
60
        // 路由是否完全匹配
61
        'route_complete_match'  => false,
62
        // 使用注解路由
63
        'route_annotation'      => false,
64
        // 路由缓存设置
65
        'route_check_cache'     => false,
66
        'route_cache_option'    => [],
67
        'route_check_cache_key' => '',
68
        // 是否自动转换URL中的控制器和操作名
69
        'url_convert'           => true,
70
        // 默认的路由变量规则
71
        'default_route_pattern' => '[\w\.]+',
72
        // URL伪静态后缀
73
        'url_html_suffix'       => 'html',
74
        // 访问控制器层名称
75
        'controller_layer'      => 'controller',
76
        // 空控制器名
77
        'empty_controller'      => 'Error',
78
        // 是否使用控制器后缀
79
        'controller_suffix'     => false,
80
        // 默认控制器名
81
        'default_controller'    => 'Index',
82
        // 默认操作名
83
        'default_action'        => 'index',
84
        // 操作方法后缀
85
        'action_suffix'         => '',
86
        // 是否开启路由检测缓存
87
        'route_check_cache'     => false,
88
        // 非路由变量是否使用普通参数方式(用于URL生成)
89
        'url_common_param'      => true,
90
    ];
91
92
    /**
93
     * 当前应用
94
     * @var App
95
     */
96
    protected $app;
97
98
    /**
99
     * 请求对象
100
     * @var Request
101
     */
102
    protected $request;
103
104
    /**
105
     * 缓存
106
     * @var Driver
107
     */
108
    protected $cache;
109
110
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
111
     * @var RuleName
112
     */
113
    protected $ruleName;
114
115
    /**
116
     * 当前HOST
117
     * @var string
118
     */
119
    protected $host;
120
121
    /**
122
     * 当前分组对象
123
     * @var RuleGroup
124
     */
125
    protected $group;
126
127
    /**
128
     * 路由绑定
129
     * @var array
130
     */
131
    protected $bind = [];
132
133
    /**
134
     * 域名对象
135
     * @var array
136
     */
137
    protected $domains = [];
138
139
    /**
140
     * 跨域路由规则
141
     * @var RuleGroup
142
     */
143
    protected $cross;
144
145
    /**
146
     * 路由是否延迟解析
147
     * @var bool
148
     */
149
    protected $lazy = true;
150
151
    /**
152
     * 路由是否测试模式
153
     * @var bool
154
     */
155
    protected $isTest = false;
156
157
    /**
158
     * (分组)路由规则是否合并解析
159
     * @var bool
160
     */
161
    protected $mergeRuleRegex = false;
162
163
    /**
164
     * 显示域名
165
     * @var bool
166
     */
167
    protected $showDomain;
168
169
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
170
    {
171
        $this->app      = $app;
172
        $this->config   = array_merge($this->config, $app->config->get('route'));
173
        $this->ruleName = new RuleName();
174
175
        $this->lazy($this->config['url_lazy_route']);
176
177
        if ($this->config['route_check_cache']) {
178
            if (!empty($this->config['route_cache_option'])) {
179
                $this->cache = $app->cache->connect($this->config['route_cache_option']);
180
            } else {
181
                $this->cache = $app->cache->init();
182
            }
183
        }
184
185
        if (is_file($app->getRuntimePath() . 'route.php')) {
186
            // 读取路由映射文件
187
            $this->import(include $app->getRuntimePath() . 'route.php');
188
        }
189
190
        $this->setDefaultDomain();
191
    }
192
193
    public function config(string $name = null)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function config()
Loading history...
194
    {
195
        if (is_null($name)) {
196
            return $this->config;
197
        }
198
199
        return $this->config[$name] ?? null;
200
    }
201
202
    /**
203
     * 设置路由域名及分组(包括资源路由)是否延迟解析
204
     * @access public
205
     * @param bool $lazy 路由是否延迟解析
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
206
     * @return $this
207
     */
208
    public function lazy(bool $lazy = true)
209
    {
210
        $this->lazy = $lazy;
211
        return $this;
212
    }
213
214
    /**
215
     * 设置路由为测试模式
216
     * @access public
217
     * @param bool $test 路由是否测试模式
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
218
     * @return void
219
     */
220
    public function setTestMode(bool $test): void
221
    {
222
        $this->isTest = $test;
223
    }
224
225
    /**
226
     * 检查路由是否为测试模式
227
     * @access public
228
     * @return bool
229
     */
230
    public function isTest(): bool
231
    {
232
        return $this->isTest;
233
    }
234
235
    /**
236
     * 设置路由域名及分组(包括资源路由)是否合并解析
237
     * @access public
238
     * @param bool $merge 路由是否合并解析
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
239
     * @return $this
240
     */
241
    public function mergeRuleRegex(bool $merge = true)
242
    {
243
        $this->mergeRuleRegex = $merge;
244
        $this->group->mergeRuleRegex($merge);
245
246
        return $this;
247
    }
248
249
    /**
250
     * 初始化默认域名
251
     * @access protected
252
     * @return void
253
     */
254
    protected function setDefaultDomain(): void
255
    {
256
        // 注册默认域名
257
        $domain = new Domain($this);
258
259
        $this->domains['-'] = $domain;
260
261
        // 默认分组
262
        $this->group = $domain;
263
    }
264
265
    /**
266
     * 设置当前分组
267
     * @access public
268
     * @param RuleGroup $group 域名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
269
     * @return void
270
     */
271
    public function setGroup(RuleGroup $group): void
272
    {
273
        $this->group = $group;
274
    }
275
276
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $name should have a doc-comment as per coding-style.
Loading history...
277
     * 获取指定标识的路由分组 不指定则获取当前分组
278
     * @access public
279
     * @return RuleGroup
280
     */
281
    public function getGroup(string $name = null)
282
    {
283
        return $name ? $this->ruleName->getGroup($name) : $this->group;
284
    }
285
286
    /**
287
     * 注册变量规则
288
     * @access public
289
     * @param array $pattern 变量规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
290
     * @return $this
291
     */
292
    public function pattern(array $pattern)
293
    {
294
        $this->group->pattern($pattern);
295
296
        return $this;
297
    }
298
299
    /**
300
     * 注册路由参数
301
     * @access public
302
     * @param array $option 参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
303
     * @return $this
304
     */
305
    public function option(array $option)
306
    {
307
        $this->group->option($option);
308
309
        return $this;
310
    }
311
312
    /**
313
     * 注册域名路由
314
     * @access public
315
     * @param string|array $name 子域名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
316
     * @param mixed        $rule 路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
317
     * @return Domain
318
     */
319
    public function domain($name, $rule = null): Domain
320
    {
321
        // 支持多个域名使用相同路由规则
322
        $domainName = is_array($name) ? array_shift($name) : $name;
323
324
        if ('*' != $domainName && false === strpos($domainName, '.')) {
325
            $domainName .= '.' . $this->request->rootDomain();
326
        }
327
328
        if (!isset($this->domains[$domainName])) {
329
            $domain = (new Domain($this, $domainName, $rule))
330
                ->lazy($this->lazy)
331
                ->mergeRuleRegex($this->mergeRuleRegex);
332
333
            $this->domains[$domainName] = $domain;
334
        } else {
335
            $domain = $this->domains[$domainName];
336
            $domain->parseGroupRule($rule);
337
        }
338
339
        if (is_array($name) && !empty($name)) {
340
            $root = $this->request->rootDomain();
341
            foreach ($name as $item) {
342
                if (false === strpos($item, '.')) {
343
                    $item .= '.' . $root;
344
                }
345
346
                $this->domains[$item] = $domainName;
347
            }
348
        }
349
350
        // 返回域名对象
351
        return $domain;
352
    }
353
354
    /**
355
     * 获取域名
356
     * @access public
357
     * @return array
358
     */
359
    public function getDomains(): array
360
    {
361
        return $this->domains;
362
    }
363
364
    /**
365
     * 获取RuleName对象
366
     * @access public
367
     * @return RuleName
368
     */
369
    public function getRuleName(): RuleName
370
    {
371
        return $this->ruleName;
372
    }
373
374
    /**
375
     * 设置路由绑定
376
     * @access public
377
     * @param string $bind   绑定信息
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
378
     * @param string $domain 域名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
379
     * @return $this
380
     */
381
    public function bind(string $bind, string $domain = null)
382
    {
383
        $domain = is_null($domain) ? '-' : $domain;
384
385
        $this->bind[$domain] = $bind;
386
387
        return $this;
388
    }
389
390
    /**
391
     * 读取路由绑定信息
392
     * @access public
393
     * @return array
394
     */
395
    public function getBind(): array
396
    {
397
        return $this->bind;
398
    }
399
400
    /**
401
     * 读取路由绑定
402
     * @access public
403
     * @param string $domain 域名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
404
     * @return string|null
405
     */
406
    public function getDomainBind(string $domain = null)
407
    {
408
        if (is_null($domain)) {
409
            $domain = $this->host;
410
        } elseif (false === strpos($domain, '.')) {
411
            $domain .= '.' . $this->request->rootDomain();
412
        }
413
414
        $subDomain = $this->request->subDomain();
415
416
        if (strpos($subDomain, '.')) {
417
            $name = '*' . strstr($subDomain, '.');
418
        }
419
420
        if (isset($this->bind[$domain])) {
421
            $result = $this->bind[$domain];
422
        } elseif (isset($name) && isset($this->bind[$name])) {
423
            $result = $this->bind[$name];
424
        } elseif (!empty($subDomain) && isset($this->bind['*'])) {
425
            $result = $this->bind['*'];
426
        } else {
427
            $result = null;
428
        }
429
430
        return $result;
431
    }
432
433
    /**
434
     * 读取路由标识
435
     * @access public
436
     * @param string $name   路由标识
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
437
     * @param string $domain 域名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
438
     * @param string $method 请求类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
439
     * @return RuleItem[]
440
     */
441
    public function getName(string $name = null, string $domain = null, string $method = '*'): array
442
    {
443
        return $this->ruleName->getName($name, $domain, $method);
444
    }
445
446
    /**
447
     * 批量导入路由标识
448
     * @access public
449
     * @param array $name 路由标识
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
450
     * @return $this
451
     */
452
    public function import(array $name): void
453
    {
454
        $this->ruleName->import($name);
455
    }
456
457
    /**
458
     * 注册路由标识
459
     * @access public
460
     * @param string       $name  路由标识
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
461
     * @param string|array $value 路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
462
     * @param bool         $first 是否置顶
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
463
     * @return void
464
     */
465
    public function setName(string $name, $value, bool $first = false): void
466
    {
467
        $this->ruleName->setName($name, $value, $first);
468
    }
469
470
    /**
471
     * 保存路由规则
472
     * @access public
473
     * @param string $rule   路由规则
1 ignored issue
show
Coding Style introduced by
Expected 5 spaces after parameter name; 3 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
474
     * @param RuleItem $ruleItem RuleItem对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
475
     * @return void
476
     */
477
    public function setRule(string $rule, RuleItem $ruleItem = null): void
478
    {
479
        $this->ruleName->setRule($rule, $ruleItem);
0 ignored issues
show
Bug introduced by
It seems like $ruleItem can also be of type null; however, parameter $ruleItem of think\route\RuleName::setRule() does only seem to accept think\route\RuleItem, 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

479
        $this->ruleName->setRule($rule, /** @scrutinizer ignore-type */ $ruleItem);
Loading history...
480
    }
481
482
    /**
483
     * 读取路由
484
     * @access public
485
     * @param string $rule   路由规则
1 ignored issue
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
486
     * @return RuleItem[]
487
     */
488
    public function getRule(string $rule): array
489
    {
490
        return $this->ruleName->getRule($rule);
491
    }
492
493
    /**
494
     * 读取路由列表
495
     * @access public
496
     * @return array
497
     */
498
    public function getRuleList(): array
499
    {
500
        return $this->ruleName->getRuleList();
501
    }
502
503
    /**
504
     * 清空路由规则
505
     * @access public
506
     * @return void
507
     */
508
    public function clear(): void
509
    {
510
        $this->ruleName->clear();
511
512
        if ($this->group) {
513
            $this->group->clear();
514
        }
515
    }
516
517
    /**
518
     * 注册路由规则
519
     * @access public
520
     * @param string $rule   路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
521
     * @param mixed  $route  路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
522
     * @param string $method 请求类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
523
     * @return RuleItem
524
     */
525
    public function rule(string $rule, $route = null, string $method = '*'): RuleItem
526
    {
527
        return $this->group->addRule($rule, $route, $method);
528
    }
529
530
    /**
531
     * 设置跨域有效路由规则
532
     * @access public
533
     * @param Rule   $rule   路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
534
     * @param string $method 请求类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
535
     * @return $this
536
     */
537
    public function setCrossDomainRule(Rule $rule, string $method = '*')
538
    {
539
        if (!isset($this->cross)) {
540
            $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
541
        }
542
543
        $this->cross->addRuleItem($rule, $method);
544
545
        return $this;
546
    }
547
548
    /**
549
     * 注册路由分组
550
     * @access public
551
     * @param string|\Closure $name  分组名称或者参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
552
     * @param mixed           $route 分组路由
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
553
     * @return RuleGroup
554
     */
555
    public function group($name, $route = null): RuleGroup
556
    {
557
        if ($name instanceof \Closure) {
558
            $route = $name;
559
            $name  = '';
560
        }
561
562
        return (new RuleGroup($this, $this->group, $name, $route))
563
            ->lazy($this->lazy)
564
            ->mergeRuleRegex($this->mergeRuleRegex);
565
    }
566
567
    /**
568
     * 注册路由
569
     * @access public
570
     * @param string $rule  路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
571
     * @param mixed  $route 路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
572
     * @return RuleItem
573
     */
574
    public function any(string $rule, $route): RuleItem
575
    {
576
        return $this->rule($rule, $route, '*');
577
    }
578
579
    /**
580
     * 注册GET路由
581
     * @access public
582
     * @param string $rule  路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
583
     * @param mixed  $route 路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
584
     * @return RuleItem
585
     */
586
    public function get(string $rule, $route): RuleItem
587
    {
588
        return $this->rule($rule, $route, 'GET');
589
    }
590
591
    /**
592
     * 注册POST路由
593
     * @access public
594
     * @param string $rule  路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
595
     * @param mixed  $route 路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
596
     * @return RuleItem
597
     */
598
    public function post(string $rule, $route): RuleItem
599
    {
600
        return $this->rule($rule, $route, 'POST');
601
    }
602
603
    /**
604
     * 注册PUT路由
605
     * @access public
606
     * @param string $rule  路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
607
     * @param mixed  $route 路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
608
     * @return RuleItem
609
     */
610
    public function put(string $rule, $route): RuleItem
611
    {
612
        return $this->rule($rule, $route, 'PUT');
613
    }
614
615
    /**
616
     * 注册DELETE路由
617
     * @access public
618
     * @param string $rule  路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
619
     * @param mixed  $route 路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
620
     * @return RuleItem
621
     */
622
    public function delete(string $rule, $route): RuleItem
623
    {
624
        return $this->rule($rule, $route, 'DELETE');
625
    }
626
627
    /**
628
     * 注册PATCH路由
629
     * @access public
630
     * @param string $rule  路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
631
     * @param mixed  $route 路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
632
     * @return RuleItem
633
     */
634
    public function patch(string $rule, $route): RuleItem
635
    {
636
        return $this->rule($rule, $route, 'PATCH');
637
    }
638
639
    /**
640
     * 注册资源路由
641
     * @access public
642
     * @param string $rule  路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
643
     * @param string $route 路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
644
     * @return Resource
645
     */
646
    public function resource(string $rule, string $route): Resource
647
    {
648
        return (new Resource($this, $this->group, $rule, $route, $this->rest))
649
            ->lazy($this->lazy);
650
    }
651
652
    /**
653
     * 注册视图路由
654
     * @access public
655
     * @param string|array $rule     路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
656
     * @param string       $template 路由模板地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
657
     * @param array        $vars     模板变量
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
658
     * @return RuleItem
659
     */
660
    public function view(string $rule, string $template = '', array $vars = []): RuleItem
661
    {
662
        return $this->rule($rule, $template, 'GET')->view($vars);
663
    }
664
665
    /**
666
     * 注册重定向路由
667
     * @access public
668
     * @param string|array $rule   路由规则
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
669
     * @param string       $route  路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
670
     * @param int          $status 状态码
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
671
     * @return RuleItem
672
     */
673
    public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
674
    {
675
        return $this->rule($rule, $route, '*')->redirect()->status($status);
676
    }
677
678
    /**
679
     * rest方法定义和修改
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
680
     * @access public
681
     * @param string|array $name     方法名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
682
     * @param array|bool   $resource 资源
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
683
     * @return $this
684
     */
685
    public function rest($name, $resource = [])
686
    {
687
        if (is_array($name)) {
688
            $this->rest = $resource ? $name : array_merge($this->rest, $name);
689
        } else {
690
            $this->rest[$name] = $resource;
691
        }
692
693
        return $this;
694
    }
695
696
    /**
697
     * 获取rest方法定义的参数
698
     * @access public
699
     * @param string $name 方法名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
700
     * @return array|null
701
     */
702
    public function getRest(string $name = null)
703
    {
704
        if (is_null($name)) {
705
            return $this->rest;
706
        }
707
708
        return $this->rest[$name] ?? null;
709
    }
710
711
    /**
712
     * 注册未匹配路由规则后的处理
713
     * @access public
714
     * @param string|Closure $route  路由地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
715
     * @param string         $method 请求类型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
716
     * @return RuleItem
717
     */
718
    public function miss($route, string $method = '*'): RuleItem
719
    {
720
        return $this->group->miss($route, $method);
721
    }
722
723
    /**
724
     * 路由调度
725
     * @param Request $request
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
726
     * @param Closure $withRoute
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
727
     * @return Response
728
     */
729
    public function dispatch(Request $request, $withRoute = null)
730
    {
731
        $this->request = $request;
732
        $this->host    = $this->request->host(true);
733
734
        if ($withRoute) {
735
            $checkCallback = function () use ($request, $withRoute) {
0 ignored issues
show
Unused Code introduced by
The import $request is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
736
                //加载路由
737
                $withRoute();
738
                return $this->check();
739
            };
740
741
            if ($this->config['route_check_cache']) {
742
                $dispatch = $this->cache
743
                    ->tag('route_cache')
744
                    ->remember($this->getRouteCacheKey($request), $checkCallback);
745
            } else {
746
                $dispatch = $checkCallback();
747
            }
748
        } else {
749
            $dispatch = $this->url($this->path());
750
        }
751
752
        $dispatch->init($this->app);
753
754
        $this->app->middleware->add(function () use ($dispatch) {
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...
755
            try {
756
                $response = $dispatch->run();
757
            } catch (HttpResponseException $exception) {
758
                $response = $exception->getResponse();
759
            }
760
            return $response;
761
        });
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...
762
763
        return $this->app->middleware->dispatch($request);
764
    }
765
766
    /**
767
     * 获取路由缓存Key
768
     * @access protected
769
     * @param Request $request
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
770
     * @return string
771
     */
772
    protected function getRouteCacheKey(Request $request): string
773
    {
774
        if (!empty($this->config['route_check_cache_key'])) {
775
            $closure  = $this->config['route_check_cache_key'];
776
            $routeKey = $closure($request);
777
        } else {
778
            $routeKey = md5($request->baseUrl(true) . ':' . $request->method());
779
        }
780
781
        return $routeKey;
782
    }
783
784
    /**
785
     * 检测URL路由
786
     * @access public
787
     * @return Dispatch
788
     * @throws RouteNotFoundException
789
     */
790
    public function check(): Dispatch
791
    {
792
        // 自动检测域名路由
793
        $url = str_replace($this->config['pathinfo_depr'], '|', $this->path());
794
795
        $completeMatch = $this->config['route_complete_match'];
796
797
        $result = $this->checkDomain()->check($this->request, $url, $completeMatch);
798
799
        if (false === $result && !empty($this->cross)) {
800
            // 检测跨域路由
801
            $result = $this->cross->check($this->request, $url, $completeMatch);
802
        }
803
804
        if (false !== $result) {
805
            return $result;
806
        } elseif ($this->config['url_route_must']) {
807
            throw new RouteNotFoundException();
808
        }
809
810
        return $this->url($url);
811
    }
812
813
    /**
814
     * 获取当前请求URL的pathinfo信息(不含URL后缀)
815
     * @access protected
816
     * @return string
817
     */
818
    protected function path(): string
819
    {
820
        $suffix   = $this->config['url_html_suffix'];
821
        $pathinfo = $this->request->pathinfo();
822
823
        if (false === $suffix) {
824
            // 禁止伪静态访问
825
            $path = $pathinfo;
826
        } elseif ($suffix) {
827
            // 去除正常的URL后缀
828
            $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
829
        } else {
830
            // 允许任何后缀访问
831
            $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
832
        }
833
834
        return $path;
835
    }
836
837
    /**
838
     * 默认URL解析
839
     * @access public
840
     * @param string $url URL地址
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
841
     * @return Dispatch
842
     */
843
    public function url(string $url): UrlDispatch
844
    {
845
        return new UrlDispatch($this->request, $this->group, $url);
846
    }
847
848
    /**
849
     * 检测域名的路由规则
850
     * @access protected
851
     * @return Domain
852
     */
853
    protected function checkDomain(): Domain
854
    {
855
        $item = false;
856
857
        if (count($this->domains) > 1) {
858
            // 获取当前子域名
859
            $subDomain = $this->request->subDomain();
860
861
            $domain  = $subDomain ? explode('.', $subDomain) : [];
862
            $domain2 = $domain ? array_pop($domain) : '';
863
864
            if ($domain) {
865
                // 存在三级域名
866
                $domain3 = array_pop($domain);
867
            }
868
869
            if (isset($this->domains[$this->host])) {
870
                // 子域名配置
871
                $item = $this->domains[$this->host];
872
            } elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) {
873
                // 泛三级域名
874
                $item      = $this->domains['*.' . $domain2];
875
                $panDomain = $domain3;
876
            } elseif (isset($this->domains['*']) && !empty($domain2)) {
877
                // 泛二级域名
878
                if ('www' != $domain2) {
879
                    $item      = $this->domains['*'];
880
                    $panDomain = $domain2;
881
                }
882
            }
883
884
            if (isset($panDomain)) {
885
                // 保存当前泛域名
886
                $this->request->setPanDomain($panDomain);
887
            }
888
        }
889
890
        if (false === $item) {
891
            // 检测全局域名规则
892
            $item = $this->domains['-'];
893
        }
894
895
        if (is_string($item)) {
896
            $item = $this->domains[$item];
897
        }
898
899
        return $item;
900
    }
901
902
    /**
903
     * URL生成 支持路由反射
904
     * @access public
905
     * @param  string       $url 路由地址
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
906
     * @param  array|string $vars 参数 ['a'=>'val1', 'b'=>'val2']
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
907
     * @param  string|bool  $suffix 伪静态后缀,默认为true表示获取配置值
908
     * @param  bool|string  $domain 是否显示域名 或者直接传入域名
909
     * @return string
910
     */
911
    public function buildUrl(string $url = '', array $vars = [], $suffix = true, $domain = false): string
912
    {
913
        // 解析URL
914
        if (0 === strpos($url, '[') && $pos = strpos($url, ']')) {
915
            // [name] 表示使用路由命名标识生成URL
916
            $name = substr($url, 1, $pos - 1);
917
            $url  = 'name' . substr($url, $pos + 1);
918
        }
919
920
        if (false === strpos($url, '://') && 0 !== strpos($url, '/')) {
921
            $info = parse_url($url);
922
            $url  = !empty($info['path']) ? $info['path'] : '';
923
924
            if (isset($info['fragment'])) {
925
                // 解析锚点
926
                $anchor = $info['fragment'];
927
928
                if (false !== strpos($anchor, '?')) {
929
                    // 解析参数
930
                    list($anchor, $info['query']) = explode('?', $anchor, 2);
931
                }
932
933
                if (false !== strpos($anchor, '@')) {
934
                    // 解析域名
935
                    list($anchor, $domain) = explode('@', $anchor, 2);
936
                }
937
            } elseif (strpos($url, '@') && false === strpos($url, '\\')) {
938
                // 解析域名
939
                list($url, $domain) = explode('@', $url, 2);
940
            }
941
        }
942
943
        $this->showDomain = false === $domain ? false : true;
944
945
        if ($url) {
946
            $checkName   = isset($name) ? $name : $url . (isset($info['query']) ? '?' . $info['query'] : '');
947
            $checkDomain = $domain && is_string($domain) ? $domain : null;
948
949
            $rule = $this->getName($checkName, $checkDomain);
950
951
            if (empty($rule) && isset($info['query'])) {
952
                $rule = $this->getName($url, $checkDomain);
953
                // 解析地址里面参数 合并到vars
954
                parse_str($info['query'], $params);
955
                $vars = array_merge($params, $vars);
956
                unset($info['query']);
957
            }
958
        }
959
960
        if (!empty($rule) && $match = $this->getRuleUrl($rule, $vars, $domain)) {
961
            // 匹配路由命名标识
962
            $url = $match[0];
963
964
            if (!empty($match[1])) {
965
                $domain = $match[1];
966
            }
967
968
            if (!is_null($match[2])) {
969
                $suffix = $match[2];
970
            }
971
972
            if ($this->request->app() && $this->app->config->get('app.auto_multi_app') && !$this->app->http->isBindDomain()) {
973
                $url = $this->request->app() . '/' . $url;
974
            }
975
        } elseif (!empty($rule) && isset($name)) {
976
            throw new \InvalidArgumentException('route name not exists:' . $name);
977
        } else {
978
            // 检测URL绑定
979
            $bind = $this->getDomainBind($domain && is_string($domain) ? $domain : null);
980
981
            if ($bind && 0 === strpos($url, $bind)) {
982
                $url = substr($url, strlen($bind) + 1);
983
            } else {
984
                $binds = $this->getBind();
985
986
                foreach ($binds as $key => $val) {
987
                    if (is_string($val) && 0 === strpos($url, $val) && substr_count($val, '/') > 1) {
988
                        $url    = substr($url, strlen($val) + 1);
989
                        $domain = $key;
990
                        break;
991
                    }
992
                }
993
            }
994
995
            // 路由标识不存在 直接解析
996
            $url = $this->parseUrl($url, $domain);
997
998
            if (isset($info['query'])) {
999
                // 解析地址里面参数 合并到vars
1000
                parse_str($info['query'], $params);
1001
                $vars = array_merge($params, $vars);
1002
            }
1003
        }
1004
1005
        // 还原URL分隔符
1006
        $depr = $this->config['pathinfo_depr'];
1007
        $url  = str_replace('/', $depr, $url);
1008
1009
        $file = $this->request->baseFile();
1010
        if ($file && 0 !== strpos($this->request->url(), $file)) {
1011
            $file = str_replace('\\', '/', dirname($file));
1012
        }
1013
1014
        $url = rtrim($file, '/') . '/' . $url;
1015
1016
        // URL后缀
1017
        if ('/' == substr($url, -1) || '' == $url) {
1018
            $suffix = '';
1019
        } else {
1020
            $suffix = $this->parseSuffix($suffix);
1021
        }
1022
1023
        // 锚点
1024
        $anchor = !empty($anchor) ? '#' . $anchor : '';
1025
1026
        // 参数组装
1027
        if (!empty($vars)) {
1028
            // 添加参数
1029
            if ($this->config['url_common_param']) {
1030
                $vars = http_build_query($vars);
1031
                $url .= $suffix . '?' . $vars . $anchor;
1032
            } else {
1033
                foreach ($vars as $var => $val) {
1034
                    if ('' !== $val) {
1035
                        $url .= $depr . $var . $depr . urlencode((string) $val);
1036
                    }
1037
                }
1038
1039
                $url .= $suffix . $anchor;
1040
            }
1041
        } else {
1042
            $url .= $suffix . $anchor;
1043
        }
1044
1045
        // 检测域名
1046
        $domain = $this->parseDomain($url, $domain);
1047
1048
        // URL组装
1049
        return $domain . '/' . ltrim($url, '/');
1050
    }
1051
1052
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $domain should have a doc-comment as per coding-style.
Loading history...
1053
     * 直接解析URL地址
1054
     * @access public
1055
     * @param  string $url URL
1056
     * @return string
1057
     */
1058
    protected function parseUrl(string $url, &$domain): string
1059
    {
1060
        $request = $this->request;
1061
1062
        if (0 === strpos($url, '/')) {
1063
            // 直接作为路由地址解析
1064
            $url = substr($url, 1);
1065
        } elseif (false !== strpos($url, '\\')) {
1066
            // 解析到类
1067
            $url = ltrim(str_replace('\\', '/', $url), '/');
1068
        } elseif (0 === strpos($url, '@')) {
1069
            // 解析到控制器
1070
            $url = substr($url, 1);
1071
        } else {
1072
            // 解析到 应用/控制器/操作
1073
            $app        = $request->app();
1074
            $controller = $request->controller();
1075
1076
            if ('' == $url) {
1077
                $action = $request->action();
1078
            } else {
1079
                $path       = explode('/', $url);
1080
                $action     = array_pop($path);
1081
                $controller = empty($path) ? $controller : array_pop($path);
1082
                $app        = empty($path) ? $app : array_pop($path);
1083
            }
1084
1085
            if ($this->config['url_convert']) {
1086
                $action     = strtolower($action);
1087
                $controller = App::parseName($controller);
1088
            }
1089
1090
            $url = $controller . '/' . $action;
1091
1092
            if ($app && $this->app->config->get('app.auto_multi_app')) {
1093
                $bind = $this->app->config->get('app.domain_bind', []);
1094
                if ($key = array_search($app, $bind)) {
1095
                    $domain = true === $domain ? $key : $domain;
1096
                } else {
1097
                    $map = $this->app->config->get('app.app_map', []);
1098
1099
                    if ($key = array_search($app, $map)) {
1100
                        $url = $key . '/' . $url;
1101
                    } else {
1102
                        $url = $app . '/' . $url;
1103
                    }
1104
                }
1105
            }
1106
        }
1107
1108
        return $url;
1109
    }
1110
1111
    /**
1112
     * 检测域名
1113
     * @access public
1114
     * @param  string      $url URL
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
1115
     * @param  string|true $domain 域名
1116
     * @return string
1117
     */
1118
    protected function parseDomain(string &$url, $domain): string
1119
    {
1120
        if (!$domain) {
1121
            return '';
1122
        }
1123
1124
        $rootDomain = $this->request->rootDomain();
1125
        if (true === $domain) {
1126
            // 自动判断域名
1127
            $domain  = $this->request->host();
1128
            $domains = $this->getDomains();
1129
1130
            if (!empty($domains)) {
1131
                $route_domain = array_keys($domains);
1132
                foreach ($route_domain as $domain_prefix) {
1133
                    if (0 === strpos($domain_prefix, '*.') && strpos($domain, ltrim($domain_prefix, '*.')) !== false) {
1134
                        foreach ($domains as $key => $rule) {
1135
                            $rule = is_array($rule) ? $rule[0] : $rule;
1136
                            if (is_string($rule) && false === strpos($key, '*') && 0 === strpos($url, $rule)) {
1137
                                $url    = ltrim($url, $rule);
1138
                                $domain = $key;
1139
1140
                                // 生成对应子域名
1141
                                if (!empty($rootDomain)) {
1142
                                    $domain .= $rootDomain;
1143
                                }
1144
                                break;
1145
                            } elseif (false !== strpos($key, '*')) {
1146
                                if (!empty($rootDomain)) {
1147
                                    $domain .= $rootDomain;
1148
                                }
1149
1150
                                break;
1151
                            }
1152
                        }
1153
                    }
1154
                }
1155
            }
1156
        } elseif (false === strpos($domain, '.') && 0 !== strpos($domain, $rootDomain)) {
1157
            $domain .= '.' . $rootDomain;
1158
        }
1159
1160
        if (false !== strpos($domain, '://')) {
1161
            $scheme = '';
1162
        } else {
1163
            $scheme = $this->request->isSsl() ? 'https://' : 'http://';
1164
        }
1165
1166
        return $this->request->host() == $domain && !$this->showDomain ? '' : $scheme . $domain;
1167
    }
1168
1169
    /**
1170
     * 解析URL后缀
1171
     * @access public
1172
     * @param  string|bool $suffix 后缀
1173
     * @return string
1174
     */
1175
    protected function parseSuffix($suffix): string
1176
    {
1177
        if ($suffix) {
1178
            $suffix = true === $suffix ? $this->config['url_html_suffix'] : $suffix;
1179
1180
            if ($pos = strpos($suffix, '|')) {
1181
                $suffix = substr($suffix, 0, $pos);
1182
            }
1183
        }
1184
1185
        return (empty($suffix) || 0 === strpos($suffix, '.')) ? (string) $suffix : '.' . $suffix;
1186
    }
1187
1188
    /**
1189
     * 匹配路由地址
1190
     * @access public
1191
     * @param  array $rule 路由规则
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter name; 1 found
Loading history...
1192
     * @param  array $vars 路由变量
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter name; 1 found
Loading history...
1193
     * @param  mixed $allowDomain 允许域名
1194
     * @return array
1195
     */
1196
    public function getRuleUrl(array $rule, array &$vars = [], $allowDomain = ''): array
1197
    {
1198
        foreach ($rule as $item) {
1199
            list($url, $pattern, $domain, $suffix) = $item;
1200
1201
            if ('-' == $domain) {
1202
                $domain = $this->host;
1203
            }
1204
1205
            if (is_string($allowDomain) && $domain != $allowDomain) {
1206
                continue;
1207
            }
1208
1209
            if (!in_array($this->request->port(), [80, 443])) {
1210
                $domain .= ':' . $this->request->port();
1211
            }
1212
1213
            if (empty($pattern)) {
1214
                return [rtrim($url, '?/-'), $domain, $suffix];
1215
            }
1216
1217
            $type = $this->config['url_common_param'];
1218
1219
            foreach ($pattern as $key => $val) {
1220
                if (isset($vars[$key])) {
1221
                    $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key, '<' . $key . '>'], $type ? $vars[$key] : urlencode((string) $vars[$key]), $url);
1222
                    unset($vars[$key]);
1223
                    $url    = str_replace(['/?', '-?'], ['/', '-'], $url);
1224
                    $result = [rtrim($url, '?/-'), $domain, $suffix];
1225
                } elseif (2 == $val) {
1226
                    $url    = str_replace(['/[:' . $key . ']', '[:' . $key . ']', '<' . $key . '?>'], '', $url);
1227
                    $url    = str_replace(['/?', '-?'], ['/', '-'], $url);
1228
                    $result = [rtrim($url, '?/-'), $domain, $suffix];
1229
                } else {
1230
                    break;
1231
                }
1232
            }
1233
1234
            if (isset($result)) {
1235
                return $result;
1236
            }
1237
        }
1238
1239
        return [];
1240
    }
1241
1242
    /**
1243
     * 设置全局的路由分组参数
1244
     * @access public
1245
     * @param string $method 方法名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1246
     * @param array  $args   调用参数
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
1247
     * @return RuleGroup
1248
     */
1249
    public function __call($method, $args)
1250
    {
1251
        return call_user_func_array([$this->group, $method], $args);
1252
    }
1253
}
1254