Passed
Pull Request — master (#225)
by Rustam
02:46
created

Route::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
nc 2
nop 9
dl 0
loc 19
ccs 8
cts 8
cp 1
crap 2
rs 10
c 1
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
use Stringable;
9
use Yiisoft\Router\Internal\MiddlewareFilter;
10
11
/**
12
 * Route defines a mapping from URL to callback / name and vice versa.
13
 */
14
final class Route implements Stringable
15
{
16
    /**
17
     * @var string[]
18
     * @psalm-var array<array-key, string>
19
     */
20
    private array $methods = [];
21
22
    /**
23
     * @var string[]
24
     */
25
    private array $hosts = [];
26
27
    /**
28
     * @var array|callable|string|null
29
     */
30
    private $action = null;
31
32
    /**
33
     * @var array[]|callable[]|string[]
34
     * @psalm-var list<array|callable|string>
35
     */
36
    private array $middlewares = [];
37
38
    /**
39
     * @psalm-var list<array|callable|string>|null
40
     */
41
    private ?array $enabledMiddlewaresCache = null;
42
43
    /**
44
     * @var array<array-key,string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key,string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key,string>.
Loading history...
45
     */
46
    private array $defaults = [];
47
48
    /**
49
     * @param array|callable|string|null $action Action handler. It is a primary middleware definition that
50
     * should be invoked last for a matched route.
51
     * @param array<array-key,scalar|Stringable|null> $defaults Parameter default values indexed by parameter names.
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key,scalar|Stringable|null> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key,scalar|Stringable|null>.
Loading history...
52
     * @param bool $override Marks route as override. When added it will replace existing route with the same name.
53
     * @param array $disabledMiddlewares Excludes middleware from being invoked when action is handled.
54
     * It is useful to avoid invoking one of the parent group middleware for
55
     * a certain route.
56
     */
57 93
    public function __construct(
58
        array $methods,
59
        private string $pattern,
60
        private ?string $name = null,
61
        array|callable|string $action = null,
62
        array $middlewares = [],
63
        array $defaults = [],
64
        array $hosts = [],
65
        private bool $override = false,
66
        private array $disabledMiddlewares = [],
67
    ) {
68 93
        if (empty($methods)) {
69 1
            throw new InvalidArgumentException('$methods cannot be empty.');
70
        }
71 92
        $this->setMethods($methods);
72 92
        $this->action = $action;
73 92
        $this->setMiddlewares($middlewares);
74 91
        $this->setHosts($hosts);
75 90
        $this->setDefaults($defaults);
76
    }
77
78
    /**
79
     * @return string[]
80
     */
81 32
    public function getMethods(): array
82
    {
83 32
        return $this->methods;
84
    }
85
86 22
    public function getAction(): array|callable|string|null
87
    {
88 22
        return $this->action;
89
    }
90
91 27
    public function getMiddlewares(): array
92
    {
93 27
        return $this->middlewares;
94
    }
95
96
    /**
97
     * @return string[]
98
     */
99 14
    public function getHosts(): array
100
    {
101 14
        return $this->hosts;
102
    }
103
104 2
    public function getDefaults(): array
105
    {
106 2
        return $this->defaults;
107
    }
108
109 25
    public function getPattern(): string
110
    {
111 25
        return $this->pattern;
112
    }
113
114 35
    public function getName(): string
115
    {
116 35
        return $this->name ??= (implode(', ', $this->methods) . ' ' . implode('|', $this->hosts) . $this->pattern);
117
    }
118
119 6
    public function isOverride(): bool
120
    {
121 6
        return $this->override;
122
    }
123
124 1
    public function getDisabledMiddlewares(): array
125
    {
126 1
        return $this->disabledMiddlewares;
127
    }
128
129
    /**
130
     * @return array[]|callable[]|string[]
131
     * @psalm-return list<array|callable|string>
132
     */
133 27
    public function getEnabledMiddlewares(): array
134
    {
135 27
        if ($this->enabledMiddlewaresCache !== null) {
136
            return $this->enabledMiddlewaresCache;
137
        }
138
139 27
        $this->enabledMiddlewaresCache = MiddlewareFilter::filter($this->middlewares, $this->disabledMiddlewares);
140 27
        if ($this->action !== null) {
141 18
            $this->enabledMiddlewaresCache[] = $this->action;
142
        }
143
144 27
        return $this->enabledMiddlewaresCache;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->enabledMiddlewaresCache returns the type null which is incompatible with the type-hinted return array.
Loading history...
145
    }
146
147 92
    public function setMethods(array $methods): self
148
    {
149 92
        $this->assertListOfStrings($methods, 'methods');
150 92
        $this->methods = $methods;
151 92
        return $this;
152
    }
153
154 91
    public function setHosts(array $hosts): self
155
    {
156 91
        $this->assertListOfStrings($hosts, 'hosts');
157 90
        $this->hosts = [];
158 90
        foreach ($hosts as $host) {
159 16
            $host = rtrim($host, '/');
160
161 16
            if ($host !== '' && !in_array($host, $this->hosts, true)) {
162 16
                $this->hosts[] = $host;
163
            }
164
        }
165
166 90
        return $this;
167
    }
168
169 7
    public function setAction(callable|array|string|null $action): self
170
    {
171 7
        $this->action = $action;
172 7
        return $this;
173
    }
174
175 92
    public function setMiddlewares(array $middlewares): self
176
    {
177 92
        $this->assertMiddlewares($middlewares);
178 91
        $this->middlewares = $middlewares;
179 91
        $this->enabledMiddlewaresCache = null;
180 91
        return $this;
181
    }
182
183 90
    public function setDefaults(array $defaults): self
184
    {
185
        /** @var mixed $value */
186 90
        foreach ($defaults as $key => $value) {
187 3
            if (!is_scalar($value) && !($value instanceof Stringable)) {
188
                throw new \InvalidArgumentException(
189
                    'Invalid $defaults provided, list of scalar or `Stringable` instance expected.'
190
                );
191
            }
192 3
            $this->defaults[$key] = (string) $value;
193
        }
194 90
        return $this;
195
    }
196
197 23
    public function setPattern(string $pattern): self
198
    {
199 23
        $this->pattern = $pattern;
200 23
        return $this;
201
    }
202
203 17
    public function setName(?string $name): self
204
    {
205 17
        $this->name = $name;
206 17
        return $this;
207
    }
208
209 1
    public function setOverride(bool $override): self
210
    {
211 1
        $this->override = $override;
212 1
        return $this;
213
    }
214
215 1
    public function setDisabledMiddlewares(array $disabledMiddlewares): self
216
    {
217 1
        $this->disabledMiddlewares = $disabledMiddlewares;
218 1
        $this->enabledMiddlewaresCache = null;
219 1
        return $this;
220
    }
221
222 8
    public function __toString(): string
223
    {
224 8
        $result = $this->name === null
225 2
            ? ''
226 6
            : '[' . $this->name . '] ';
227
228 8
        if ($this->methods !== []) {
229 8
            $result .= implode(',', $this->methods) . ' ';
230
        }
231
232 8
        if (!empty($this->hosts)) {
233 4
            $quoted = array_map(static fn ($host) => preg_quote($host, '/'), $this->hosts);
234
235 4
            if (!preg_match('/' . implode('|', $quoted) . '/', $this->pattern)) {
236 4
                $result .= implode('|', $this->hosts);
237
            }
238
        }
239
240 8
        $result .= $this->pattern;
241
242 8
        return $result;
243
    }
244
245 1
    public function __debugInfo()
246
    {
247 1
        return [
248 1
            'name' => $this->name,
249 1
            'methods' => $this->methods,
250 1
            'pattern' => $this->pattern,
251 1
            'action' => $this->action,
252 1
            'hosts' => $this->hosts,
253 1
            'defaults' => $this->defaults,
254 1
            'override' => $this->override,
255 1
            'middlewares' => $this->middlewares,
256 1
            'disabledMiddlewares' => $this->disabledMiddlewares,
257 1
            'enabledMiddlewares' => $this->getEnabledMiddlewares(),
258 1
        ];
259
    }
260
261
    /**
262
     * @psalm-assert array<array-key,string> $items
263
     */
264 92
    private function assertListOfStrings(array $items, string $argument): void
265
    {
266 92
        foreach ($items as $item) {
267 92
            if (!is_string($item)) {
268 1
                throw new \InvalidArgumentException('Invalid $' . $argument . ' provided, list of string expected.');
269
            }
270
        }
271
    }
272
273
    /**
274
     * @psalm-assert list<array|callable|string> $middlewares
275
     */
276 92
    private function assertMiddlewares(array $middlewares): void
277
    {
278
        /** @var mixed $middleware */
279 92
        foreach ($middlewares as $middleware) {
280 34
            if (is_string($middleware)) {
281 13
                continue;
282
            }
283
284 21
            if (is_callable($middleware) || is_array($middleware)) {
285 21
                continue;
286
            }
287
288 1
            throw new \InvalidArgumentException(
289 1
                'Invalid $middlewares provided, list of string or array or callable expected.'
290 1
            );
291
        }
292
    }
293
}
294