Completed
Push — 6.0 ( 1e69d2...64aa8b )
by yun
02:11
created

Route   F

Complexity

Total Complexity 99

Size/Duplication

Total Lines 893
Duplicated Lines 0 %

Test Coverage

Coverage 60.5%

Importance

Changes 16
Bugs 0 Features 0
Metric Value
eloc 226
c 16
b 0
f 0
dl 0
loc 893
ccs 144
cts 238
cp 0.605
rs 2
wmc 99

48 Methods

Rating   Name   Duplication   Size   Complexity  
A patch() 0 3 1
A any() 0 3 1
A delete() 0 3 1
A option() 0 5 1
A setCrossDomainRule() 0 9 2
A pattern() 0 5 1
A mergeRuleRegex() 0 6 1
A setTestMode() 0 3 1
A options() 0 3 1
A getRuleList() 0 3 1
A isTest() 0 3 1
A setRule() 0 3 1
A getDomains() 0 3 1
A import() 0 3 1
A setName() 0 3 1
A bind() 0 7 2
A setDefaultDomain() 0 9 1
A getGroup() 0 3 2
A getRuleName() 0 3 1
A lazy() 0 4 1
A getBind() 0 3 1
A getRule() 0 3 1
A setGroup() 0 3 1
A clear() 0 6 2
A getName() 0 3 1
A config() 0 7 2
A get() 0 3 1
A group() 0 11 2
A resource() 0 4 1
A put() 0 3 1
A post() 0 3 1
A domain() 0 25 6
A view() 0 5 1
A rule() 0 9 2
B getDomainBind() 0 27 11
A init() 0 11 2
A __construct() 0 12 2
A rest() 0 9 3
A getRest() 0 7 2
A dispatch() 0 22 3
A path() 0 17 3
A url() 0 10 2
A miss() 0 3 1
A check() 0 21 5
A __call() 0 3 1
A buildUrl() 0 3 1
F checkDomain() 0 49 15
A redirect() 0 17 2

How to fix   Complexity   

Complex Class

Complex classes like Route often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Route, and based on these observations, apply Extract Interface, too.

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

466
        $this->ruleName->setRule($rule, /** @scrutinizer ignore-type */ $ruleItem);
Loading history...
467 30
    }
468
469
    /**
470
     * 读取路由
471
     * @access public
472
     * @param string $rule 路由规则
473
     * @return RuleItem[]
474
     */
475 3
    public function getRule(string $rule): array
476
    {
477 3
        return $this->ruleName->getRule($rule);
478
    }
479
480
    /**
481
     * 读取路由列表
482
     * @access public
483
     * @return array
484
     */
485
    public function getRuleList(): array
486
    {
487
        return $this->ruleName->getRuleList();
488
    }
489
490
    /**
491
     * 清空路由规则
492
     * @access public
493
     * @return void
494
     */
495
    public function clear(): void
496
    {
497
        $this->ruleName->clear();
498
499
        if ($this->group) {
500
            $this->group->clear();
501
        }
502
    }
503
504
    /**
505
     * 注册路由规则
506
     * @access public
507
     * @param string $rule   路由规则
508
     * @param mixed  $route  路由地址
509
     * @param string $method 请求类型
510
     * @return RuleItem
511
     */
512 30
    public function rule(string $rule, $route = null, string $method = '*'): RuleItem
513
    {
514 30
        if ($route instanceof Response) {
515
            // 兼容之前的路由到响应对象,感觉不需要,使用场景很少,闭包就能实现
516
            $route = function () use ($route) {
517 3
                return $route;
518 3
            };
519
        }
520 30
        return $this->group->addRule($rule, $route, $method);
521
    }
522
523
    /**
524
     * 设置跨域有效路由规则
525
     * @access public
526
     * @param Rule   $rule   路由规则
527
     * @param string $method 请求类型
528
     * @return $this
529
     */
530
    public function setCrossDomainRule(Rule $rule, string $method = '*')
