1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* WebHemi. |
4
|
|
|
* |
5
|
|
|
* PHP version 5.6 |
6
|
|
|
* |
7
|
|
|
* @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com) |
8
|
|
|
* @license https://opensource.org/licenses/MIT The MIT License (MIT) |
9
|
|
|
* |
10
|
|
|
* @link http://www.gixx-web.com |
11
|
|
|
*/ |
12
|
|
|
namespace WebHemi\Middleware\Pipeline; |
13
|
|
|
|
14
|
|
|
use InvalidArgumentException; |
15
|
|
|
use RuntimeException; |
16
|
|
|
use WebHemi\Middleware\MiddlewareInterface; |
17
|
|
|
use WebHemi\Middleware\DispatcherMiddleware; |
18
|
|
|
use WebHemi\Middleware\FinalMiddleware; |
19
|
|
|
use WebHemi\Middleware\RoutingMiddleware; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Class Pipeline. |
23
|
|
|
*/ |
24
|
|
|
class Pipeline implements MiddlewarePipelineInterface |
25
|
|
|
{ |
26
|
|
|
/** @var array */ |
27
|
|
|
private $priorityList; |
28
|
|
|
/** @var array */ |
29
|
|
|
private $pipelineList; |
30
|
|
|
/** @var array */ |
31
|
|
|
private $keyMiddlewareList; |
32
|
|
|
/** @var int */ |
33
|
|
|
private $index; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Pipeline constructor. |
37
|
|
|
*/ |
38
|
|
|
public function __construct() |
39
|
|
|
{ |
40
|
|
|
$this->keyMiddlewareList = [ |
41
|
|
|
RoutingMiddleware::class, |
42
|
|
|
DispatcherMiddleware::class, |
43
|
|
|
FinalMiddleware::class |
44
|
|
|
]; |
45
|
|
|
|
46
|
|
|
// The FinalMiddleware should not be part of the queue. |
47
|
|
|
$this->priorityList = [ |
48
|
|
|
0 => [RoutingMiddleware::class], |
49
|
|
|
100 => [DispatcherMiddleware::class] |
50
|
|
|
]; |
51
|
|
|
|
52
|
|
|
$this->pipelineList = [ |
53
|
|
|
RoutingMiddleware::class, |
54
|
|
|
DispatcherMiddleware::class, |
55
|
|
|
]; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Adds a new middleware to the pipeline queue. |
60
|
|
|
* |
61
|
|
|
* @param string $middleWareClass |
62
|
|
|
* @param int $priority |
63
|
|
|
* |
64
|
|
|
* @throws RuntimeException |
65
|
|
|
* |
66
|
|
|
* @return $this |
67
|
|
|
*/ |
68
|
|
|
public function queueMiddleware($middleWareClass, $priority = 50) |
69
|
|
|
{ |
70
|
|
|
if (in_array($middleWareClass, $this->keyMiddlewareList)) { |
71
|
|
|
// Don't throw error if the user defines the default middleware classes. |
72
|
|
|
return $this; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
$this->checkPipelineIsStarted(); |
76
|
|
|
$this->checkDuplicates($middleWareClass); |
77
|
|
|
$this->checkClassType($middleWareClass); |
78
|
|
|
|
79
|
|
|
if ($priority === 0 || $priority == 100) { |
80
|
|
|
$priority++; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
if (!isset($this->priorityList[$priority])) { |
84
|
|
|
$this->priorityList[$priority] = []; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
if (!in_array($middleWareClass, $this->priorityList[$priority])) { |
88
|
|
|
$this->priorityList[$priority][] = $middleWareClass; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
return $this; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Checks if the pipline is already being processed. |
96
|
|
|
* |
97
|
|
|
* @throws RuntimeException |
98
|
|
|
*/ |
99
|
|
|
private function checkPipelineIsStarted() |
100
|
|
|
{ |
101
|
|
|
if (isset($this->index)) { |
102
|
|
|
throw new RuntimeException('You are forbidden to add new middleware after start.'); |
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Checks if the given middleware is already added to the list. |
108
|
|
|
* |
109
|
|
|
* @param string $middleWareClass |
110
|
|
|
* |
111
|
|
|
* @throws RuntimeException |
112
|
|
|
*/ |
113
|
|
|
private function checkDuplicates($middleWareClass) |
114
|
|
|
{ |
115
|
|
|
if (in_array($middleWareClass, $this->pipelineList)) { |
116
|
|
|
throw new InvalidArgumentException( |
117
|
|
|
sprintf('The class "%s" is already added to the pipeline.', $middleWareClass) |
118
|
|
|
); |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Checks if the given class is a middleware. |
124
|
|
|
* |
125
|
|
|
* @param string $middleWareClass |
126
|
|
|
* |
127
|
|
|
* @throws RuntimeException |
128
|
|
|
*/ |
129
|
|
|
private function checkClassType($middleWareClass) |
130
|
|
|
{ |
131
|
|
|
$interfaces = class_implements($middleWareClass); |
132
|
|
|
|
133
|
|
|
if ($interfaces && !in_array(MiddlewareInterface::class, $interfaces)) { |
|
|
|
|
134
|
|
|
throw new InvalidArgumentException( |
135
|
|
|
sprintf('The class "%s" does not implement MiddlewareInterface.', $middleWareClass) |
136
|
|
|
); |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Sorts the pipeline elements according to the priority. |
142
|
|
|
*/ |
143
|
|
|
private function sortPipeline() |
144
|
|
|
{ |
145
|
|
|
ksort($this->priorityList); |
146
|
|
|
$this->pipelineList = []; |
147
|
|
|
|
148
|
|
|
foreach ($this->priorityList as $middlewareList) { |
149
|
|
|
$this->pipelineList = array_merge($this->pipelineList, $middlewareList); |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Starts the pipeline. |
155
|
|
|
* |
156
|
|
|
* @return null|string |
157
|
|
|
*/ |
158
|
|
|
public function start() |
159
|
|
|
{ |
160
|
|
|
$this->index = 0; |
161
|
|
|
$this->sortPipeline(); |
162
|
|
|
|
163
|
|
|
return $this->next(); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Gets next element from the pipeline. |
168
|
|
|
* |
169
|
|
|
* @return null|string |
170
|
|
|
*/ |
171
|
|
|
public function next() |
172
|
|
|
{ |
173
|
|
|
if (!isset($this->index)) { |
174
|
|
|
throw new RuntimeException('Unable to get the next element until the pipeline is not started.'); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
return isset($this->pipelineList[$this->index]) ? $this->pipelineList[$this->index++] : null; |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.