Passed
Push — 8.0 ( 495b3f...e5cbfb )
by liu
02:07
created

RuleItem::checkMatch()   D

Complexity

Conditions 27
Paths 56

Size

Total Lines 63
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 154.2028

Importance

Changes 0
Metric Value
cc 27
eloc 35
c 0
b 0
f 0
nc 56
nop 4
dl 0
loc 63
ccs 15
cts 34
cp 0.4412
crap 154.2028
rs 4.1666

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~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\route;
14
15
use think\Exception;
16
use think\Request;
17
use think\Route;
18
19
/**
20
 * 路由规则类
21
 */
22
class RuleItem extends Rule
23
{
24
    /**
25
     * 是否为MISS规则
26
     * @var bool
27
     */
28
    protected $miss = false;
29
30
    /**
31
     * 是否为额外自动注册的OPTIONS规则
32
     * @var bool
33
     */
34
    protected $autoOption = false;
35
36
    /**
37
     * 架构函数
38
     * @access public
39
     * @param  Route             $router 路由实例
40
     * @param  RuleGroup         $parent 上级对象
41
     * @param  string            $name 路由标识
42
     * @param  string            $rule 路由规则
43
     * @param  string|\Closure   $route 路由地址
44
     * @param  string            $method 请求类型
45
     */
46 27
    public function __construct(Route $router, RuleGroup $parent, string $name = null, string $rule = '', $route = null, string $method = '*')
47
    {
48 27
        $this->router = $router;
49 27
        $this->parent = $parent;
50 27
        $this->name   = $name;
51 27
        $this->route  = $route;
52 27
        $this->method = $method;
53
54 27
        $this->setRule($rule);
55
56 27
        $this->router->setRule($this->rule, $this);
57
    }
58
59
    /**
60
     * 设置当前路由规则为MISS路由
61
     * @access public
62
     * @return $this
63
     */
64 27
    public function setMiss()
65
    {
66 27
        $this->miss = true;
67 27
        return $this;
68
    }
69
70
    /**
71
     * 判断当前路由规则是否为MISS路由
72
     * @access public
73
     * @return bool
74
     */
75
    public function isMiss(): bool
76
    {
77
        return $this->miss;
78
    }
79
80
    /**
81
     * 获取当前路由的URL后缀
82
     * @access public
83
     * @return string|null
84
     */
85 9
    public function getSuffix(): ?string
86
    {
87 9
        if (isset($this->option['ext'])) {
88
            $suffix = $this->option['ext'];
89 9
        } elseif ($this->parent->getOption('ext')) {
90
            $suffix = $this->parent->getOption('ext');
91
        } else {
92 9
            $suffix = null;
93
        }
94
95 9
        return $suffix;
96
    }
97
98
    /**
99
     * 路由规则预处理
100
     * @access public
101
     * @param  string      $rule     路由规则
102
     * @return void
103
     */
104 27
    public function setRule(string $rule): void
105
    {
106 27
        if (str_ends_with($rule, '$')) {
107
            // 是否完整匹配
108 3
            $rule = substr($rule, 0, -1);
109
110 3
            $this->option['complete_match'] = true;
111
        }
112
113 27
        $rule = '/' != $rule ? ltrim($rule, '/') : '';
114
115 27
        if ($this->parent && $prefix = $this->parent->getFullName()) {
116
            $rule = $prefix . ($rule ? '/' . ltrim($rule, '/') : '');
117
        }
118
119 27
        if (str_contains($rule, ':')) {
120
            $this->rule = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $rule);
121
        } else {
122 27
            $this->rule = $rule;
123
        }
124
125
        // 生成路由标识的快捷访问
126 27
        $this->setRuleName();
127
    }
128
129
    /**
130
     * 设置别名
131
     * @access public
132
     * @param  string     $name
133
     * @return $this
134
     */
135
    public function name(string $name)
136
    {
137
        $this->name = $name;
138
        $this->setRuleName(true);
139
140
        return $this;
141
    }
142
143
    /**
144
     * 设置路由标识 用于URL反解生成
145
     * @access protected
146
     * @param  bool $first 是否插入开头
147
     * @return void
148
     */
149 27
    protected function setRuleName(bool $first = false): void
150
    {
151 27
        if ($this->name) {
152 9
            $this->router->setName($this->name, $this, $first);
153
        }
154
    }
155
156
    /**
157
     * 检测路由
158
     * @access public
159
     * @param  Request      $request  请求对象
160
     * @param  string       $url      访问地址
161
     * @param  array        $match    匹配路由变量
162
     * @param  bool         $completeMatch   路由是否完全匹配
163
     * @return Dispatch|false
164
     */
165 24
    public function checkRule(Request $request, string $url, array $match = null, bool $completeMatch = false)
166
    {
167
        // 检查参数有效性
168 24
        if (!$this->checkOption($this->option, $request)) {
169
            return false;
170
        }
171
172
        // 合并分组参数
173 24
        $option  = $this->getOption();
174 24
        $pattern = $this->getPattern();
175 24
        $url     = $this->urlSuffixCheck($request, $url, $option);
176
177 24
        if (is_null($match)) {
178 24
            $match = $this->checkMatch($url, $option, $pattern, $completeMatch);
179
        }
180
181 24
        if (false !== $match) {
182 24
            return $this->parseRule($request, $this->rule, $this->route, $url, $option, $match);
183
        }
184
185
        return false;
186
    }
