Passed
Pull Request — master (#138)
by Rustam
02:27
created

Route::patch()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
use Yiisoft\Http\Method;
10
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
11
12
/**
13
 * Route defines a mapping from URL to callback / name and vice versa.
14
 */
15
final class Route
16
{
17
    private ?string $name = null;
18
    /** @var string[] */
19
    private array $methods;
20
    private string $pattern;
21
    private ?string $host = null;
22
    private bool $override = false;
23
    private ?MiddlewareDispatcher $dispatcher;
24
    private bool $actionAdded = false;
25
    private array $middlewareDefinitions = [];
26
    private array $disabledMiddlewareDefinitions = [];
27
    private array $defaults = [];
28
29 50
    private function __construct(?MiddlewareDispatcher $dispatcher = null)
30
    {
31 50
        $this->dispatcher = $dispatcher;
32 50
    }
33
34 7
    public function injectDispatcher(MiddlewareDispatcher $dispatcher): void
35
    {
36 7
        $this->dispatcher = $dispatcher;
37 7
    }
38
39
    /**
40
     * @return self
41
     */
42 5
    public function withDispatcher(MiddlewareDispatcher $dispatcher): self
43
    {
44 5
        $route = clone $this;
45 5
        $route->dispatcher = $dispatcher;
46 5
        return $route;
47
    }
48
49 12
    public function getDispatcherWithMiddlewares(): MiddlewareDispatcher
50
    {
51 12
        if ($this->dispatcher->hasMiddlewares()) {
0 ignored issues
show
Bug introduced by
The method hasMiddlewares() 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 ignore-call  annotation

51
        if ($this->dispatcher->/** @scrutinizer ignore-call */ hasMiddlewares()) {

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...
52
            return $this->dispatcher;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->dispatcher could return the type null which is incompatible with the type-hinted return Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher. Consider adding an additional type-check to rule them out.
Loading history...
53
        }
54
55 12
        foreach ($this->middlewareDefinitions as $index => $definition) {
56 12
            if (in_array($definition, $this->disabledMiddlewareDefinitions, true)) {
57
                unset($this->middlewareDefinitions[$index]);
58
            }
59
        }
60
61 12
        return $this->dispatcher = $this->dispatcher->withMiddlewares($this->middlewareDefinitions);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->dispatcher...>middlewareDefinitions) could return the type null which is incompatible with the type-hinted return Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher. Consider adding an additional type-check to rule them out.
Loading history...
62
    }
63
64 26
    public function hasDispatcher(): bool
65
    {
66 26
        return $this->dispatcher !== null;
67
    }
68
69
    /**
70
     * @param string $pattern
71
     * @param MiddlewareDispatcher|null $dispatcher
72
     *
73
     * @return self
74
     */
75 39
    public static function get(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
76
    {
77 39
        return self::methods([Method::GET], $pattern, $dispatcher);
78
    }
79
80
    /**
81
     * @param string $pattern
82
     * @param MiddlewareDispatcher|null $dispatcher
83
     *
84
     * @return self
85
     */
86 9
    public static function post(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
87
    {
88 9
        return self::methods([Method::POST], $pattern, $dispatcher);
89
    }
90
91
    /**
92
     * @param string $pattern
93
     * @param MiddlewareDispatcher|null $dispatcher
94
     *
95
     * @return self
96
     */
97 4
    public static function put(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
98
    {
99 4
        return self::methods([Method::PUT], $pattern, $dispatcher);
100
    }
101
102
    /**
103
     * @param string $pattern
104
     * @param MiddlewareDispatcher|null $dispatcher
105
     *
106
     * @return self
107
     */
108 1
    public static function delete(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
109
    {
110 1
        return self::methods([Method::DELETE], $pattern, $dispatcher);
111
    }
112
113
    /**
114
     * @param string $pattern
115
     * @param MiddlewareDispatcher|null $dispatcher
116
     *
117
     * @return self
118
     */
119 1
    public static function patch(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
120
    {
121 1
        return self::methods([Method::PATCH], $pattern, $dispatcher);
122
    }
123
124
    /**
125
     * @param string $pattern
126
     * @param MiddlewareDispatcher|null $dispatcher
127
     *
128
     * @return self
129
     */
130 1
    public static function head(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
131
    {
132 1
        return self::methods([Method::HEAD], $pattern, $dispatcher);
133
    }
134
135
    /**
136
     * @param string $pattern
137
     * @param MiddlewareDispatcher|null $dispatcher
138
     *
139
     * @return self
140
     */
141 7
    public static function options(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
142
    {
143 7
        return self::methods([Method::OPTIONS], $pattern, $dispatcher);
144
    }
145
146
    /**
147
     * @param array $methods
148
     * @param string $pattern
149
     * @param MiddlewareDispatcher|null $dispatcher
150
     *
151
     * @return self
152
     */
153 50
    public static function methods(
154
        array $methods,
155
        string $pattern,
156
        ?MiddlewareDispatcher $dispatcher = null
157
    ): self {
158 50
        $route = new self($dispatcher);
159 50
        $route->methods = $methods;
160 50
        $route->pattern = $pattern;
161
162 50
        return $route;
163
    }
164
165
    /**
166
     * @return self
167
     */
168 19
    public function name(string $name): self
169
    {
170 19
        $route = clone $this;
171 19
        $route->name = $name;
172 19
        return $route;
173
    }
174
175
    /**
176
     * @return self
177
     */
178 19
    public function pattern(string $pattern): self
179
    {
180 19
        $new = clone $this;
181 19
        $new->pattern = $pattern;
182 19
        return $new;
183
    }
184
185
    /**
186
     * @return self
187
     */
188 4
    public function host(string $host): self
189
    {
190 4
        $route = clone $this;
191 4
        $route->host = rtrim($host, '/');
192 4
        return $route;
193
    }
194
195
    /**
196
     * Marks route as override. When added it will replace existing route with the same name.
197
     *
198
     * @return self
199
     */
200 2
    public function override(): self
201
    {
202 2
        $route = clone $this;
203 2
        $route->override = true;
204 2
        return $route;
205
    }
206
207
    /**
208
     * Parameter default values indexed by parameter names.
209
     *
210
     * @param array $defaults
211
     *
212
     * @return self
213
     */
214 1
    public function defaults(array $defaults): self
215
    {
216 1
        $route = clone $this;
217 1
        $route->defaults = $defaults;
218 1
        return $route;
219
    }
220
221
    /**
222
     * Appends a handler middleware definition that should be invoked for a matched route.
223
     * First added handler will be executed first.
224
     *
225
     * @param mixed $middlewareDefinition
226
     *
227
     * @return self
228
     */
229 11
    public function middleware($middlewareDefinition): self
230
    {
231 11
        if ($this->actionAdded) {
232
            throw new RuntimeException('middleware() can not be used after action().');
233
        }
234 11
        $route = clone $this;
235 11
        $route->middlewareDefinitions[] = $middlewareDefinition;
236 11
        return $route;
237
    }
238
239
    /**
240
     * Prepends a handler middleware definition that should be invoked for a matched route.
241
     * Last added handler will be executed first.
242
     *
243
     * @param mixed $middlewareDefinition
244
     *
245
     * @return self
246
     */
247 11
    public function prependMiddleware($middlewareDefinition): self
248
    {
249 11
        if (!$this->actionAdded) {
250
            throw new RuntimeException('prependMiddleware() can not be used before action().');
251
        }
252 11
        $route = clone $this;
253 11
        array_unshift($route->middlewareDefinitions, $middlewareDefinition);
254 11
        return $route;
255
    }
256
257
    /**
258
     * Appends action handler. It is a primary middleware definition that should be invoked last for a matched route.
259
     *
260
     * @param mixed $middlewareDefinition
261
     *
262
     * @return self
263
     */
264 13
    public function action($middlewareDefinition): self
265
    {
266 13
        $route = clone $this;
267 13
        $route->middlewareDefinitions[] = $middlewareDefinition;
268 13
        $route->actionAdded = true;
269 13
        return $route;
270
    }
271
272
    /**
273
     * Excludes middleware from being invoked when action is handled.
274
     * It is useful to avoid invoking one of the parent group middleware for
275
     * a certain route.
276
     *
277
     * @param mixed $middlewareDefinition
278
     *
279
     * @return self
280
     */
281
    public function disableMiddleware($middlewareDefinition): self
282
    {
283
        $route = clone $this;
284
        $route->disabledMiddlewareDefinitions[] = $middlewareDefinition;
285
        return $route;
286
    }
287
288 3
    public function __toString(): string
289
    {
290 3
        $result = '';
291
292 3
        if ($this->name !== null) {
293 2
            $result .= '[' . $this->name . '] ';
294
        }
295
296 3
        if ($this->methods !== []) {
297 3
            $result .= implode(',', $this->methods) . ' ';
298
        }
299 3
        if ($this->host !== null && strrpos($this->pattern, $this->host) === false) {
300 1
            $result .= $this->host;
301
        }
302 3
        $result .= $this->pattern;
303
304 3
        return $result;
305
    }
306
307
    /**
308
     * @param string $key
309
     *
310
     * @return mixed
311
     */
312 34
    public function getData(string $key)
313
    {
314 34
        switch ($key) {
315 34
            case 'name':
316 22
                return $this->name ?? (implode(', ', $this->methods) . ' ' . $this->host . $this->pattern);
317 30
            case 'pattern':
318 19
                return $this->pattern;
319 29
            case 'host':
320 7
                return $this->host;
321 28
            case 'methods':
322 26
                return $this->methods;
323 5
            case 'defaults':
324 1
                return $this->defaults;
325 4
            case 'override':
326 4
                return $this->override;
327
            default:
328
                throw new InvalidArgumentException('Unknown data key: ' . $key);
329
        }
330
    }
331
332 18
    public function hasMiddlewares(): bool
333
    {
334 18
        return $this->middlewareDefinitions !== [];
335
    }
336
337
    public function __debugInfo()
338
    {
339
        return [
340
            'name' => $this->name,
341
            'methods' => $this->methods,
342
            'pattern' => $this->pattern,
343
            'host' => $this->host,
344
            'defaults' => $this->defaults,
345
            'override' => $this->override,
346
            'actionAdded' => $this->actionAdded,
347
            'middlewareDefinitions' => $this->middlewareDefinitions,
348
            'disabledMiddlewareDefinitions' => $this->disabledMiddlewareDefinitions,
349
            'middlewareDispatcher' => $this->dispatcher,
350
        ];
351
    }
352
}
353