531
    {
532
        if (!isset($this->cross)) {
533
            $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
534
        }
535
536
        $this->cross->addRuleItem($rule, $method);
537
538
        return $this;
539
    }
540
541
    /**
542
     * 注册路由分组
543
     * @access public
544
     * @param string|\Closure $name  分组名称或者参数
545
     * @param mixed           $route 分组路由
546
     * @return RuleGroup
547
     */
548 6
    public function group($name, $route = null): RuleGroup
549
    {
550 6
        if ($name instanceof Closure) {
551 6
            $route = $name;
552 6
            $name  = '';
553
        }
554
555 6
        return (new RuleGroup($this, $this->group, $name, $route))
556 6
            ->lazy($this->lazy)
557 6
            ->removeSlash($this->removeSlash)
558 6
            ->mergeRuleRegex($this->mergeRuleRegex);
559
    }
560
561
    /**
562
     * 注册路由
563
     * @access public
564
     * @param string $rule  路由规则
565
     * @param mixed  $route 路由地址
566
     * @return RuleItem
567
     */
568
    public function any(string $rule, $route): RuleItem
569
    {
570
        return $this->rule($rule, $route, '*');
571
    }
572
573
    /**
574
     * 注册GET路由
575
     * @access public
576
     * @param string $rule  路由规则
577
     * @param mixed  $route 路由地址
578
     * @return RuleItem
579
     */
580 24
    public function get(string $rule, $route): RuleItem
581
    {
582 24
        return $this->rule($rule, $route, 'GET');
583
    }
584
585
    /**
586
     * 注册POST路由
587
     * @access public
588
     * @param string $rule  路由规则
589
     * @param mixed  $route 路由地址
590
     * @return RuleItem
591
     */
592 6
    public function post(string $rule, $route): RuleItem
593
    {
594 6
        return $this->rule($rule, $route, 'POST');
595
    }
596
597
    /**
598
     * 注册PUT路由
599
     * @access public
600
     * @param string $rule  路由规则
601
     * @param mixed  $route 路由地址
602
     * @return RuleItem
603
     */
604 6
    public function put(string $rule, $route): RuleItem
605
    {
606 6
        return $this->rule($rule, $route, 'PUT');
607
    }
608
609
    /**
610
     * 注册DELETE路由
611
     * @access public
612
     * @param string $rule  路由规则
613
     * @param mixed  $route 路由地址
614
     * @return RuleItem
615
     */
616
    public function delete(string $rule, $route): RuleItem
617
    {
618
        return $this->rule($rule, $route, 'DELETE');
619
    }
620
621
    /**
622
     * 注册PATCH路由
623
     * @access public
624
     * @param string $rule  路由规则
625
     * @param mixed  $route 路由地址
626
     * @return RuleItem
627
     */
628
    public function patch(string $rule, $route): RuleItem
629
    {
630
        return $this->rule($rule, $route, 'PATCH');
631
    }
632
633
    /**
634
     * 注册OPTIONS路由
635
     * @access public
636
     * @param string $rule  路由规则
637
     * @param mixed  $route 路由地址
638
     * @return RuleItem
639
     */
640
    public function options(string $rule, $route): RuleItem
641
    {
642
        return $this->rule($rule, $route, 'OPTIONS');
643
    }
644
645
    /**
646
     * 注册资源路由
647
     * @access public
648
     * @param string $rule  路由规则
649
     * @param string $route 路由地址
650
     * @return Resource
651
     */
652 3
    public function resource(string $rule, string $route): Resource
653
    {
654 3
        return (new Resource($this, $this->group, $rule, $route, $this->rest))
655 3
            ->lazy($this->lazy);
656
    }
657
658
    /**
659
     * 注册视图路由
660
     * @access public
661
     * @param string $rule     路由规则
662
     * @param string $template 路由模板地址
663
     * @param array  $vars     模板变量
664
     * @return RuleItem
665
     */
666 3
    public function view(string $rule, string $template = '', array $vars = []): RuleItem
