Completed
Branch 6.0 (d30585)
by yun
04:17
created

Dispatch::__sleep()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
crap 2
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 18
    public function __construct(Request $request, Rule $rule, $dispatch, array $param = [], int $code = null)
63
    {
64 18
        $this->request  = $request;
65 18
        $this->rule     = $rule;
66 18
        $this->dispatch = $dispatch;
67 18
        $this->param    = $param;
68 18
        $this->code     = $code;
69 18
    }
70
71 18
    public function init(App $app)
72
    {
73 18
        $this->app = $app;
74
75
        // 执行路由后置操作
76 18
        $this->doRouteAfter();
77 18
    }
78
79
    /**
80
     * 执行路由调度
81
     * @access public
82
     * @return mixed
83
     */
84 18
    public function run(): Response
85
    {
86 18
        if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) {
87 6
            $rules = $this->rule->getRouter()->getRule($this->rule->getRule());
88 6
            $allow = [];
89 6
            foreach ($rules as $item) {
90 6
                $allow[] = strtoupper($item->getMethod());
91
            }
92
93 6
            return Response::create('', 'html', 204)->header(['Allow' => implode(', ', $allow)]);
94
        }
95
96 15
        $data = $this->exec();
97 15
        return $this->autoResponse($data);
98
    }
99
100 15
    protected function autoResponse($data): Response
101
    {
102 15
        if ($data instanceof Response) {
103 9
            $response = $data;
104 15
        } elseif (!is_null($data)) {
105
            // 默认自动识别响应输出类型
106 15
            $type     = $this->request->isJson() ? 'json' : 'html';
107 15
            $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, 'html', $status);
114
        }
115
116 15
        return $response;
117
    }
118
119
    /**
120
     * 检查路由后置操作
121
     * @access protected
122
     * @return void
123
     */
124 18
    protected function doRouteAfter(): void
125
    {
126 18
        $option = $this->rule->getOption();
127
128
        // 添加中间件
129 18
        if (!empty($option['middleware'])) {
130 3
            $this->app->middleware->import($option['middleware'], 'route');
131
        }
132
133 18
        if (!empty($option['append'])) {
134
            $this->param = array_merge($this->param, $option['append']);
135
        }
136
137
        // 绑定模型数据
138 18
        if (!empty($option['model'])) {
139
            $this->createBindModel($option['model'], $this->param);
140
        }
141
142
        // 记录当前请求的路由规则
143 18
        $this->request->setRule($this->rule);
144
145
        // 记录路由变量
146 18
        $this->request->setRoute($this->param);
147
148
        // 数据自动验证
149 18
        if (isset($option['validate'])) {
150
            $this->autoValidate($option['validate']);
151
        }
152 18
    }
153
154
    /**
155
     * 路由绑定模型实例
156
     * @access protected
157
     * @param array $bindModel 绑定模型
158
     * @param array $matches   路由变量
159
     * @return void
160
     */
161
    protected function createBindModel(array $bindModel, array $matches): void
162
    {
163
        foreach ($bindModel as $key => $val) {
164
            if ($val instanceof \Closure) {
165
                $result = $this->app->invokeFunction($val, $matches);
166
            } else {
167
                $fields = explode('&', $key);
168
169
                if (is_array($val)) {
170
                    [$model, $exception] = $val;
0 ignored issues
show
Bug introduced by
The variable $model does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $exception does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
171
                } else {
172
                    $model     = $val;
173
                    $exception = true;
174
                }
175
176
                $where = [];
177
                $match = true;
178
179
                foreach ($fields as $field) {
180
                    if (!isset($matches[$field])) {
181
                        $match = false;
182
                        break;
183
                    } else {
184
                        $where[] = [$field, '=', $matches[$field]];
185
                    }
186
                }
187
188
                if ($match) {
189
                    $result = $model::where($where)->failException($exception)->find();
190
                }
191
            }
192
193
            if (!empty($result)) {
194
                // 注入容器
195
                $this->app->instance(get_class($result), $result);
196
            }
197
        }
198
    }
199
200
    /**
201
     * 验证数据
202
     * @access protected
203
     * @param array $option
204
     * @return void
205
     * @throws \think\exception\ValidateException
206
     */
207
    protected function autoValidate(array $option): void
208
    {
209
        [$validate, $scene, $message, $batch] = $option;
0 ignored issues
show
Bug introduced by
The variable $validate does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $scene does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $message does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $batch does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
210
211
        if (is_array($validate)) {
212
            // 指定验证规则
213
            $v = new Validate();
214
            $v->rule($validate);
215
        } else {
216
            // 调用验证器
217
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
218
219
            $v = new $class();
220
221
            if (!empty($scene)) {
222
                $v->scene($scene);
223
            }
224
        }
225
226
        /** @var Validate $v */
227
        $v->message($message)
228
            ->batch($batch)
229
            ->failException(true)
230
            ->check($this->request->param());
231
    }
232
233
    public function getDispatch()
234
    {
235
        return $this->dispatch;
236
    }
237
238
    public function getParam(): array
239
    {
240
        return $this->param;
241
    }
242
243
    abstract public function exec();
244
245
    public function __sleep()
246
    {
247
        return ['rule', 'dispatch', 'param', 'code', 'controller', 'actionName'];
248
    }
249
250
    public function __wakeup()
251
    {
252
        $this->app     = Container::pull('app');
253
        $this->request = $this->app->request;
254
    }
255
256
    public function __debugInfo()
257
    {
258
        return [
259
            'dispatch' => $this->dispatch,
260
            'param'    => $this->param,
261
            'code'     => $this->code,
262
            'rule'     => $this->rule,
263
        ];
264
    }
265
}
266