Completed
Push — 6.0 ( fe454f...4b767c )
by liu
05:27
created

Dispatch::run()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 8
c 2
b 0
f 0
nc 3
nop 0
dl 0
loc 14
ccs 0
cts 8
cp 0
crap 30
rs 9.6111
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\route;
14
15
use think\App;
16
use think\Container;
17
use think\Request;
18
use think\Response;
19
use think\Validate;
20
21
/**
22
 * 路由调度基础类
23
 */
24
abstract class Dispatch
25
{
26
    /**
27
     * 应用对象
28
     * @var \think\App
29
     */
30
    protected $app;
31
32
    /**
33
     * 请求对象
34
     * @var Request
35
     */
36
    protected $request;
37
38
    /**
39
     * 路由规则
40
     * @var Rule
41
     */
42
    protected $rule;
43
44
    /**
45
     * 调度信息
46
     * @var mixed
47
     */
48
    protected $dispatch;
49
50
    /**
51
     * 路由变量
52
     * @var array
53
     */
54
    protected $param;
55
56
    /**
57
     * 状态码
58
     * @var int
59
     */
60
    protected $code;
61
62
    public function __construct(Request $request, Rule $rule, $dispatch, array $param = [], int $code = null)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
63
    {
64
        $this->request  = $request;
65
        $this->rule     = $rule;
66
        $this->dispatch = $dispatch;
67
        $this->param    = $param;
68
        $this->code     = $code;
69
    }
70
71
    public function init(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function init()
Loading history...
72
    {
73
        $this->app = $app;
74
75
        // 执行路由后置操作
76
        $this->doRouteAfter();
77
    }
78
79
    /**
80
     * 执行路由调度
81
     * @access public
82
     * @return mixed
83
     */
84
    public function run(): Response
85
    {
86
        if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) {
87
            $rules = $this->rule->getRouter()->getRule($this->rule->getRule());
88
            $allow = [];
89
            foreach ($rules as $item) {
90
                $allow[] = strtoupper($item->getMethod());
91
            }
92
93
            return Response::create('', '', 204)->header(['Allow' => implode(', ', $allow)]);
94
        }
95
96
        $data = $this->exec();
97
        return $this->autoResponse($data);
98
    }
99
100
    protected function autoResponse($data): Response
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function autoResponse()
Loading history...
101
    {
102
        if ($data instanceof Response) {
103
            $response = $data;
104
        } elseif (!is_null($data)) {
105
            // 默认自动识别响应输出类型
106
            $type     = $this->request->isJson() ? 'json' : 'html';
107
            $response = Response::create($data, $type);
108
        } else {
109
            $data = ob_get_clean();
110
111
            $content  = false === $data ? '' : $data;
112
            $status   = '' === $content && $this->request->isJson() ? 204 : 200;
113
            $response = Response::create($content, '', $status);
114
        }
115
116
        return $response;
117
    }
118
119
    /**
120
     * 检查路由后置操作
121
     * @access protected
122
     * @return void
123
     */
124
    protected function doRouteAfter(): void
125
    {
126
        $option = $this->rule->getOption();
127
128
        if (!empty($option['app'])) {
129
            $this->app->http->setApp($option['app']);
130
        } elseif ($this->app->http->isMulti() && !$this->app->http->getName()) {
131
            $this->app->http->setApp($this->app->config->get('app.default_app', 'index'));
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get(....default_app', 'index') can also be of type array; however, parameter $appName of think\Http::setApp() does only seem to accept string, 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

131
            $this->app->http->setApp(/** @scrutinizer ignore-type */ $this->app->config->get('app.default_app', 'index'));
Loading history...
132
        }
133
134
        // 添加中间件
135
        if (!empty($option['middleware'])) {
136
            $this->app->middleware->import($option['middleware'], 'route');
137
        }
138
139
        if (!empty($option['append'])) {
140
            $this->param = array_merge($this->param, $option['append']);
141
        }
142
143
        // 绑定模型数据
144
        if (!empty($option['model'])) {
145
            $this->createBindModel($option['model'], $this->param);
146
        }
147
148
        // 数据自动验证
149
        if (isset($option['validate'])) {
150
            $this->autoValidate($option['validate']);
151
        }
152
153
        // 记录当前请求的路由规则
154
        $this->request->setRule($this->rule);
155
156
        // 记录路由变量
157
        $this->request->setRoute($this->param);
158
    }
159
160
    /**
161
     * 路由绑定模型实例
162
     * @access protected
163
     * @param array $bindModel 绑定模型
164
     * @param array $matches   路由变量
165
     * @return void
166
     */
167
    protected function createBindModel(array $bindModel, array $matches): void
168
    {
169
        foreach ($bindModel as $key => $val) {
170
            if ($val instanceof \Closure) {
171
                $result = $this->app->invokeFunction($val, $matches);
172
            } else {
173
                $fields = explode('&', $key);
174
175
                if (is_array($val)) {
176
                    list($model, $exception) = $val;
177
                } else {
178
                    $model     = $val;
179
                    $exception = true;
180
                }
181
182
                $where = [];
183
                $match = true;
184
185
                foreach ($fields as $field) {
186
                    if (!isset($matches[$field])) {
187
                        $match = false;
188
                        break;
189
                    } else {
190
                        $where[] = [$field, '=', $matches[$field]];
191
                    }
192
                }
193
194
                if ($match) {
195
                    $result = $model::where($where)->failException($exception)->find();
196
                }
197
            }
198
199
            if (!empty($result)) {
200
                // 注入容器
201
                $this->app->instance(get_class($result), $result);
202
            }
203
        }
204
    }
205
206
    /**
207
     * 验证数据
208
     * @access protected
209
     * @param array $option
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
210
     * @return void
211
     * @throws \think\exception\ValidateException
212
     */
213
    protected function autoValidate(array $option): void
214
    {
215
        list($validate, $scene, $message, $batch) = $option;
216
217
        if (is_array($validate)) {
218
            // 指定验证规则
219
            $v = new Validate();
220
            $v->rule($validate);
221
        } else {
222
            // 调用验证器
223
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
224
225
            $v = new $class();
226
227
            if (!empty($scene)) {
228
                $v->scene($scene);
229
            }
230
        }
231
232
        /** @var Validate $v */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
233
        $v->message($message)
234
            ->batch($batch)
235
            ->failException(true)
236
            ->check($this->request->param());
0 ignored issues
show
Bug introduced by
It seems like $this->request->param() can also be of type null and object; however, parameter $data of think\Validate::check() 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

236
            ->check(/** @scrutinizer ignore-type */ $this->request->param());
Loading history...
237
    }
238
239
    public function getDispatch()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getDispatch()
Loading history...
240
    {
241
        return $this->dispatch;
242
    }
243
244
    public function getParam(): array
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getParam()
Loading history...
245
    {
246
        return $this->param;
247
    }
248
249
    abstract public function exec();
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function exec()
Loading history...
250
251
    public function __sleep()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __sleep()
Loading history...
252
    {
253
        return ['rule', 'dispatch', 'param', 'code', 'controller', 'actionName'];
254
    }
255
256
    public function __wakeup()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __wakeup()
Loading history...
257
    {
258
        $this->app     = Container::pull('app');
259
        $this->request = $this->app->request;
260
    }
261
262
    public function __debugInfo()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __debugInfo()
Loading history...
263
    {
264
        return [
265
            'dispatch' => $this->dispatch,
266
            'param'    => $this->param,
267
            'code'     => $this->code,
268
            'rule'     => $this->rule,
269
        ];
270
    }
271
}
272