Passed
Push — 8.0 ( 4448c2...81f206 )
by liu
02:14
created

Route::auto()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 9
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 11
ccs 0
cts 10
cp 0
crap 2
rs 9.9666
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
27
/**
28
 * 路由管理类
29
 * @package think
30
 */
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
        'url_case_sensitive'    => false,
60
        // 合并路由规则
61
        'route_rule_merge'      => false,
62
        // 路由是否完全匹配
63
        'route_complete_match'  => false,
64
        // 去除斜杠
65
        'remove_slash'          => false,
66
        // 使用注解路由
67
        'route_annotation'      => false,
68
        // 默认的路由变量规则
69
        'default_route_pattern' => '[\w\.]+',
70
        // URL伪静态后缀
71
        'url_html_suffix'       => 'html',
72
        // 访问控制器层名称
73
        'controller_layer'      => 'controller',
74
        // 空控制器名
75
        'empty_controller'      => 'Error',
76
        // 是否使用控制器后缀
77
        'controller_suffix'     => false,
78
        // 默认路由 [路由规则, 路由地址]
79
        'default_route'         => [],
80
        // 默认模块名
81
        'default_module'        => 'index',
82
        // 默认控制器名
83
        'default_controller'    => 'Index',
84
        // 默认操作名
85
        'default_action'        => 'index',
86
        // 操作方法后缀
87
        'action_suffix'         => '',
88
        // 非路由变量是否使用普通参数方式(用于URL生成)
89
        'url_common_param'      => true,
90
    ];
91
92
    /**
93
     * 请求对象
94
     * @var Request
95
     */
96
    protected $request;
97
98
    /**
99
     * @var RuleName
100
     */
101
    protected $ruleName;
102
103
    /**
104
     * 当前HOST
105
     * @var string
106
     */
107
    protected $host;
108
109
    /**
110
     * 当前分组对象
111
     * @var RuleGroup
112
     */
113
    protected $group;
114
115
    /**
116
     * 路由绑定
117
     * @var array
118
     */
119
    protected $bind = [];
120
121
    /**
122
     * 域名对象
123
     * @var Domain[]
124
     */
125
    protected $domains = [];
126
127
    /**
128
     * 跨域路由规则
129
     * @var RuleGroup
130
     */
131
    protected $cross;
132
133
    /**
134
     * 路由是否延迟解析
135
     * @var bool
136
     */
137
    protected $lazy = false;
138
139
    /**
140
     * (分组)路由规则是否合并解析
141
     * @var bool
142
     */
143
    protected $mergeRuleRegex = false;
144
145
    /**
146
     * 是否去除URL最后的斜线
147
     * @var bool
148
     */
149
    protected $removeSlash = false;
150
151 27
    public function __construct(protected App $app)
152
    {
153 27
        $this->ruleName = new RuleName();
154 27
        $this->setDefaultDomain();
155
156 27
        if (is_file($this->app->getRuntimePath() . 'route.php')) {
157
            // 读取路由映射文件
158
            $this->import(include $this->app->getRuntimePath() . 'route.php');
159
        }
160
161 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

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

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

655
            return Response::create($template, 'view')->/** @scrutinizer ignore-call */ assign($vars);
Loading history...
656 3
        }, 'GET');
657
    }
658
659
    /**
660
     * 注册重定向路由
661
     * @access public
662
     * @param string $rule   路由规则
663
     * @param string $route  路由地址
664
     * @param int    $status 状态码
665
     * @return RuleItem
666
     */
667 3
    public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
668
    {
669 3
        return $this->rule($rule, function (Request $request) use ($status, $route) {
670 3
            $search  = $replace  = [];
671 3
            $matches = $request->rule()->getVars();
672
673 3
            foreach ($matches as $key => $value) {
674
                $search[]  = '<' . $key . '>';
675
                $replace[] = $value;
676
677
                $search[]  = ':' . $key;
678
                $replace[] = $value;
679
            }
680
681 3
            $route = str_replace($search, $replace, $route);
682 3
            return Response::create($route, 'redirect')->code($status);
683 3
        }, '*');
684
    }
685
686
    /**
687
     * rest方法定义和修改
688
     * @access public
689
     * @param string|array $name     方法名称
690
     * @param array|bool   $resource 资源
691
     * @return $this
692
     */
693
    public function rest(string | array $name, array | bool $resource = [])
694
    {
695
        if (is_array($name)) {
0 ignored issues
show
introduced by
The condition is_array($name) is always true.
Loading history...
696
            $this->rest = $resource ? $name : array_merge($this->rest, $name);
697
        } else {
698
            $this->rest[$name] = $resource;
699
        }
700
701
        return $this;
702
    }
703
704
    /**
705
     * 获取rest方法定义的参数
706
     * @access public
707
     * @param string $name 方法名称
708
     * @return array|null
709
     */
710
    public function getRest(?string $name = null)
