Passed
Push — 8.0 ( 1d487f...814364 )
by liu
02:38
created

Route::checkDomain()   F

Complexity

Conditions 15
Paths 388

Size

Total Lines 49
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 32.0416

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 15
eloc 25
c 1
b 0
f 0
nc 388
nop 0
dl 0
loc 49
ccs 15
cts 26
cp 0.5769
crap 32.0416
rs 2.7333

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2023 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\Domain;
19
use think\route\Resource;
20
use think\route\ResourceRegister;
21
use think\route\Rule;
22
use think\route\RuleGroup;
23
use think\route\RuleItem;
24
use think\route\RuleName;
25
use think\route\Url as UrlBuild;
26
use think\route\UrlRuleItem;
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
        'url_case_sensitive'    => false,
61
        // 合并路由规则
62
        'route_rule_merge'      => false,
63
        // 路由是否完全匹配
64
        'route_complete_match'  => false,
65
        // 去除斜杠
66
        'remove_slash'          => false,
67
        // 使用注解路由
68
        'route_annotation'      => false,
69
        // 默认的路由变量规则
70
        'default_route_pattern' => '[\w\.]+',
71
        // URL伪静态后缀
72
        'url_html_suffix'       => 'html',
73
        // 访问控制器层名称
74
        'controller_layer'      => 'controller',
75
        // 空控制器名
76
        'empty_controller'      => 'Error',
77
        // 是否使用控制器后缀
78
        'controller_suffix'     => false,
79
        // 默认路由 [路由规则, 路由地址]
80
        'default_route'         =>  [],
81
        // 默认控制器名
82
        'default_controller'    => 'Index',
83
        // 默认操作名
84
        'default_action'        => 'index',
85
        // 操作方法后缀
86
        'action_suffix'         => '',
87
        // 非路由变量是否使用普通参数方式(用于URL生成)
88
        'url_common_param'      => true,
89
    ];
90
91
    /**
92
     * 请求对象
93
     * @var Request
94
     */
95
    protected $request;
96
97
    /**
98
     * @var RuleName
99
     */
100
    protected $ruleName;
101
102
    /**
103
     * 当前HOST
104
     * @var string
105
     */
106
    protected $host;
107
108
    /**
109
     * 当前分组对象
110
     * @var RuleGroup
111
     */
112
    protected $group;
113
114
    /**
115
     * 路由绑定
116
     * @var array
117
     */
118
    protected $bind = [];
119
120
    /**
121
     * 域名对象
122
     * @var Domain[]
123
     */
124
    protected $domains = [];
125
126
    /**
127
     * 跨域路由规则
128
     * @var RuleGroup
129
     */
130
    protected $cross;
131
132
    /**
133
     * 路由是否延迟解析
134
     * @var bool
135
     */
136
    protected $lazy = false;
137
138
    /**
139
     * (分组)路由规则是否合并解析
140
     * @var bool
141
     */
142
    protected $mergeRuleRegex = false;
143
144
    /**
145
     * 是否去除URL最后的斜线
146
     * @var bool
147
     */
148
    protected $removeSlash = false;
149
150 27
    public function __construct(protected App $app)
151
    {
152 27
        $this->ruleName = new RuleName();
153 27
        $this->setDefaultDomain();
154
155 27
        if (is_file($this->app->getRuntimePath() . 'route.php')) {
156
            // 读取路由映射文件
157
            $this->import(include $this->app->getRuntimePath() . 'route.php');
158
        }
159
160 27
        $this->config = array_merge($this->config, $this->app->config->get('route'));
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get('route') can also be of type null; however, parameter $arrays of array_merge() does only seem to accept array, 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

160
        $this->config = array_merge($this->config, /** @scrutinizer ignore-type */ $this->app->config->get('route'));
Loading history...
161
162 27
        $this->init();
163
    }
164
165 27
    protected function init()
166
    {
167 27
        if (!empty($this->config['middleware'])) {
168
            $this->app->middleware->import($this->config['middleware'], 'route');
169
        }
170
171 27
        $this->lazy($this->config['url_lazy_route']);
172 27
        $this->mergeRuleRegex = $this->config['route_rule_merge'];
173 27
        $this->removeSlash    = $this->config['remove_slash'];
174
175 27
        $this->group->removeSlash($this->removeSlash);
176
177
        // 注册全局MISS路由
178 27
        $this->miss(function () {
179 3
            return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']);
180 27
        }, 'options');
181
    }
