Completed
Push — 6.0 ( 677f21...00c571 )
by liu
05:27
created

Middleware::add()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 2
rs 10
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
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
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 4
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
40
    {
41 4
        $this->app = $app;
42 4
    }
43
44
    /**
45
     * 导入中间件
46
     * @access public
47
     * @param array  $middlewares
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
48
     * @param string $type 中间件类型
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter name; 1 found
Loading history...
49
     * @return void
50
     */
51 3
    public function import(array $middlewares = [], string $type = 'global'): void
52
    {
53 3
        foreach ($middlewares as $middleware) {
54 2
            $this->add($middleware, $type);
55
        }
56 3
    }
57
58
    /**
59
     * 注册中间件
60
     * @access public
61
     * @param mixed  $middleware
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
62
     * @param string $type 中间件类型
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter name; 1 found
Loading history...
63
     * @return void
64
     */
65 2
    public function add($middleware, string $type = 'global'): void
66
    {
67 2
        $middleware = $this->buildMiddleware($middleware, $type);
68
69 2
        if ($middleware) {
70 2
            $this->queue[$type][] = $middleware;
71
        }
72 2
    }
73
74
    /**
75
     * 注册路由中间件
76
     * @access public
77
     * @param mixed $middleware
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
78
     * @return void
79
     */
80
    public function route($middleware): void
81
    {
82
        $this->add($middleware, 'route');
83
    }
84
85
    /**
86
     * 注册控制器中间件
87
     * @access public
88
     * @param mixed $middleware
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
89
     * @return void
90
     */
91 1
    public function controller($middleware): void
92
    {
93 1
        $this->add($middleware, 'controller');
94 1
    }
95
96
    /**
97
     * 注册中间件到开始位置
98
     * @access public
99
     * @param mixed  $middleware
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
100
     * @param string $type 中间件类型
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter name; 1 found
Loading history...
101
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
102 1
    public function unshift($middleware, string $type = 'global')
103
    {
104 1
        $middleware = $this->buildMiddleware($middleware, $type);
105
106 1
        if (!empty($middleware)) {
107 1
            if (!isset($this->queue[$type])) {
108
                $this->queue[$type] = [];
109
            }
110
111 1
            array_unshift($this->queue[$type], $middleware);
112
        }
113 1
    }
114
115
    /**
116
     * 获取注册的中间件
117
     * @access public
118
     * @param string $type 中间件类型
119
     * @return array
120
     */
121 1
    public function all(string $type = 'global'): array
122
    {
123 1
        return $this->queue[$type] ?? [];
124
    }
125
126
    /**
127
     * 调度管道
128
     * @access public
129
     * @param string $type 中间件类型
130
     * @return Pipeline
131
     */
132 2
    public function pipeline(string $type = 'global')
133
    {
134 2
        return (new Pipeline())
135
            ->through(array_map(function ($middleware) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
136
                return function ($request, $next) use ($middleware) {
137 1
                    list($call, $param) = $middleware;
138 1
                    if (is_array($call) && is_string($call[0])) {
139 1
                        $call = [$this->app->make($call[0]), $call[1]];
140
                    }
141 1
                    $response = call_user_func($call, $request, $next, $param);
142
143 1
                    if (!$response instanceof Response) {
144
                        throw new LogicException('The middleware must return Response instance');
145
                    }
146 1
                    return $response;
147 1
                };
148 2
            }, $this->sortMiddleware($this->queue[$type] ?? [])))
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
149 2
            ->whenException([$this, 'handleException']);
150
    }
151
152
    /**
153
     * 结束调度
154
     * @param Response $response
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
155
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
156 2
    public function end(Response $response)
157
    {
158 2
        foreach ($this->queue as $queue) {
159 1
            foreach ($queue as $middleware) {
160 1
                list($call) = $middleware;
161 1
                if (is_array($call) && is_string($call[0])) {
162 1
                    $instance = $this->app->make($call[0]);
163 1
                    if (method_exists($instance, 'end')) {
164 1
                        $instance->end($response);
165
                    }
166
                }
167
            }
168
        }
169 2
    }
170
171
    /**
172
     * 异常处理
173
     * @param Request   $passable
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
174
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
175
     * @return Response
176
     */
177 1
    public function handleException($passable, Throwable $e)
178
    {
179
        /** @var Handle $handler */
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...
180 1
        $handler = $this->app->make(Handle::class);
181
182 1
        $handler->report($e);
183
184 1
        $response = $handler->render($passable, $e);
185
186 1
        return $response;
187
    }
188
189
    /**
190
     * 解析中间件
191
     * @access protected
192
     * @param mixed  $middleware
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
193
     * @param string $type 中间件类型
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter name; 1 found
Loading history...
194
     * @return array
195
     */
196 2
    protected function buildMiddleware($middleware, string $type): array
197
    {
198 2
        if (is_array($middleware)) {
199 1
            list($middleware, $param) = $middleware;
200
        }
201
202 2
        if ($middleware instanceof Closure) {
203 2
            return [$middleware, $param ?? null];
204
        }
205
206 2
        if (!is_string($middleware)) {
207
            throw new InvalidArgumentException('The middleware is invalid');
208
        }
209
210
        //中间件别名检查
211 2
        $alias = $this->app->config->get('middleware.alias', []);
212
213 2
        if (isset($alias[$middleware])) {
214 1
            $middleware = $alias[$middleware];
215
        }
216
217 2
        if (is_array($middleware)) {
218 1
            $this->import($middleware, $type);
219 1
            return [];
220
        }
221
222 2
        return [[$middleware, 'handle'], $param ?? null];
223
    }
224
225
    /**
226
     * 中间件排序
227
     * @param array $middlewares
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
228
     * @return array
229
     */
230 2
    protected function sortMiddleware(array $middlewares)
231
    {
232 2
        $priority = $this->app->config->get('middleware.priority', []);
233
        uasort($middlewares, function ($a, $b) use ($priority) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
234 1
            $aPriority = $this->getMiddlewarePriority($priority, $a);
235 1
            $bPriority = $this->getMiddlewarePriority($priority, $b);
236 1
            return $bPriority - $aPriority;
237 2
        });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
238
239 2
        return $middlewares;
240
    }
241
242
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $priority should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $middleware should have a doc-comment as per coding-style.
Loading history...
243
     * 获取中间件优先级
244
     * @param $priority
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
245
     * @param $middleware
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
246
     * @return int
247
     */
248 1
    protected function getMiddlewarePriority($priority, $middleware)
249
    {
250 1
        list($call) = $middleware;
251 1
        if (is_array($call) && is_string($call[0])) {
252 1
            $index = array_search($call[0], array_reverse($priority));
253 1
            return false === $index ? -1 : $index;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false === $index ? -1 : $index also could return the type string which is incompatible with the documented return type integer.
Loading history...
254
        }
255 1
        return -1;
256
    }
257
258
}
259