711
    {
712
        if (is_null($name)) {
713
            return $this->rest;
714
        }
715
716
        return $this->rest[$name] ?? null;
717
    }
718
719
    /**
720
     * 注册未匹配路由规则后的处理
721
     * @access public
722
     * @param string|Closure $route  路由地址
723
     * @param string         $method 请求类型
724
     * @return RuleItem
725
     */
726 27
    public function miss(string | Closure $route, string $method = '*'): RuleItem
727
    {
728 27
        return $this->group->miss($route, $method);
729
    }
730
731
    /**
732
     * 路由调度
733
     * @param Request $request
734
     * @param Closure|bool $withRoute
735
     * @return Response
736
     */
737 27
    public function dispatch(Request $request, Closure | bool $withRoute = true)
738
    {
739 27
        $this->request = $request;
740 27
        $this->host    = $this->request->host(true);
741 27
        $completeMatch = (bool) $this->config['route_complete_match'];
742
743 27
        if ($withRoute) {
744
            //加载路由
745 27
            if ($withRoute instanceof Closure) {
746
                $withRoute();
747
            }
748 27
            $dispatch = $this->check($completeMatch);
749
        } else {
750
            $dispatch = $this->autoUrl($this->config['default_route'])
751
                ->check($this->request, $this->path(), $completeMatch);
752
        }
753
754 27
        $dispatch->init($this->app);
755
756 27
        return $this->app->middleware->pipeline('route')
757 27
            ->send($request)
758 27
            ->then(function () use ($dispatch) {
759 27
                return $dispatch->run();
760 27
            });
761
    }
762
763
    /**
764
     * 检测URL路由
765
     * @access public
766
     * @param  bool $completeMatch
767
     * @return Dispatch|false
768
     * @throws RouteNotFoundException
769
     */
770 27
    public function check(bool $completeMatch = false)
771
    {
772
        // 自动检测域名路由
773 27
        $url = str_replace($this->config['pathinfo_depr'], '|', $this->path());
774
775 27
        $result = $this->checkDomain()->check($this->request, $url, $completeMatch);
776
777 27
        if (false === $result && !empty($this->cross)) {
778
            // 检测跨域路由
779
            $result = $this->cross->check($this->request, $url, $completeMatch);
780
        }
781
782 27
        if (false !== $result) {
783 24
            return $result;
784 3
        } elseif ($this->config['url_route_must']) {
785
            throw new RouteNotFoundException();
786
        }
787 3
        return $this->autoUrl($this->config['default_route'])
788 3
            ->check($this->request, $url, $completeMatch);
789
    }
790
791
    /**
792
     * 获取当前请求URL的pathinfo信息(不含URL后缀)
793
     * @access protected
794
     * @return string
795
     */
796 27
    protected function path(): string
797
    {
798 27
        $suffix   = $this->config['url_html_suffix'];
799 27
        $pathinfo = $this->request->pathinfo();
800
801 27
        if (false === $suffix) {
802
            // 禁止伪静态访问
803
            $path = $pathinfo;
804 27
        } elseif ($suffix) {
805
            // 去除正常的URL后缀
806 27
            $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
807
        } else {
808
            // 允许任何后缀访问
809
            $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
810
        }
811
812 27
        return $path;
813
    }
814
815
    /**
816
     * 自动多模块URL路由 如使用多模块在路由定义文件最后定义
817
     * @access public
818
     * @param  string $rule    路由规则
819
     * @param  mixed  $route   路由地址
820
     * @return RuleItem
821
     */
822
    public function auto(string $rule = '[:module]/[:controller]/[:action]', $route = ':module/:controller/:action'): RuleItem
823
    {
824
        return $this->rule($rule, $route)
825
            ->pattern([
826
                'module'     => '[A-Za-z0-9\.\_]+',
827
                'controller' => '[A-Za-z0-9\.\_]+',
828
                'action'     => '[A-Za-z0-9\_]+',
829
            ])->default([
830
                'module'     => $this->config['default_module'],
831
                'controller' => $this->config['default_controller'],
832
                'action'     => $this->config['default_action'],
833
            ]);
834
    }
835
836
    /**
837
     * 注册分组默认URL解析路由
838
     * @access public
839
     * @param  array     $option 解析规则
840
     * @return RuleItem
841
     */
842 3
    protected function autoUrl(array $option = []): RuleItem
843
    {
844 3
        return $this->group->autoUrl($option);
845
    }
846
847
    /**
848
     * 检测域名的路由规则
849
     * @access protected
850
     * @return Domain
851
     */
852 27
    protected function checkDomain(): Domain
853
    {
854 27
        $item = false;
855
856 27
        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 27
        if (false === $item) {
892
            // 检测全局域名规则
893 24
            $item = $this->domains['-'];
894
        }
895
896 27
        if (is_string($item)) {
897
            $item = $this->domains[$item];
898
        }
899
900 27
        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