182
183 27
    public function config(?string $name = null)
184
    {
185 27
        if (is_null($name)) {
186
            return $this->config;
187
        }
188
189 27
        return $this->config[$name] ?? null;
190
    }
191
192
    /**
193
     * 设置路由域名及分组(包括资源路由)是否延迟解析
194
     * @access public
195
     * @param bool $lazy 路由是否延迟解析
196
     * @return $this
197
     */
198 27
    public function lazy(bool $lazy = true)
199
    {
200 27
        $this->lazy = $lazy;
201 27
        return $this;
202
    }
203
204
    /**
205
     * 设置路由域名及分组(包括资源路由)是否合并解析
206
     * @access public
207
     * @param bool $merge 路由是否合并解析
208
     * @return $this
209
     */
210
    public function mergeRuleRegex(bool $merge = true)
211
    {
212
        $this->mergeRuleRegex = $merge;
213
        $this->group->mergeRuleRegex($merge);
214
215
        return $this;
216
    }
217
218
    /**
219
     * 初始化默认域名
220
     * @access protected
221
     * @return void
222
     */
223 27
    protected function setDefaultDomain(): void
224
    {
225
        // 注册默认域名
226 27
        $domain = new Domain($this);
227
228 27
        $this->domains['-'] = $domain;
229
230
        // 默认分组
231 27
        $this->group = $domain;
232
    }
233
234
    /**
235
     * 设置当前分组
236
     * @access public
237
     * @param RuleGroup $group 域名
238
     * @return void
239
     */
240 27
    public function setGroup(RuleGroup $group): void
241
    {
242 27
        $this->group = $group;
243
    }
244
245
    /**
246
     * 获取指定标识的路由分组 不指定则获取当前分组
247
     * @access public
248
     * @param string $name 分组标识
249
     * @return RuleGroup
250
     */
251 27
    public function getGroup(?string $name = null)
252
    {
253 27
        return $name ? $this->ruleName->getGroup($name) : $this->group;
254
    }
255
256
    /**
257
     * 注册变量规则
258
     * @access public
259
     * @param array $pattern 变量规则
260
     * @return $this
261
     */
262
    public function pattern(array $pattern)
263
    {
264
        $this->group->pattern($pattern);
265
266
        return $this;
267
    }
268
269
    /**
270
     * 注册路由参数
271
     * @access public
272
     * @param array $option 参数
273
     * @return $this
274
     */
275
    public function option(array $option)
276
    {
277
        $this->group->option($option);
278
279
        return $this;
280
    }
281
282
    /**
283
     * 注册域名路由
284
     * @access public
285
     * @param string|array $name 子域名
286
     * @param mixed        $rule 路由规则
287
     * @return Domain
288
     */
289 3
    public function domain(string | array $name, $rule = null): Domain
290
    {
291
        // 支持多个域名使用相同路由规则
292 3
        $domainName = is_array($name) ? array_shift($name) : $name;
0 ignored issues
show
introduced by
The condition is_array($name) is always true.
Loading history...
293
294 3
        if (!isset($this->domains[$domainName])) {
295 3
            $domain = (new Domain($this, $domainName, $rule, $this->lazy))
296 3
                ->removeSlash($this->removeSlash)
297 3
                ->mergeRuleRegex($this->mergeRuleRegex);
298
299 3
            $this->domains[$domainName] = $domain;
300
        } else {
301
            $domain = $this->domains[$domainName];
302
            $domain->parseGroupRule($rule);
303
        }
304
305 3
        if (is_array($name) && !empty($name)) {
306
            foreach ($name as $item) {
307
                $this->domains[$item] = $domainName;
308
            }
309
        }
310
311
        // 返回域名对象
312 3
        return $domain;
313
    }
314
315
    /**
316
     * 获取域名
317
     * @access public
318
     * @return array
319
     */
320
    public function getDomains(): array
321
    {
322
        return $this->domains;
323
    }
324
325
    /**
326
     * 获取RuleName对象
327
     * @access public
328
     * @return RuleName
329
     */
330
    public function getRuleName(): RuleName
331
    {
332
        return $this->ruleName;
333
    }
334
335
    /**
336
     * 设置路由绑定
337
     * @access public
338
     * @param string $bind   绑定信息
339
     * @param string $domain 域名
340
     * @return $this
341
     */
342
    public function bind(string $bind, ?string $domain = null)