667
    {
668
        return $this->rule($rule, function () use ($vars, $template) {
669 3
            return Response::create($template, 'view')->assign($vars);
0 ignored issues
show
Bug introduced by
The method assign() does not exist on think\Response. It seems like you code against a sub-type of think\Response such as think\response\View. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

669
            return Response::create($template, 'view')->/** @scrutinizer ignore-call */ assign($vars);
Loading history...
670 3
        }, 'GET');
671
    }
672
673
    /**
674
     * 注册重定向路由
675
     * @access public
676
     * @param string $rule   路由规则
677
     * @param string $route  路由地址
678
     * @param int    $status 状态码
679
     * @return RuleItem
680
     */
681 3
    public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
682
    {
683
        return $this->rule($rule, function (Request $request) use ($status, $route) {
684 3
            $search  = $replace  = [];
685 3
            $matches = $request->rule()->getVars();
686
687
            foreach ($matches as $key => $value) {
688
                $search[]  = '<' . $key . '>';
689
                $replace[] = $value;
690
691
                $search[]  = ':' . $key;
692
                $replace[] = $value;
693
            }
694
695
            $route = str_replace($search, $replace, $route);
696
            return Response::create($route, 'redirect')->code($status);
697 3
        }, '*');
698
    }
699
700
    /**
701
     * rest方法定义和修改
702
     * @access public
703
     * @param string|array $name     方法名称
704
     * @param array|bool   $resource 资源
705
     * @return $this
706
     */
707
    public function rest($name, $resource = [])
708
    {
709
        if (is_array($name)) {
710
            $this->rest = $resource ? $name : array_merge($this->rest, $name);
711
        } else {
712
            $this->rest[$name] = $resource;
713
        }
714
715
        return $this;
716
    }
717
718
    /**
719
     * 获取rest方法定义的参数
720
     * @access public
721
     * @param string $name 方法名称
722
     * @return array|null
723
     */
724
    public function getRest(string $name = null)
725
    {
726
        if (is_null($name)) {
727
            return $this->rest;
728
        }
729
730
        return $this->rest[$name] ?? null;
731
    }
732
733
    /**
734
     * 注册未匹配路由规则后的处理
735
     * @access public
736
     * @param string|Closure $route  路由地址
737
     * @param string         $method 请求类型
738
     * @return RuleItem
739
     */
740
    public function miss($route, string $method = '*'): RuleItem
741
    {
742
        return $this->group->miss($route, $method);
743
    }
744
745
    /**
746
     * 路由调度
747
     * @param Request $request
748
     * @param Closure|bool $withRoute
749
     * @return Response
750
     */
751 33
    public function dispatch(Request $request, $withRoute = true)
752
    {
753 33
        $this->request = $request;
754 33
        $this->host    = $this->request->host(true);
755 33
        $this->init();
756
757 33
        if ($withRoute) {
758
            //加载路由
759 33
            if ($withRoute instanceof Closure) {
760
                $withRoute();
761
            }
762 33
            $dispatch = $this->check();
763
        } else {
764
            $dispatch = $this->url($this->path());
765
        }
766
767 33
        $dispatch->init($this->app);
768
769 33
        return $this->app->middleware->pipeline('route')
770 33
            ->send($request)
771
            ->then(function () use ($dispatch) {
772 33
                return $dispatch->run();
773 33
            });
774
    }
775
776
    /**
777
     * 检测URL路由
778
     * @access public
779
     * @return Dispatch|false
780
     * @throws RouteNotFoundException
781
     */
782 33
    public function check()
783
    {
784
        // 自动检测域名路由
785 33
        $url = str_replace($this->config['pathinfo_depr'], '|', $this->path());
786
787 33
        $completeMatch = $this->config['route_complete_match'];
788
789 33
        $result = $this->checkDomain()->check($this->request, $url, $completeMatch);
790
791 33
        if (false === $result && !empty($this->cross)) {
792
            // 检测跨域路由
793
            $result = $this->cross->check($this->request, $url, $completeMatch);
794
        }
795
796 33
        if (false !== $result) {
797 30
            return $result;
798 9
        } elseif ($this->config['url_route_must']) {
799
            throw new RouteNotFoundException();
800
        }
801
802 9
        return $this->url($url);
803
    }
