Completed
Push — 6.0 ( b31059...b166ff )
by liu
09:16 queued 06:24
created

Dispatch::autoResponse()   B

Complexity

Conditions 7
Paths 11

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 11
nc 11
nop 1
dl 0
loc 17
ccs 0
cts 11
cp 0
crap 56
rs 8.8333
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
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
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
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
    /**
63
     * 是否进行大小写转换
64
     * @var bool
65
     */
66
    protected $convert;
67
68
    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...
69
    {
70
        $this->request  = $request;
71
        $this->rule     = $rule;
72
        $this->dispatch = $dispatch;
73
        $this->param    = $param;
74
        $this->code     = $code;
75
76
        if (isset($param['convert'])) {
77
            $this->convert = $param['convert'];
78
        }
79
    }
80
81
    public function init(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function init()
Loading history...
82
    {
83
        $this->app = $app;
84
85
        // 记录当前请求的路由规则
86
        $this->request->setRule($this->rule);
87
88
        // 记录路由变量
89
        $this->request->setRoute($this->param);
90
91
        // 执行路由后置操作
92
        $this->doRouteAfter();
93
    }
94
95
    /**
96
     * 执行路由调度
97
     * @access public
98
     * @return mixed
99
     */
100
    public function run(): Response
101
    {
102
        $option = $this->rule->getOption();
103
104
        // 数据自动验证
105
        if (isset($option['validate'])) {
106
            $this->autoValidate($option['validate']);
107
        }
108
109
        $data = $this->exec();
110
111
        return $this->autoResponse($data);
112
    }
113
114
    protected function autoResponse($data): Response
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function autoResponse()
Loading history...
115
    {
116
        if ($data instanceof Response) {
117
            $response = $data;
118
        } elseif (!is_null($data)) {
119
            // 默认自动识别响应输出类型
120
            $type     = $this->request->isJson() ? 'json' : 'html';
121
            $response = Response::create($data, $type);
122
        } else {
123
            $data = ob_get_clean();
124
125
            $content  = false === $data ? '' : $data;
126
            $status   = '' === $content && $this->request->isJson() ? 204 : 200;
127
            $response = Response::create($content, '', $status);
128
        }
129
130
        return $response;
131
    }
132
133
    /**
134
     * 检查路由后置操作
135
     * @access protected
136
     * @return void
137
     */
138
    protected function doRouteAfter(): void
139
    {
140
        // 记录匹配的路由信息
141
        $option = $this->rule->getOption();
142
143
        // 添加中间件
144
        if (!empty($option['middleware'])) {
145
            $this->app->middleware->import($option['middleware']);
146
        }
147
148
        // 绑定模型数据
149
        if (!empty($option['model'])) {
150
            $this->createBindModel($option['model'], $this->request->route());
0 ignored issues
show
Bug introduced by
It seems like $this->request->route() can also be of type null and object; however, parameter $matches of think\route\Dispatch::createBindModel() 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

150
            $this->createBindModel($option['model'], /** @scrutinizer ignore-type */ $this->request->route());
Loading history...
151
        }
152
153
        if (!empty($option['append'])) {
154
            $this->request->setRoute($option['append']);
155
        }
156
    }
157
158
    /**
159
     * 路由绑定模型实例
160
     * @access protected
161
     * @param array $bindModel 绑定模型
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
162
     * @param array $matches   路由变量
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
163
     * @return void
164
     */
165
    protected function createBindModel(array $bindModel, array $matches): void
166
    {
167
        foreach ($bindModel as $key => $val) {
168
            if ($val instanceof \Closure) {
169
                $result = $this->app->invokeFunction($val, $matches);
170
            } else {
171
                $fields = explode('&', $key);
172
173
                if (is_array($val)) {
174
                    list($model, $exception) = $val;
175
                } else {
176
                    $model     = $val;
177
                    $exception = true;
178
                }
179
180
                $where = [];
181
                $match = true;
182
183
                foreach ($fields as $field) {
184
                    if (!isset($matches[$field])) {
185
                        $match = false;
186
                        break;
187
                    } else {
188
                        $where[] = [$field, '=', $matches[$field]];
189
                    }
190
                }
191
192
                if ($match) {
193
                    $result = $model::where($where)->failException($exception)->find();
194
                }
195
            }
196
197
            if (!empty($result)) {
198
                // 注入容器
199
                $this->app->instance(get_class($result), $result);
200
            }
201
        }
202
    }
203
204
    /**
205
     * 验证数据
206
     * @access protected
207
     * @param array $option
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
208
     * @return void
209
     * @throws \think\exception\ValidateException
210
     */
211
    protected function autoValidate(array $option): void
212
    {
213
        list($validate, $scene, $message, $batch) = $option;
214
215
        if (is_array($validate)) {
216
            // 指定验证规则
217
            $v = new Validate();
218
            $v->rule($validate);
219
        } else {
220
            // 调用验证器
221
            /** @var Validate $class */
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...
222
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
223
224
            $v = new $class();
225
226
            if (!empty($scene)) {
227
                $v->scene($scene);
228
            }
229
        }
230
231
        $v->message($message)->batch($batch)->failException(true)->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

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