343
    {
344
        $domain = is_null($domain) ? '-' : $domain;
345
346
        $this->bind[$domain] = $bind;
347
348
        return $this;
349
    }
350
351
    /**
352
     * 读取路由绑定信息
353
     * @access public
354
     * @return array
355
     */
356
    public function getBind(): array
357
    {
358
        return $this->bind;
359
    }
360
361
    /**
362
     * 读取路由绑定
363
     * @access public
364
     * @param string $domain 域名
365
     * @return string|null
366
     */
367 27
    public function getDomainBind(?string $domain = null)
368
    {
369 27
        if (is_null($domain)) {
370 24
            $domain = $this->host;
371 3
        } elseif (!str_contains($domain, '.') && $this->request) {
372 3
            $domain .= '.' . $this->request->rootDomain();
373
        }
374
375 27
        if ($this->request) {
376 27
            $subDomain = $this->request->subDomain();
377
378 27
            if (str_contains($subDomain, '.')) {
379
                $name = '*' . strstr($subDomain, '.');
380
            }
381
        }
382
383 27
        if (isset($this->bind[$domain])) {
384
            $result = $this->bind[$domain];
385 27
        } elseif (isset($name) && isset($this->bind[$name])) {
386
            $result = $this->bind[$name];
387 27
        } elseif (!empty($subDomain) && isset($this->bind['*'])) {
388
            $result = $this->bind['*'];
389
        } else {
390 27
            $result = null;
391
        }
392
393 27
        return $result;
394
    }
395
396
    /**
397
     * 读取路由标识
398
     * @access public
399
     * @param string $name   路由标识
400
     * @param string $domain 域名
401
     * @param string $method 请求类型
402
     * @return array
403
     */
404
    public function getName(?string $name = null, ?string $domain = null, string $method = '*'): array
405
    {
406
        return $this->ruleName->getName($name, $domain, $method);
407
    }
408
409
    /**
410
     * 批量导入路由标识
411
     * @access public
412
     * @param array $name 路由标识
413
     * @return void
414
     */
415
    public function import(array $name): void
416
    {
417
        $this->ruleName->import($name);
418
    }
419
420
    /**
421
     * 注册路由标识
422
     * @access public
423
     * @param string   $name     路由标识
424
     * @param RuleItem $ruleItem 路由规则
425
     * @param bool     $first    是否优先
426
     * @return void
427
     */
428 12
    public function setName(string $name, RuleItem $ruleItem, bool $first = false): void
429
    {
430 12
        $this->ruleName->setName($name, $ruleItem, $first);
431
    }
432
433
    /**
434
     * 保存路由规则
435
     * @access public
436
     * @param string   $rule     路由规则
437
     * @param RuleItem $ruleItem RuleItem对象
438
     * @return void
439
     */
440 27
    public function setRule(string $rule, ?RuleItem $ruleItem = null): void
441
    {
442 27
        $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

442
        $this->ruleName->setRule($rule, /** @scrutinizer ignore-type */ $ruleItem);
Loading history...
443
    }
444
445
    /**
446
     * 读取路由
447
     * @access public
448
     * @param string $rule 路由规则
449
     * @return RuleItem[]
450
     */
451
    public function getRule(string $rule): array
452
    {
453
        return $this->ruleName->getRule($rule);
454
    }
455
456
    /**
457
     * 读取路由列表
458
     * @access public
459
     * @return array
460
     */
461
    public function getRuleList(): array
462
    {
463
        return $this->ruleName->getRuleList();
464
    }
465
466
    /**
467
     * 清空路由规则
468
     * @access public
469
     * @return void
470
     */
471
    public function clear(): void
472
    {
473
        $this->ruleName->clear();
474
475
        if ($this->group) {
476
            $this->group->clear();
477
        }
478
    }
479
480
    /**
481
     * 注册路由规则
482
     * @access public
483
     * @param string $rule   路由规则
484
     * @param mixed  $route  路由地址
485
     * @param string $method 请求类型
486
     * @return RuleItem
487
     */
488 24
    public function rule(string $rule, $route = null, string $method = '*'): RuleItem
489
    {
490 24
        return $this->group->addRule($rule, $route, $method);
491
    }
492
493
    /**
494
     * 设置路由规则全局有效
495
     * @access public
496
     * @param Rule   $rule   路由规则
497
     * @return $this
498
     */
499
    public function setCrossDomainRule(Rule $rule)