804
805
    /**
806
     * 获取当前请求URL的pathinfo信息(不含URL后缀)
807
     * @access protected
808
     * @return string
809
     */
810 33
    protected function path(): string
811
    {
812 33
        $suffix   = $this->config['url_html_suffix'];
813 33
        $pathinfo = $this->request->pathinfo();
814
815 33
        if (false === $suffix) {
816
            // 禁止伪静态访问
817
            $path = $pathinfo;
818 33
        } elseif ($suffix) {
819
            // 去除正常的URL后缀
820 33
            $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
821
        } else {
822
            // 允许任何后缀访问
823
            $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
824
        }
825
826 33
        return $path;
827
    }
828
829
    /**
830
     * 默认URL解析
831
     * @access public
832
     * @param string $url URL地址
833
     * @return Dispatch
834
     */
835 9
    public function url(string $url): Dispatch
836
    {
837 9
        if ($this->request->method() == 'OPTIONS') {
838
            // 自动响应options请求
839
            return new Callback($this->request, $this->group, function () {
840 6
                return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']);
841 6
            });
842
        }
843
844 3
        return new UrlDispatch($this->request, $this->group, $url);
845
    }
846
847
    /**
848
     * 检测域名的路由规则
849
     * @access protected
850
     * @return Domain
851
     */
852 33
    protected function checkDomain(): Domain
853
    {
854 33
        $item = false;
855
856 33
        if (count($this->domains) > 1) {
857
            // 获取当前子域名
858 3
            $subDomain = $this->request->subDomain();
859
860 3
            $domain  = $subDomain ? explode('.', $subDomain) : [];
861 3
            $domain2 = $domain ? array_pop($domain) : '';
862
863 3
            if ($domain) {
864
                // 存在三级域名
865
                $domain3 = array_pop($domain);
866
            }
867
868 3
            if (isset($this->domains[$this->host])) {
869
                // 子域名配置
870
                $item = $this->domains[$this->host];
871 3
            } elseif (isset($this->domains[$subDomain])) {
872 3
                $item = $this->domains[$subDomain];
873
            } elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) {
874
                // 泛三级域名
875
                $item      = $this->domains['*.' . $domain2];
876
                $panDomain = $domain3;
877
            } elseif (isset($this->domains['*']) && !empty($domain2)) {
878
                // 泛二级域名
879
                if ('www' != $domain2) {
880
                    $item      = $this->domains['*'];
881
                    $panDomain = $domain2;
882
                }
883
            }
884
885 3
            if (isset($panDomain)) {
886
                // 保存当前泛域名
887
                $this->request->setPanDomain($panDomain);
888
            }
889
        }
890
891 33
        if (false === $item) {
892
            // 检测全局域名规则
893 30
            $item = $this->domains['-'];
894
        }
895
896 33
        if (is_string($item)) {
897
            $item = $this->domains[$item];
898
        }
899
900 33
        return $item;
901
    }
902
903
    /**
904
     * URL生成 支持路由反射
905
     * @access public
906
     * @param string $url  路由地址
907
     * @param array  $vars 参数 ['a'=>'val1', 'b'=>'val2']
908
     * @return UrlBuild
909
     */
910
    public function buildUrl(string $url = '', array $vars = []): UrlBuild
911
    {
912
        return $this->app->make(UrlBuild::class, [$this, $this->app, $url, $vars], true);
913
    }
914
915
    /**
916
     * 设置全局的路由分组参数
917
     * @access public
918
     * @param string $method 方法名
919
     * @param array  $args   调用参数
920
     * @return RuleGroup
921
     */
922
    public function __call($method, $args)
923
    {
924
        return call_user_func_array([$this->group, $method], $args);
925
    }
926
}
927