187
188
    /**
189
     * 检测路由(含路由匹配)
190
     * @access public
191
     * @param  Request      $request  请求对象
192
     * @param  string       $url      访问地址
193
     * @param  bool         $completeMatch   路由是否完全匹配
194
     * @return Dispatch|false
195
     */
196 24
    public function check(Request $request, string $url, bool $completeMatch = false)
197
    {
198 24
        return $this->checkRule($request, $url, null, $completeMatch);
199
    }
200
201
    /**
202
     * URL后缀及Slash检查
203
     * @access protected
204
     * @param  Request      $request  请求对象
205
     * @param  string       $url      访问地址
206
     * @param  array        $option   路由参数
207
     * @return string
208
     */
209 24
    protected function urlSuffixCheck(Request $request, string $url, array $option = []): string
210
    {
211
        // 是否区分 / 地址访问
212 24
        if (!empty($option['remove_slash']) && '/' != $this->rule) {
213
            $this->rule = rtrim($this->rule, '/');
214
            $url        = rtrim($url, '|');
215
        }
216
217 24
        if (isset($option['ext'])) {
218
            // 路由ext参数 优先于系统配置的URL伪静态后缀参数
219
            $url = preg_replace('/\.(' . $request->ext() . ')$/i', '', $url);
220
        }
221
222 24
        return $url;
223
    }
224
225
    /**
226
     * 检测URL和规则路由是否匹配
227
     * @access private
228
     * @param  string    $url URL地址
229
     * @param  array     $option    路由参数
230
     * @param  array     $pattern   变量规则
231
     * @param  bool      $completeMatch   是否完全匹配
232
     * @return array|false
233
     */
234 24
    private function checkMatch(string $url, array $option, array $pattern, bool $completeMatch)
235
    {
236 24
        if (isset($option['complete_match'])) {
237 3
            $completeMatch = $option['complete_match'];
238
        }
239
240 24
        $depr = $this->config('pathinfo_depr');
241 24
        if (isset($option['case_sensitive'])) {
242
            $case = $option['case_sensitive'];
243
        } else {
244 24
            $case = $this->config('url_case_sensitive');
245
        }
246
247
        // 检查完整规则定义
248 24
        if (isset($pattern['__url__']) && !preg_match(str_starts_with($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . ($completeMatch ? '$' : '') . '/', str_replace('|', $depr, $url))) {
249
            return false;
250
        }
251
252 24
        $var  = [];
253 24
        $url  = $depr . str_replace('|', $depr, $url);
254 24
        $rule = $depr . str_replace('/', $depr, $this->rule);
255
256 24
        if ($depr == $rule && $depr != $url) {
257
            return false;
258
        }
259
260 24
        if (!str_contains($rule, '<')) {
261 24
            if ($case && (0 === strcmp($rule, $url) || (!$completeMatch && 0 === strncmp($rule . $depr, $url . $depr, strlen($rule . $depr))))) {
262
                return $var;
263 24
            } elseif (!$case && (0 === strcasecmp($rule, $url) || (!$completeMatch && 0 === strncasecmp($rule . $depr, $url . $depr, strlen($rule . $depr))))) {
264 24
                return $var;
265
            }
266
            return false;
267
        }
268
269
        $slash = preg_quote('/-' . $depr, '/');
270
271
        if ($matchRule = preg_split('/[' . $slash . ']?<\w+\??>/', $rule, 2)) {
272
            if ($matchRule[0] && 0 !== strncasecmp($rule, $url, strlen($matchRule[0]))) {
273
                return false;
274
            }
275
        }
276
277
        if (preg_match_all('/[' . $slash . ']?<?\w+\??>?/', $rule, $matches)) {
278
            $regex = $this->buildRuleRegex($rule, $matches[0], $pattern, $option, $completeMatch);
279
280
            try {
281
                if (!preg_match('~^' . $regex . '~u' . ($case ? '' : 'i'), $url, $match)) {
282
                    return false;
283
                }
284
            } catch (\Exception $e) {
285
                throw new Exception('route pattern error');
286
            }
287
288
            foreach ($match as $key => $val) {
289
                if (is_string($key)) {
290
                    $var[$key] = $val;
291
                }
292
            }
293
        }
294
295
        // 成功匹配后返回URL中的动态变量数组
296
        return $var;
297
    }
298
299
    /**
300
     * 设置路由所属分组(用于注解路由)
301
     * @access public
302
     * @param  string $name 分组名称或者标识
303
     * @return $this
304
     */
305
    public function group(string $name)
306
    {
307
        $group = $this->router->getRuleName()->getGroup($name);
308
309
        if ($group) {
310
            $this->parent = $group;
311
            $this->setRule($this->rule);
312
        }
313
314
        return $this;
315
    }
316
}
317