500
    {
501
        if (!isset($this->cross)) {
502
            $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
503
        }
504
505
        $this->cross->addRuleItem($rule);
506
507
        return $this;
508
    }
509
510
    /**
511
     * 注册路由分组
512
     * @access public
513
     * @param string|Closure $name  分组名称或者参数
514
     * @param mixed           $route 分组路由
515
     * @return RuleGroup
516
     */
517 3
    public function group(string | Closure $name, $route = null): RuleGroup
518
    {
519 3
        if ($name instanceof Closure) {
520 3
            $route = $name;
521 3
            $name  = '';
522
        }
523
524 3
        return (new RuleGroup($this, $this->group, $name, $route, $this->lazy))
525 3
            ->removeSlash($this->removeSlash)
526 3
            ->mergeRuleRegex($this->mergeRuleRegex);
527
    }
528
529
    /**
530
     * 注册路由
531
     * @access public
532
     * @param string $rule  路由规则
533
     * @param mixed  $route 路由地址
534
     * @return RuleItem
535
     */
536
    public function any(string $rule, $route): RuleItem
537
    {
538
        return $this->rule($rule, $route, '*');
539
    }
540
541
    /**
542
     * 注册GET路由
543
     * @access public
544
     * @param string $rule  路由规则
545
     * @param mixed  $route 路由地址
546
     * @return RuleItem
547
     */
548 18
    public function get(string $rule, $route): RuleItem
549
    {
550 18
        return $this->rule($rule, $route, 'GET');
551
    }
552
553
    /**
554
     * 注册POST路由
555
     * @access public
556
     * @param string $rule  路由规则
557
     * @param mixed  $route 路由地址
558
     * @return RuleItem
559
     */
560 3
    public function post(string $rule, $route): RuleItem
561
    {
562 3
        return $this->rule($rule, $route, 'POST');
563
    }
564
565
    /**
566
     * 注册PUT路由
567
     * @access public
568
     * @param string $rule  路由规则
569
     * @param mixed  $route 路由地址
570
     * @return RuleItem
571
     */
572 3
    public function put(string $rule, $route): RuleItem
573
    {
574 3
        return $this->rule($rule, $route, 'PUT');
575
    }
576
577
    /**
578
     * 注册DELETE路由
579
     * @access public
580
     * @param string $rule  路由规则
581
     * @param mixed  $route 路由地址
582
     * @return RuleItem
583
     */
584
    public function delete(string $rule, $route): RuleItem
585
    {
586
        return $this->rule($rule, $route, 'DELETE');
587
    }
588
589
    /**
590
     * 注册PATCH路由
591
     * @access public
592
     * @param string $rule  路由规则
593
     * @param mixed  $route 路由地址
594
     * @return RuleItem
595
     */
596
    public function patch(string $rule, $route): RuleItem
597
    {
598
        return $this->rule($rule, $route, 'PATCH');
599
    }
600
601
    /**
602
     * 注册HEAD路由
603
     * @access public
604
     * @param string $rule  路由规则
605
     * @param mixed  $route 路由地址
606
     * @return RuleItem
607
     */
608
    public function head(string $rule, $route): RuleItem
609
    {
610
        return $this->rule($rule, $route, 'HEAD');
611
    }
612
613
    /**
614
     * 注册OPTIONS路由
615
     * @access public
616
     * @param string $rule  路由规则
617
     * @param mixed  $route 路由地址
618
     * @return RuleItem
619
     */
620
    public function options(string $rule, $route): RuleItem
621
    {
622
        return $this->rule($rule, $route, 'OPTIONS');
623
    }
624
625
    /**
626
     * 注册资源路由
627
     * @access public
628
     * @param string $rule  路由规则
629
     * @param string $route 路由地址
630
     * @return Resource|ResourceRegister
631
     */
632
    public function resource(string $rule, string $route)
633
    {
634
        $resource = new Resource($this, $this->group, $rule, $route, $this->rest);
635
636
        if (!$this->lazy) {
637
            return new ResourceRegister($resource);
638
        }
639
640
        return $resource;
641
    }
642
643
    /**
644
     * 注册视图路由
645
     * @access public
646
     * @param string $rule     路由规则
647
     * @param string $template 路由模板地址
648
     * @param array  $vars     模板变量
649
     * @return RuleItem
650
     */
651 3
    public function view(string $rule, string $template = '', array $vars = []): RuleItem
652
    {
653 3
        return $this->rule($rule, function () use ($vars, $template) {
654 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

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