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

Middleware::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
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: Slince <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use Closure;
16
use InvalidArgumentException;
17
use LogicException;
18
use think\exception\Handle;
19
use Throwable;
20
21
/**
22
 * 中间件管理类
23
 * @package think
24
 */
25
class Middleware
26
{
27
    /**
28
     * 中间件执行队列
29
     * @var array
30
     */
31
    protected $queue = [];
32
33
    /**
34
     * 应用对象
35
     * @var App
36
     */
37
    protected $app;
38
39 30
    public function __construct(App $app)
40
    {
41 30
        $this->app = $app;
42 30
    }
43
44
    /**
45
     * 导入中间件
46
     * @access public
47
     * @param array  $middlewares
48
     * @param string $type 中间件类型
49
     * @return void
50
     */
51 12
    public function import(array $middlewares = [], string $type = 'global'): void
52
    {
53 12
        foreach ($middlewares as $middleware) {
54 9
            $this->add($middleware, $type);
55
        }
56 12
    }
57
58
    /**
59
     * 注册中间件
60
     * @access public
61
     * @param mixed  $middleware
62
     * @param string $type 中间件类型
63
     * @return void
64
     */
65 12
    public function add($middleware, string $type = 'global'): void
66
    {
67 12
        $middleware = $this->buildMiddleware($middleware, $type);
68
69 12
        if (!empty($middleware)) {
70 12
            $this->queue[$type][] = $middleware;
71 12
            $this->queue[$type]   = array_unique($this->queue[$type], SORT_REGULAR);
72
        }
73 12
    }
74
75
    /**
76
     * 注册路由中间件
77
     * @access public
78
     * @param mixed $middleware
79
     * @return void
80
     */
81
    public function route($middleware): void
82
    {
83
        $this->add($middleware, 'route');
84
    }
85
86
    /**
87
     * 注册控制器中间件
88
     * @access public
89
     * @param mixed $middleware
90
     * @return void
91
     */
92 6
    public function controller($middleware): void
93
    {
94 6
        $this->add($middleware, 'controller');
95 6
    }
96
97
    /**
98
     * 注册中间件到开始位置
99
     * @access public
100
     * @param mixed  $middleware
101
     * @param string $type 中间件类型
102
     */
103 3
    public function unshift($middleware, string $type = 'global')
104
    {
105 3
        $middleware = $this->buildMiddleware($middleware, $type);
106
107 3
        if (!empty($middleware)) {
108 3
            if (!isset($this->queue[$type])) {
109
                $this->queue[$type] = [];
110
            }
111
112 3
            array_unshift($this->queue[$type], $middleware);
113
        }
114 3
    }
115
116
    /**
117
     * 获取注册的中间件
118
     * @access public
119
     * @param string $type 中间件类型
120
     * @return array
121
     */
122 3
    public function all(string $type = 'global'): array
123
    {
124 3
        return $this->queue[$type] ?? [];
125
    }
126
127
    /**
128
     * 调度管道
129
     * @access public
130
     * @param string $type 中间件类型
131
     * @return Pipeline
132
     */
133 24
    public function pipeline(string $type = 'global')
134
    {
135 24
        return (new Pipeline())
136
            ->through(array_map(function ($middleware) {
137
                return function ($request, $next) use ($middleware) {
138 9
                    [$call, $params] = $middleware;
0 ignored issues
show
Bug introduced by
The variable $call seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $params 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...
139 9
                    if (is_array($call) && is_string($call[0])) {
0 ignored issues
show
Bug introduced by
The variable $call seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
140 9
                        $call = [$this->app->make($call[0]), $call[1]];
0 ignored issues
show
Bug introduced by
The variable $call seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
141
                    }
142 9
                    $response = call_user_func($call, $request, $next, ...$params);
0 ignored issues
show
Bug introduced by
The variable $call 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...
143
144 9
                    if (!$response instanceof Response) {
145
                        throw new LogicException('The middleware must return Response instance');
146
                    }
147 9
                    return $response;
148 9
                };
149 24
            }, $this->sortMiddleware($this->queue[$type] ?? [])))
150 24
            ->whenException([$this, 'handleException']);
151
    }
152
153
    /**
154
     * 结束调度
155
     * @param Response $response
156
     */
157 6
    public function end(Response $response)
158
    {
159 6
        foreach ($this->queue as $queue) {
160 3
            foreach ($queue as $middleware) {
161 3
                [$call] = $middleware;
0 ignored issues
show
Bug introduced by
The variable $call 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...
162 3
                if (is_array($call) && is_string($call[0])) {
163 3
                    $instance = $this->app->make($call[0]);
164 3
                    if (method_exists($instance, 'end')) {
165 3
                        $instance->end($response);
166
                    }
167
                }
168
            }
169
        }
170 6
    }
171
172
    /**
173
     * 异常处理
174
     * @param Request   $passable
175
     * @param Throwable $e
176
     * @return Response
177
     */
178 3
    public function handleException($passable, Throwable $e)
179
    {
180
        /** @var Handle $handler */
181 3
        $handler = $this->app->make(Handle::class);
182
183 3
        $handler->report($e);
184
185 3
        return $handler->render($passable, $e);
186
    }
187
188
    /**
189
     * 解析中间件
190
     * @access protected
191
     * @param mixed  $middleware
192
     * @param string $type 中间件类型
193
     * @return array
194
     */
195 12
    protected function buildMiddleware($middleware, string $type): array
196
    {
197 12
        if (is_array($middleware)) {
198 9
            [$middleware, $params] = $middleware;
0 ignored issues
show
Bug introduced by
The variable $params 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...
199
        }
200
201 12
        if ($middleware instanceof Closure) {
202 6
            return [$middleware, $params ?? []];
203
        }
204
205 12
        if (!is_string($middleware)) {
206
            throw new InvalidArgumentException('The middleware is invalid');
207
        }
208
209
        //中间件别名检查
210 12
        $alias = $this->app->config->get('middleware.alias', []);
211
212 12
        if (isset($alias[$middleware])) {
213 3
            $middleware = $alias[$middleware];
214
        }
215
216 12
        if (is_array($middleware)) {
217 3
            $this->import($middleware, $type);
218 3
            return [];
219
        }
220
221 12
        return [[$middleware, 'handle'], $params ?? []];
222
    }
223
224
    /**
225
     * 中间件排序
226
     * @param array $middlewares
227
     * @return array
228
     */
229 24
    protected function sortMiddleware(array $middlewares)
230
    {
231 24
        $priority = $this->app->config->get('middleware.priority', []);
232
        uasort($middlewares, function ($a, $b) use ($priority) {
233 6
            $aPriority = $this->getMiddlewarePriority($priority, $a);
234 6
            $bPriority = $this->getMiddlewarePriority($priority, $b);
235 6
            return $bPriority - $aPriority;
236 24
        });
237
238 24
        return $middlewares;
239
    }
240
241
    /**
242
     * 获取中间件优先级
243
     * @param $priority
244
     * @param $middleware
245
     * @return int
246
     */
247 6
    protected function getMiddlewarePriority($priority, $middleware)
248
    {
249 6
        [$call] = $middleware;
0 ignored issues
show
Bug introduced by
The variable $call 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...
250 6
        if (is_array($call) && is_string($call[0])) {
251 6
            $index = array_search($call[0], array_reverse($priority));
252 6
            return false === $index ? -1 : $index;
253
        }
254 3
        return -1;
255
    }
256
257
}
258