blitz-php /
framework
| 1 | <?php |
||||
| 2 | |||||
| 3 | /** |
||||
| 4 | * This file is part of Blitz PHP framework. |
||||
| 5 | * |
||||
| 6 | * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]> |
||||
| 7 | * |
||||
| 8 | * For the full copyright and license information, please view |
||||
| 9 | * the LICENSE file that was distributed with this source code. |
||||
| 10 | */ |
||||
| 11 | |||||
| 12 | namespace BlitzPHP\Http; |
||||
| 13 | |||||
| 14 | use BlitzPHP\Container\Container; |
||||
| 15 | use BlitzPHP\Middlewares\BaseMiddleware; |
||||
| 16 | use BlitzPHP\Middlewares\ClosureDecorator; |
||||
| 17 | use Closure; |
||||
| 18 | use Countable; |
||||
| 19 | use InvalidArgumentException; |
||||
| 20 | use LogicException; |
||||
| 21 | use OutOfBoundsException; |
||||
| 22 | use Psr\Http\Server\MiddlewareInterface; |
||||
| 23 | use SeekableIterator; |
||||
| 24 | |||||
| 25 | class MiddlewareQueue implements Countable, SeekableIterator |
||||
| 26 | { |
||||
| 27 | /** |
||||
| 28 | * Index du middleware actuellement executer |
||||
| 29 | */ |
||||
| 30 | protected int $position = 0; |
||||
| 31 | |||||
| 32 | /** |
||||
| 33 | * Aliases des middlewares |
||||
| 34 | */ |
||||
| 35 | protected array $aliases = []; |
||||
| 36 | |||||
| 37 | /** |
||||
| 38 | * Groupes de middlewares |
||||
| 39 | * |
||||
| 40 | * @var array<string, array> |
||||
| 41 | */ |
||||
| 42 | protected array $groups = []; |
||||
| 43 | |||||
| 44 | /** |
||||
| 45 | * Constructor |
||||
| 46 | * |
||||
| 47 | * @param array $queue Liste des middlewares a executer pour la requete courante |
||||
| 48 | */ |
||||
| 49 | public function __construct(protected Container $container, protected array $queue = [], protected ?Request $request = null, protected ?Response $response = null) |
||||
| 50 | { |
||||
| 51 | 14 | $this->request = $request ?: $this->container->get(Request::class); |
|||
| 52 | 14 | $this->response = $response ?: $this->container->get(Response::class); |
|||
| 53 | } |
||||
| 54 | |||||
| 55 | /** |
||||
| 56 | * Ajoute un alias de middleware |
||||
| 57 | */ |
||||
| 58 | public function alias(string $alias, Closure|MiddlewareInterface|string $middleware): static |
||||
| 59 | { |
||||
| 60 | 2 | return $this->aliases([$alias => $middleware]); |
|||
| 61 | } |
||||
| 62 | |||||
| 63 | /** |
||||
| 64 | * Ajoute des alias de middlewares |
||||
| 65 | * |
||||
| 66 | * @param array<string, Closure|MiddlewareInterface|string> $aliases |
||||
| 67 | */ |
||||
| 68 | public function aliases(array $aliases): static |
||||
| 69 | { |
||||
| 70 | 2 | $this->aliases = array_merge($this->aliases, $aliases); |
|||
| 71 | |||||
| 72 | 2 | return $this; |
|||
| 73 | } |
||||
| 74 | |||||
| 75 | /** |
||||
| 76 | * Ajoute des groupes de middlewares |
||||
| 77 | * |
||||
| 78 | * @param array<string, array> $groups |
||||
| 79 | */ |
||||
| 80 | public function groups(array $groups): static |
||||
| 81 | { |
||||
| 82 | 4 | $this->groups = array_merge($this->groups, $groups); |
|||
| 83 | |||||
| 84 | 4 | return $this; |
|||
| 85 | } |
||||
| 86 | |||||
| 87 | /** |
||||
| 88 | * Ajoute un middleware a la chaine d'execution |
||||
| 89 | */ |
||||
| 90 | public function add(array|Closure|MiddlewareInterface|string $middleware): static |
||||
| 91 | { |
||||
| 92 | if (is_array($middleware)) { |
||||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||||
| 93 | 4 | $this->queue = array_merge($this->queue, $middleware); |
|||
| 94 | |||||
| 95 | 4 | return $this; |
|||
| 96 | } |
||||
| 97 | 12 | $this->queue[] = $middleware; |
|||
| 98 | |||||
| 99 | 12 | return $this; |
|||
| 100 | } |
||||
| 101 | |||||
| 102 | /** |
||||
| 103 | * Alias pour MiddlewareQueue::add(). |
||||
| 104 | * |
||||
| 105 | * @see MiddlewareQueue::add() |
||||
| 106 | */ |
||||
| 107 | public function push(array|Closure|MiddlewareInterface|string $middleware): static |
||||
| 108 | { |
||||
| 109 | 4 | return $this->add($middleware); |
|||
| 110 | } |
||||
| 111 | |||||
| 112 | /** |
||||
| 113 | * Ajoute un middleware en bout de chaine |
||||
| 114 | * |
||||
| 115 | * Alias pour MiddlewareQueue::add(). |
||||
| 116 | * |
||||
| 117 | * @see MiddlewareQueue::add() |
||||
| 118 | */ |
||||
| 119 | public function append(array|Closure|MiddlewareInterface|string $middleware): static |
||||
| 120 | { |
||||
| 121 | 2 | return $this->add($middleware); |
|||
| 122 | } |
||||
| 123 | |||||
| 124 | /** |
||||
| 125 | * Ajoute un middleware en debut de chaine |
||||
| 126 | */ |
||||
| 127 | public function prepend(array|Closure|MiddlewareInterface|string $middleware): static |
||||
| 128 | { |
||||
| 129 | if (is_array($middleware)) { |
||||
|
0 ignored issues
–
show
|
|||||
| 130 | 2 | $this->queue = array_merge($middleware, $this->queue); |
|||
| 131 | |||||
| 132 | 2 | return $this; |
|||
| 133 | } |
||||
| 134 | 2 | array_unshift($this->queue, $middleware); |
|||
| 135 | |||||
| 136 | 2 | return $this; |
|||
| 137 | } |
||||
| 138 | |||||
| 139 | /** |
||||
| 140 | * insert un middleware a une position donnee. |
||||
| 141 | * |
||||
| 142 | * Alias pour MiddlewareQueue::add(). |
||||
| 143 | * |
||||
| 144 | * @param int $index La position où le middleware doit être insérer. |
||||
| 145 | * |
||||
| 146 | * @see MiddlewareQueue::add() |
||||
| 147 | */ |
||||
| 148 | public function insert(int $index, Closure|MiddlewareInterface|string $middleware): static |
||||
| 149 | { |
||||
| 150 | return $this->insertAt($index, $middleware); |
||||
| 151 | } |
||||
| 152 | |||||
| 153 | /** |
||||
| 154 | * Insérez un middleware appelable à un index spécifique. |
||||
| 155 | * |
||||
| 156 | * Si l'index existe déjà, le nouvel appelable sera inséré, |
||||
| 157 | * et l'élément existant sera décalé d'un indice supérieur. |
||||
| 158 | * |
||||
| 159 | * @param int $index La position où le middleware doit être insérer. |
||||
| 160 | */ |
||||
| 161 | public function insertAt(int $index, Closure|MiddlewareInterface|string $middleware): static |
||||
| 162 | { |
||||
| 163 | 6 | array_splice($this->queue, $index, 0, [$middleware]); |
|||
| 164 | |||||
| 165 | 6 | return $this; |
|||
| 166 | } |
||||
| 167 | |||||
| 168 | /** |
||||
| 169 | * Insérez un objet middleware avant la première classe correspondante. |
||||
| 170 | * |
||||
| 171 | * Trouve l'index du premier middleware qui correspond à la classe fournie, |
||||
| 172 | * et insère le middleware fourni avant. |
||||
| 173 | * |
||||
| 174 | * @param string $class Le nom de classe pour insérer le middleware avant. |
||||
| 175 | * |
||||
| 176 | * @throws LogicException Si le middleware à insérer avant n'est pas trouvé. |
||||
| 177 | */ |
||||
| 178 | public function insertBefore(string $class, Closure|MiddlewareInterface|string $middleware): static |
||||
| 179 | { |
||||
| 180 | 4 | $found = false; |
|||
| 181 | 4 | $i = 0; |
|||
| 182 | |||||
| 183 | if (array_key_exists($class, $this->aliases) && is_string($this->aliases[$class])) { |
||||
| 184 | 2 | $class = $this->aliases[$class]; |
|||
| 185 | } |
||||
| 186 | |||||
| 187 | foreach ($this->queue as $i => $object) { |
||||
| 188 | if ((is_string($object) && $object === $class) || is_a($object, $class)) { |
||||
| 189 | 4 | $found = true; |
|||
| 190 | 4 | break; |
|||
| 191 | } |
||||
| 192 | } |
||||
| 193 | |||||
| 194 | if ($found) { |
||||
| 195 | 4 | return $this->insertAt($i, $middleware); |
|||
| 196 | } |
||||
| 197 | |||||
| 198 | 2 | throw new LogicException(sprintf("No middleware matching '%s' could be found.", $class)); |
|||
| 199 | } |
||||
| 200 | |||||
| 201 | /** |
||||
| 202 | * Insérez un objet middleware après la première classe correspondante. |
||||
| 203 | * |
||||
| 204 | * Trouve l'index du premier middleware qui correspond à la classe fournie, |
||||
| 205 | * et insère le callback fourni après celui-ci. Si la classe n'est pas trouvée, |
||||
| 206 | * cette méthode se comportera comme add(). |
||||
| 207 | * |
||||
| 208 | * @param string $class Le nom de classe pour insérer le middleware après. |
||||
| 209 | */ |
||||
| 210 | public function insertAfter(string $class, Closure|MiddlewareInterface|string $middleware): static |
||||
| 211 | { |
||||
| 212 | 4 | $found = false; |
|||
| 213 | 4 | $i = 0; |
|||
| 214 | |||||
| 215 | if (array_key_exists($class, $this->aliases) && is_string($this->aliases[$class])) { |
||||
| 216 | 2 | $class = $this->aliases[$class]; |
|||
| 217 | } |
||||
| 218 | |||||
| 219 | foreach ($this->queue as $i => $object) { |
||||
| 220 | if ((is_string($object) && $object === $class) || is_a($object, $class)) { |
||||
| 221 | 4 | $found = true; |
|||
| 222 | 4 | break; |
|||
| 223 | } |
||||
| 224 | } |
||||
| 225 | |||||
| 226 | if ($found) { |
||||
| 227 | 4 | return $this->insertAt($i + 1, $middleware); |
|||
| 228 | } |
||||
| 229 | |||||
| 230 | 2 | return $this->add($middleware); |
|||
| 231 | } |
||||
| 232 | |||||
| 233 | /** |
||||
| 234 | * Obtenir le nombre de couches middleware connectés. |
||||
| 235 | */ |
||||
| 236 | public function count(): int |
||||
| 237 | { |
||||
| 238 | 8 | return count($this->queue); |
|||
| 239 | } |
||||
| 240 | |||||
| 241 | /** |
||||
| 242 | * {@inheritDoc} |
||||
| 243 | */ |
||||
| 244 | public function seek(int $position): void |
||||
| 245 | { |
||||
| 246 | if (! isset($this->queue[$position])) { |
||||
| 247 | 2 | throw new OutOfBoundsException(sprintf('Invalid seek position (%s).', $position)); |
|||
| 248 | } |
||||
| 249 | |||||
| 250 | 2 | $this->position = $position; |
|||
| 251 | } |
||||
| 252 | |||||
| 253 | /** |
||||
| 254 | * {@inheritDoc} |
||||
| 255 | */ |
||||
| 256 | public function rewind(): void |
||||
| 257 | { |
||||
| 258 | 4 | $this->position = 0; |
|||
| 259 | } |
||||
| 260 | |||||
| 261 | /** |
||||
| 262 | * {@inheritDoc} |
||||
| 263 | */ |
||||
| 264 | public function current(): MiddlewareInterface |
||||
| 265 | { |
||||
| 266 | if (! isset($this->queue[$this->position])) { |
||||
| 267 | 2 | throw new OutOfBoundsException(sprintf('Position actuelle non valide (%s).', $this->position)); |
|||
| 268 | } |
||||
| 269 | |||||
| 270 | if ($this->queue[$this->position] instanceof MiddlewareInterface) { |
||||
| 271 | 6 | return $this->queue[$this->position]; |
|||
| 272 | } |
||||
| 273 | |||||
| 274 | 14 | return $this->queue[$this->position] = $this->resolve($this->queue[$this->position]); |
|||
| 275 | } |
||||
| 276 | |||||
| 277 | /** |
||||
| 278 | * {@inheritDoc} |
||||
| 279 | */ |
||||
| 280 | public function key(): int |
||||
| 281 | { |
||||
| 282 | return $this->position; |
||||
| 283 | } |
||||
| 284 | |||||
| 285 | /** |
||||
| 286 | * Passe la position actuelle au middleware suivant. |
||||
| 287 | */ |
||||
| 288 | public function next(): void |
||||
| 289 | { |
||||
| 290 | 8 | $this->position++; |
|||
| 291 | } |
||||
| 292 | |||||
| 293 | /** |
||||
| 294 | * Vérifie si la position actuelle est valide. |
||||
| 295 | */ |
||||
| 296 | public function valid(): bool |
||||
| 297 | { |
||||
| 298 | 2 | return isset($this->queue[$this->position]); |
|||
| 299 | } |
||||
| 300 | |||||
| 301 | /** |
||||
| 302 | * Enregistre les middlewares definis dans le gestionnaire des middlewares |
||||
| 303 | * |
||||
| 304 | * @internal |
||||
| 305 | */ |
||||
| 306 | public function register(array $config) |
||||
| 307 | { |
||||
| 308 | $config += [ |
||||
| 309 | 'aliases' => [], |
||||
| 310 | 'globals' => [], |
||||
| 311 | 'groups' => [], |
||||
| 312 | 'build' => static fn () => null, |
||||
| 313 | 2 | ]; |
|||
| 314 | |||||
| 315 | 2 | $this->aliases($config['aliases']); |
|||
| 316 | 2 | $this->groups($config['groups']); |
|||
| 317 | |||||
| 318 | foreach ($config['globals'] as $middleware) { |
||||
| 319 | 2 | $this->add($middleware); |
|||
| 320 | } |
||||
| 321 | |||||
| 322 | if (is_callable($build = $config['build'])) { |
||||
| 323 | $this->container->call($build, [ |
||||
| 324 | 'request' => $this->request, |
||||
| 325 | 'queue' => $this, |
||||
| 326 | 2 | ]); |
|||
| 327 | } |
||||
| 328 | } |
||||
| 329 | |||||
| 330 | /** |
||||
| 331 | * Resout les groups pour definir les middlewares |
||||
| 332 | * |
||||
| 333 | * @internal |
||||
| 334 | */ |
||||
| 335 | public function resolveGroups() |
||||
| 336 | { |
||||
| 337 | foreach ($this->queue as $queue) { |
||||
| 338 | if (is_string($queue) && ! empty($this->groups[$queue])) { |
||||
| 339 | if (! is_array($this->groups[$queue])) { |
||||
| 340 | continue; |
||||
| 341 | } |
||||
| 342 | |||||
| 343 | 2 | $i = array_search($queue, $this->queue, true); |
|||
| 344 | 2 | $j = 0; |
|||
| 345 | |||||
| 346 | 2 | unset($this->queue[$i]); |
|||
| 347 | |||||
| 348 | foreach ($this->groups[$queue] as $middleware) { |
||||
| 349 | 2 | $this->insertAt(($i + $j), $middleware); |
|||
| 350 | 2 | $j++; |
|||
| 351 | } |
||||
| 352 | } |
||||
| 353 | } |
||||
| 354 | } |
||||
| 355 | |||||
| 356 | /** |
||||
| 357 | * {@internal} |
||||
| 358 | */ |
||||
| 359 | public function response(): Response |
||||
| 360 | { |
||||
| 361 | 2 | return $this->response; |
|||
|
0 ignored issues
–
show
|
|||||
| 362 | } |
||||
| 363 | |||||
| 364 | /** |
||||
| 365 | * Résoudre le nom middleware à une instance de middleware compatible PSR 15. |
||||
| 366 | * |
||||
| 367 | * @throws InvalidArgumentException si Middleware introuvable. |
||||
| 368 | */ |
||||
| 369 | protected function resolve(Closure|MiddlewareInterface|string $middleware): MiddlewareInterface |
||||
| 370 | { |
||||
| 371 | if (is_string($middleware)) { |
||||
| 372 | 8 | [$middleware, $options] = explode(':', $middleware) + [1 => null]; |
|||
| 373 | |||||
| 374 | if (isset($this->aliases[$middleware])) { |
||||
| 375 | 2 | $middleware = $this->aliases[$middleware]; |
|||
| 376 | } |
||||
| 377 | |||||
| 378 | if ($this->container->has($middleware)) { |
||||
| 379 | 8 | $middleware = $this->container->get($middleware); |
|||
| 380 | } else { |
||||
| 381 | throw new InvalidArgumentException(sprintf( |
||||
| 382 | 'Middleware, `%s` n\'a pas été trouvé.', |
||||
| 383 | $middleware |
||||
| 384 | 2 | )); |
|||
| 385 | } |
||||
| 386 | |||||
| 387 | if ($middleware instanceof BaseMiddleware) { |
||||
| 388 | if (null !== $options) { |
||||
| 389 | $middleware->fill(explode(',', $options)); |
||||
| 390 | } |
||||
| 391 | |||||
| 392 | $middleware->init($this->request->getPath()); |
||||
|
0 ignored issues
–
show
The method
getPath() does not exist on null.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||||
| 393 | } |
||||
| 394 | } |
||||
| 395 | |||||
| 396 | if ($middleware instanceof MiddlewareInterface) { |
||||
| 397 | 8 | return $middleware; |
|||
| 398 | } |
||||
| 399 | |||||
| 400 | 12 | return new ClosureDecorator($middleware, $this->response); |
|||
|
0 ignored issues
–
show
It seems like
$middleware can also be of type string; however, parameter $callable of BlitzPHP\Middlewares\Clo...ecorator::__construct() does only seem to accept Closure, 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
Loading history...
|
|||||
| 401 | } |
||||
| 402 | } |
||||
| 403 |