Passed
Push — master ( f1358e...f908b9 )
by Alexander
11:22
created

Route::methods()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Yiisoft\Router;
4
5
use InvalidArgumentException;
6
use LogicException;
7
use Yiisoft\Router\Middleware\Callback;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
13
/**
14
 * Route defines a mapping from URL to callback / name and vice versa
15
 */
16
final class Route implements MiddlewareInterface, RequestHandlerInterface
17
{
18
    private ?string $name = null;
19
    /** @var string[] */
20
    private array $methods;
21
    private string $pattern;
22
    private ?string $host = null;
23
    /**
24
     * @var MiddlewareInterface[]|callable[]
25
     */
26
    private array $middlewares = [];
27
    private array $defaults = [];
28
    private RequestHandlerInterface $nextHandler;
29
30
    private function __construct()
31
    {
32
    }
33
34
    public static function get(string $pattern): self
35 17
    {
36
        $route = new static();
37 17
        $route->methods = [Method::GET];
38 17
        $route->pattern = $pattern;
39 17
        return $route;
40 17
    }
41
42
    public static function post(string $pattern): self
43 3
    {
44
        $route = new static();
45 3
        $route->methods = [Method::POST];
46 3
        $route->pattern = $pattern;
47 3
        return $route;
48 3
    }
49
50
    public static function put(string $pattern): self
51 1
    {
52
        $route = new static();
53 1
        $route->methods = [Method::PUT];
54 1
        $route->pattern = $pattern;
55 1
        return $route;
56 1
    }
57
58
    public static function delete(string $pattern): self
59 1
    {
60
        $route = new static();
61 1
        $route->methods = [Method::DELETE];
62 1
        $route->pattern = $pattern;
63 1
        return $route;
64 1
    }
65
66
    public static function patch(string $pattern): self
67 1
    {
68
        $route = new static();
69 1
        $route->methods = [Method::PATCH];
70 1
        $route->pattern = $pattern;
71 1
        return $route;
72 1
    }
73
74
    public static function head(string $pattern): self
75 1
    {
76
        $route = new static();
77 1
        $route->methods = [Method::HEAD];
78 1
        $route->pattern = $pattern;
79 1
        return $route;
80 1
    }
81
82
    public static function options(string $pattern): self
83 1
    {
84
        $route = new static();
85 1
        $route->methods = [Method::OPTIONS];
86 1
        $route->pattern = $pattern;
87 1
        return $route;
88 1
    }
89
90
    public static function methods(array $methods, string $pattern): self
91 2
    {
92
        $route = new static();
93 2
        $route->methods = $methods;
94 2
        $route->pattern = $pattern;
95 2
        return $route;
96 2
    }
97
98
    public static function anyMethod(string $pattern): self
99 1
    {
100
        $route = new static();
101 1
        $route->methods = Method::ANY;
102 1
        $route->pattern = $pattern;
103 1
        return $route;
104 1
    }
105
106
    public function name(string $name): self
107 2
    {
108
        $route = clone $this;
109 2
        $route->name = $name;
110 2
        return $route;
111 2
    }
112
113
    public function pattern(string $pattern): self
114 1
    {
115
        $new = clone $this;
116 1
        $new->pattern = $pattern;
117 1
        return $new;
118 1
    }
119
120
    public function host(string $host): self
121 2
    {
122
        $route = clone $this;
123 2
        $route->host = rtrim($host, '/');
124 2
        return $route;
125 2
    }
126
127
    /**
128
     * Parameter default values indexed by parameter names
129
     *
130
     * @param array $defaults
131
     * @return Route
132
     */
133
    public function defaults(array $defaults): self
134 1
    {
135
        $route = clone $this;
136 1
        $route->defaults = $defaults;
137 1
        return $route;
138 1
    }
139
140
    /**
141
     * @param callable|MiddlewareInterface $middleware
142
     * @return MiddlewareInterface
143
     */
144
    private function prepareMiddleware($middleware): MiddlewareInterface
145
    {
146
        if (is_callable($middleware)) {
147 1
            $middleware = new Callback($middleware);
0 ignored issues
show
Bug introduced by
It seems like $middleware can also be of type Psr\Http\Server\MiddlewareInterface; however, parameter $callback of Yiisoft\Router\Middleware\Callback::__construct() does only seem to accept callable, 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 ignore-type  annotation

147
            $middleware = new Callback(/** @scrutinizer ignore-type */ $middleware);
Loading history...
148
        }
149 1
150 1
        if (!$middleware instanceof MiddlewareInterface) {
151 1
            throw new InvalidArgumentException('Parameter should be either a PSR middleware or a callable.');
152
        }
153
154
        return $middleware;
155
    }
156
157
    /**
158 7
     * Adds a handler that should be invoked for a matching route.
159
     * It can be either a PSR middleware or a callable with the following signature:
160 7
     *
161 1
     * ```
162
     * function (ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
163
     * ```
164 7
     *
165 1
     * @param MiddlewareInterface|callable $middleware
166
     * @return Route
167
     */
168 6
    public function to($middleware): self
169
    {
170
        $route = clone $this;
171
        $route->middlewares[] = $this->prepareMiddleware($middleware);
172
        return $route;
173
    }
174
175
    /**
176
     * Adds a handler that should be invoked for a matching route.
177
     * It can be either a PSR middleware or a callable with the following signature:
178
     *
179
     * ```
180
     * function (ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
181
     * ```
182 7
     *
183
     * @param MiddlewareInterface|callable $middleware
184 7
     * @return Route
185 7
     */
186 6
    public function then($middleware): self
187
    {
188
        return $this->to($middleware);
189
    }
190
191
    /**
192
     * Prepends a handler that should be invoked for a matching route.
193
     * It can be either a PSR middleware or a callable with the following signature:
194
     *
195
     * ```
196
     * function (ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
197
     * ```
198
     *
199
     * @param MiddlewareInterface|callable $middleware
200 1
     * @return Route
201
     */
202 1
    public function prepend($middleware): self
203
    {
204
        $route = clone $this;
205
        array_unshift($route->middlewares, $this->prepareMiddleware($middleware));
206
        return $route;
207
    }
208
209
    public function __toString()
210
    {
211
        $result = '';
212
213
        if ($this->name !== null) {
214
            $result .= '[' . $this->name . '] ';
215
        }
216 1
217
        if ($this->methods !== []) {
218 1
            $result .= implode(',', $this->methods) . ' ';
219 1
        }
220 1
        if ($this->host !== null && strrpos($this->pattern, $this->host) === false) {
221
            $result .= $this->host;
222
        }
223 2
        $result .= $this->pattern;
224
225 2
        return $result;
226
    }
227 2
228 1
    public function getName(): string
229
    {
230
        return $this->name ?? (implode(', ', $this->methods) . ' ' . $this->pattern);
231 2
    }
232 2
233
    public function getMethods(): array
234 2
    {
235 1
        return $this->methods;
236
    }
237 2
238
    public function getPattern(): string
239 2
    {
240
        return $this->pattern;
241
    }
242 2
243
    public function getHost(): ?string
244 2
    {
245
        return $this->host;
246
    }
247 9
248
    public function getDefaults(): array
249 9
    {
250
        return $this->defaults;
251
    }
252 1
253
    /**
254 1
     * @internal please use {@see dispatch()} or {@see process()}
255
     * @param ServerRequestInterface $request
256
     * @return ResponseInterface
257 1
     */
258
    public function handle(ServerRequestInterface $request): ResponseInterface
259 1
    {
260
        $middleware = current($this->middlewares);
261
        next($this->middlewares);
262 1
        if ($middleware === false) {
263
            if (!$this->nextHandler !== null) {
0 ignored issues
show
introduced by
The condition ! $this->nextHandler !== null is always true.
Loading history...
264 1
                return $this->nextHandler->handle($request);
265
            }
266
267 1
            throw new LogicException('Middleware stack exhausted');
268
        }
269 1
270
        return $middleware->process($request, $this);
271
    }
272
273
    public function dispatch(ServerRequestInterface $request): ResponseInterface
274
    {
275
        reset($this->middlewares);
276
        return $this->handle($request);
277 6
    }
278
279 6
    public function process(ServerRequestInterface $request, RequestHandlerInterface $nextHandler): ResponseInterface
280 6
    {
281 6
        $this->nextHandler = $nextHandler;
282
        return $this->dispatch($request);
283
    }
284
}
285