chengkun
2025-06-05 4080b5997b38ca84b3b203c7101dcadb97b76925
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2025 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);
 
namespace think\route;
 
use Closure;
use think\Container;
use think\Route;
 
/**
 * 资源路由类
 */
class Resource extends RuleGroup
{
    /**
     * REST方法定义
     * @var array
     */
    protected $rest = [];
 
    /**
     * 模型绑定
     * @var array
     */
    protected $model = [];
 
    /**
     * 数据验证
     * @var array
     */
    protected $validate = [];
 
    /**
     * 中间件
     * @var array
     */
    protected $middleware = [];
 
    /**
     * 扩展规则
     * @var Closure
     */
    protected $extend;
 
    /**
     * 架构函数
     * @access public
     * @param  Route         $router     路由对象
     * @param  RuleGroup     $parent     上级对象
     * @param  string        $name       资源名称
     * @param  string        $route      路由地址
     * @param  array         $rest       资源定义
     */
    public function __construct(Route $router, ?RuleGroup $parent = null, string $name = '', string $route = '', array $rest = [])
    {
        $name         = ltrim($name, '/');
        $this->router = $router;
        $this->parent = $parent;
        $this->rule   = $name;
        $this->route  = $route;
        $this->name   = str_contains($name, '.') ? strstr($name, '.', true) : $name;
 
        $this->setFullName();
 
        // 资源路由默认为完整匹配
        $this->option['complete_match'] = true;
 
        $this->rest = $rest;
 
        if ($this->parent) {
            $this->domain = $this->parent->getDomain();
            $this->parent->addRuleItem($this);
        }
    }
 
    /**
     * 扩展额外路由规则
     * @access public
     * @param  Closure $extend 路由规则闭包定义
     * @return $this
     */
    public function extend(?Closure $extend)
    {
        $this->extend = $extend;
        return $this;
    }
 
    /**
     * 生成资源路由规则
     * @access public
     * @param  mixed $rule 路由规则
     * @return void
     */
    public function parseGroupRule($rule): void
    {
        $option = $this->option;
        $origin = $this->router->getGroup();
        $this->router->setGroup($this);
 
        if (str_contains($rule, '.')) {
            // 注册嵌套资源路由
            $array = explode('.', $rule);
            $last  = array_pop($array);
            $item  = [];
 
            foreach ($array as $val) {
                $item[] = $val . '/<' . ($option['var'][$val] ?? $val . '_id') . '>';
            }
 
            $rule = implode('/', $item) . '/' . $last;
            $id   = $option['var'][$last] ?? 'id';
        } else {
            $id = $option['var'][$rule] ?? 'id';
        }
 
        $prefix = substr($rule, strlen($this->name) + 1);
 
        // 注册资源路由
        foreach ($this->rest as $key => $val) {
            if ((isset($option['only']) && !in_array($key, $option['only']))
                || (isset($option['except']) && in_array($key, $option['except']))
            ) {
                continue;
            }
 
            if (str_contains($val[1], '<id>') && 'id' != $id) {
                $val[1] = str_replace('<id>', '<' . $id . '>', $val[1]);
            }
 
            $ruleItem = $this->addRule(trim($prefix . $val[1], '/'), $this->route . '/' . $val[2], $val[0]);
 
            foreach (['model', 'validate', 'middleware', 'pattern'] as $name) {
                if (isset($this->$name[$key])) {
                    call_user_func_array([$ruleItem, $name], (array) $this->$name[$key]);
                }
            }
        }
 
        if ($this->extend) {
            // 扩展路由规则
            $group = new RuleGroup($this->router, $this, $prefix . '/<' . $id . '>');
            $this->router->setGroup($group);
            Container::getInstance()->invokeFunction($this->extend);
        }
 
        $this->router->setGroup($origin);
        $this->hasParsed = true;
    }
 
    /**
     * 设置资源允许
     * @access public
     * @param  array $only 资源允许
     * @return $this
     */
    public function only(array $only)
    {
        return $this->setOption('only', $only);
    }
 
    /**
     * 设置资源排除
     * @access public
     * @param  array $except 排除资源
     * @return $this
     */
    public function except(array $except)
    {
        return $this->setOption('except', $except);
    }
 
    /**
     * 设置资源路由的变量
     * @access public
     * @param  array $vars 资源变量
     * @return $this
     */
    public function vars(array $vars)
    {
        return $this->setOption('var', $vars);
    }
 
    /**
     * 绑定资源验证
     * @access public
     * @param  array|string $name 资源类型或者验证信息
     * @param  array|string $validate 验证信息
     * @return $this
     */
    public function withValidate(array | string $name, array | string $validate = [])
    {
        if (is_array($name)) {
            $this->validate = array_merge($this->validate, $name);
        } else {
            $this->validate[$name] = $validate;
        }
 
        return $this;
    }
 
    /**
     * 绑定资源模型
     * @access public
     * @param  array|string $name 资源类型或者模型绑定
     * @param  array|string $model 模型绑定
     * @return $this
     */
    public function withModel(array | string $name, array | string $model = [])
    {
        if (is_array($name)) {
            $this->model = array_merge($this->model, $name);
        } else {
            $this->model[$name] = $model;
        }
 
        return $this;
    }
 
    /**
     * 绑定资源中间件
     * @access public
     * @param  array|string $name 资源类型或者中间件定义
     * @param  array|string $middleware 中间件定义
     * @return $this
     */
    public function withMiddleware(array | string $name, array | string $middleware = [])
    {
        if (is_array($name)) {
            $this->middleware = array_merge($this->middleware, $name);
        } else {
            $this->middleware[$name] = $middleware;
        }
 
        return $this;
    }
 
    /**
     * rest方法定义和修改
     * @access public
     * @param  array|string  $name 方法名称
     * @param  array|bool    $resource 资源
     * @return $this
     */
    public function rest(array | string $name, array | bool $resource = [])
    {
        if (is_array($name)) {
            $this->rest = $resource ? $name : array_merge($this->rest, $name);
        } else {
            $this->rest[$name] = $resource;
        }
 
        return $this;
    }
}