Passed
Push — master ( 02c0f4...848e78 )
by Divine Niiquaye
08:42
created

MiddlewareTrait::prepare()   B

Complexity

Conditions 11
Paths 48

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 11.0359

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 15
c 1
b 0
f 0
nc 48
nop 1
dl 0
loc 31
ccs 14
cts 15
cp 0.9333
crap 11.0359
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Flight Routing.
7
 *
8
 * PHP version 7.1 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Flight\Routing\Traits;
19
20
use Closure;
21
use Flight\Routing\Exceptions\DuplicateRouteException;
22
use Flight\Routing\Exceptions\InvalidMiddlewareException;
23
use Laminas\Stratigility\Middleware\CallableMiddlewareDecorator;
24
use Laminas\Stratigility\Middleware\RequestHandlerMiddleware;
25
use Psr\Container\NotFoundExceptionInterface;
26
use Psr\Http\Server\MiddlewareInterface;
27
use Psr\Http\Server\RequestHandlerInterface;
28
29
/**
30
 * Provides ability to manage set of middleware.
31
 */
32
trait MiddlewareTrait
33
{
34
    /**
35
     * Set of middleware to be applied for every request.
36
     *
37
     * @var array<int|string,mixed>
38
     */
39
    protected $middlewares = [];
40
41
    /**
42
     * Set of route middleware to be used in $middlewares
43
     * Stack, if string name is equal to a given middleware.
44
     *
45
     * @var array<int|string,mixed>
46
     */
47
    protected $nameMiddlewares = [];
48
49
    /**
50
     * Add new middleware(s) at the end of chain.
51
     *
52
     * Example (in bootstrap):
53
     * $this->addMiddleware(new ProxyMiddleware());
54
     *
55
     * @param array<string,mixed>|callable|MiddlewareInterface|RequestHandlerInterface|string ...$middlewares
56
     *
57
     * @throws DuplicateRouteException
58
     */
59 42
    public function addMiddleware(...$middlewares): void
60
    {
61 42
        foreach ($middlewares as $middleware) {
62 31
            if (\is_array($middleware) && !\is_callable($middleware)) {
63 5
                $this->addRecursiveMiddleware($middleware);
64
65 5
                continue;
66
            }
67
68 29
            $hash = $this->getHash($middleware);
69
70 29
            if (isset($this->middlewares[$hash])) {
71 1
                throw new DuplicateRouteException(\sprintf('A middleware with the hash "%s" already exists.', $hash));
72
            }
73
74 29
            $this->middlewares[$hash] = $middleware;
75
        }
76 42
    }
77
78
    /**
79
     * @param array<int|string,mixed> $middlewares
80
     */
81 5
    protected function addRecursiveMiddleware(array $middlewares): void
82
    {
83 5
        foreach ($middlewares as $index => $middleware) {
84 5
            if (\is_string($index)) {
85 4
                $this->nameMiddlewares[$index] = $middleware;
86
87 4
                continue;
88
            }
89
90 1
            $this->addMiddleware($middleware);
91
        }
92 5
    }
93
94
    /**
95
     * Add a new middleware to the stack.
96
     *
97
     * Middleware are organized as a stack. That means middleware
98
     * that have been added before will be executed after the newly
99
     * added one (last in, first out).
100
     *
101
     * @param mixed $middleware
102
     *
103
     * @throws InvalidMiddlewareException if argument is not one of
104
     *                                    the specified types
105
     *
106
     * @return MiddlewareInterface
107
     */
108 26
    protected function prepare($middleware): MiddlewareInterface
109
    {
110 26
        if (\is_string($middleware) && \array_key_exists($middleware, $this->nameMiddlewares)) {
111 1
            $middleware = $this->nameMiddlewares[$middleware];
112
        }
113
114 26
        if (\is_string($middleware) && null !== $this->container) {
115
            try {
116 2
                $middleware = $this->container->get($middleware);
117
            } catch (NotFoundExceptionInterface $e) {
118
                // ... handled at the end
119
            }
120
        }
121
122 26
        if (\is_string($middleware) && \class_exists($middleware)) {
123 4
            $middleware = new $middleware();
124
        }
125
126 26
        if ($middleware instanceof RequestHandlerInterface) {
127 1
            return new RequestHandlerMiddleware($middleware);
128
        }
129
130 26
        if (\is_callable($middleware)) {
131 2
            return new CallableMiddlewareDecorator($middleware);
132
        }
133
134 26
        if (!$middleware instanceof MiddlewareInterface) {
135 3
            throw InvalidMiddlewareException::forMiddleware($middleware);
136
        }
137
138 24
        return $middleware;
139
    }
140
141
    /**
142
     * @param mixed $middleware
143
     *
144
     * @return string
145
     */
146 29
    private function getHash($middleware): string
147
    {
148 29
        if ($middleware instanceof Closure || \is_object($middleware)) {
149 27
            return \spl_object_hash($middleware);
150
        }
151
152 11
        if (\is_callable($middleware) && \count($middleware) === 2) {
153 2
            return $middleware[1];
154
        }
155
156 11
        return \md5($middleware);
157
    }
158
}
159