Passed
Pull Request — master (#135)
by Rustam
02:12
created

Route   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 326
Duplicated Lines 0 %

Test Coverage

Coverage 84.03%

Importance

Changes 15
Bugs 4 Features 0
Metric Value
eloc 97
c 15
b 4
f 0
dl 0
loc 326
ccs 100
cts 119
cp 0.8403
rs 9.0399
wmc 42

32 Methods

Rating   Name   Duplication   Size   Complexity  
A injectDispatcher() 0 3 1
A __construct() 0 3 1
A put() 0 3 1
A patch() 0 3 1
A name() 0 5 1
A getDispatcherWithMiddlewares() 0 13 4
A defaults() 0 5 1
A override() 0 5 1
A head() 0 3 1
A methods() 0 10 1
A action() 0 6 1
A pattern() 0 5 1
A delete() 0 3 1
A get() 0 3 1
A disableMiddleware() 0 5 1
A withDispatcher() 0 5 1
A post() 0 3 1
A options() 0 3 1
A hasDispatcher() 0 3 1
A middleware() 0 8 2
A host() 0 5 1
A prependMiddleware() 0 8 2
A getDefaults() 0 3 1
A isOverride() 0 3 1
A preFlight() 0 7 2
A getName() 0 3 1
A getMethods() 0 3 1
A getPattern() 0 3 1
A __toString() 0 17 5
A hasMiddlewares() 0 3 1
A getHost() 0 3 1
A __debugInfo() 0 13 1

How to fix   Complexity   

Complex Class

Complex classes like Route often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Route, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use RuntimeException;
8
use Yiisoft\Http\Method;
9
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
10
11
/**
12
 * Route defines a mapping from URL to callback / name and vice versa.
13
 */
14
final class Route implements RouteInterface, RouteParametersInterface
15
{
16
    private ?string $name = null;
17
    /** @var string[] */
18
    private array $methods;
19
    private string $pattern;
20
    private ?string $host = null;
21
    private bool $override = false;
22
    private ?MiddlewareDispatcher $dispatcher;
23
    private bool $actionAdded = false;
24
    private array $middlewareDefinitions = [];
25
    private array $disabledMiddlewareDefinitions = [];
26
    private array $defaults = [];
27
28 47
    private function __construct(?MiddlewareDispatcher $dispatcher = null)
29
    {
30 47
        $this->dispatcher = $dispatcher;
31 47
    }
32
33 6
    public function injectDispatcher(MiddlewareDispatcher $dispatcher): void
34
    {
35 6
        $this->dispatcher = $dispatcher;
36 6
    }
37
38
    /**
39
     * @return self
40
     */
41 5
    public function withDispatcher(MiddlewareDispatcher $dispatcher): RouteInterface
42
    {
43 5
        $route = clone $this;
44 5
        $route->dispatcher = $dispatcher;
45 5
        return $route;
46
    }
47
48 11
    public function getDispatcherWithMiddlewares(): MiddlewareDispatcher
49
    {
50 11
        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

50
        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...
51
            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...
52
        }
53
54 11
        foreach ($this->middlewareDefinitions as $index => $definition) {
55 11
            if (in_array($definition, $this->disabledMiddlewareDefinitions, true)) {
56
                unset($this->middlewareDefinitions[$index]);
57
            }
58
        }
59
60 11
        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...
61
    }
62
63 22
    public function hasDispatcher(): bool
64
    {
65 22
        return $this->dispatcher !== null;
66
    }
67
68
    /**
69
     * @param string $pattern
70
     * @param MiddlewareDispatcher|null $dispatcher
71
     *
72
     * @return RouteInterface
73
     */
74 37
    public static function get(string $pattern, ?MiddlewareDispatcher $dispatcher = null): RouteInterface
75
    {
76 37
        return self::methods([Method::GET], $pattern, $dispatcher);
77
    }
78
79
    /**
80
     * @param string $pattern
81
     * @param MiddlewareDispatcher|null $dispatcher
82
     *
83
     * @return RouteInterface
84
     */
85 4
    public static function post(string $pattern, ?MiddlewareDispatcher $dispatcher = null): RouteInterface
86
    {
87 4
        return self::methods([Method::POST], $pattern, $dispatcher);
88
    }
89
90
    /**
91
     * @param string $pattern
92
     * @param MiddlewareDispatcher|null $dispatcher
93
     *
94
     * @return RouteInterface
95
     */
96 1
    public static function put(string $pattern, ?MiddlewareDispatcher $dispatcher = null): RouteInterface
97
    {
98 1
        return self::methods([Method::PUT], $pattern, $dispatcher);
99
    }
100
101
    /**
102
     * @param string $pattern
103
     * @param MiddlewareDispatcher|null $dispatcher
104
     *
105
     * @return RouteInterface
106
     */
107 1
    public static function delete(string $pattern, ?MiddlewareDispatcher $dispatcher = null): RouteInterface
108
    {
109 1
        return self::methods([Method::DELETE], $pattern, $dispatcher);
110
    }
111
112
    /**
113
     * @param string $pattern
114
     * @param MiddlewareDispatcher|null $dispatcher
115
     *
116
     * @return RouteInterface
117
     */
118 1
    public static function patch(string $pattern, ?MiddlewareDispatcher $dispatcher = null): RouteInterface
119
    {
120 1
        return self::methods([Method::PATCH], $pattern, $dispatcher);
121
    }
122
123
    /**
124
     * @param string $pattern
125
     * @param MiddlewareDispatcher|null $dispatcher
126
     *
127
     * @return RouteInterface
128
     */
129 1
    public static function head(string $pattern, ?MiddlewareDispatcher $dispatcher = null): RouteInterface
130
    {
131 1
        return self::methods([Method::HEAD], $pattern, $dispatcher);
132
    }
133
134
    /**
135
     * @param string $pattern
136
     * @param MiddlewareDispatcher|null $dispatcher
137
     *
138
     * @return RouteInterface
139
     */
140 1
    public static function options(string $pattern, ?MiddlewareDispatcher $dispatcher = null): RouteInterface
141
    {
142 1
        return self::methods([Method::OPTIONS], $pattern, $dispatcher);
143
    }
144
145
    /**
146
     * @param array $methods
147
     * @param string $pattern
148
     * @param MiddlewareDispatcher|null $dispatcher
149
     *
150
     * @return RouteInterface
151
     */
152 47
    public static function methods(
153
        array $methods,
154
        string $pattern,
155
        ?MiddlewareDispatcher $dispatcher = null
156
    ): RouteInterface {
157 47
        $route = new self($dispatcher);
158 47
        $route->methods = $methods;
159 47
        $route->pattern = $pattern;
160
161 47
        return $route;
162
    }
163
164
    /**
165
     * @return self
166
     */
167 20
    public function name(string $name): RouteInterface
168
    {
169 20
        $route = clone $this;
170 20
        $route->name = $name;
171 20
        return $route;
172
    }
173
174
    /**
175
     * @return self
176
     */
177 15
    public function pattern(string $pattern): RouteInterface
178
    {
179 15
        $new = clone $this;
180 15
        $new->pattern = $pattern;
181 15
        return $new;
182
    }
183
184
    /**
185
     * @return self
186
     */
187 3
    public function host(string $host): RouteInterface
188
    {
189 3
        $route = clone $this;
190 3
        $route->host = rtrim($host, '/');
191 3
        return $route;
192
    }
193
194
    /**
195
     * @return self
196
     */
197 2
    public function override(): RouteInterface
198
    {
199 2
        $route = clone $this;
200 2
        $route->override = true;
201 2
        return $route;
202
    }
203
204
    /**
205
     * @return self
206
     */
207 1
    public function defaults(array $defaults): RouteInterface
208
    {
209 1
        $route = clone $this;
210 1
        $route->defaults = $defaults;
211 1
        return $route;
212
    }
213
214
    /**
215
     * @return self
216
     */
217 6
    public function middleware($middlewareDefinition): RouteInterface
218
    {
219 6
        if ($this->actionAdded) {
220
            throw new RuntimeException('middleware() can not be used after action().');
221
        }
222 6
        $route = clone $this;
223 6
        $route->middlewareDefinitions[] = $middlewareDefinition;
224 6
        return $route;
225
    }
226
227
    /**
228
     * @return self
229
     */
230 6
    public function prependMiddleware($middlewareDefinition): RouteInterface
231
    {
232 6
        if (!$this->actionAdded) {
233
            throw new RuntimeException('prependMiddleware() can not be used before action().');
234
        }
235 6
        $route = clone $this;
236 6
        array_unshift($route->middlewareDefinitions, $middlewareDefinition);
237 6
        return $route;
238
    }
239
240
    /**
241
     * @return self
242
     */
243 8
    public function action($middlewareDefinition): RouteInterface
244
    {
245 8
        $route = clone $this;
246 8
        $route->middlewareDefinitions[] = $middlewareDefinition;
247 8
        $route->actionAdded = true;
248 8
        return $route;
249
    }
250
251
    /**
252
     * @return self
253
     */
254
    public function disableMiddleware($middlewareDefinition): RouteInterface
255
    {
256
        $route = clone $this;
257
        $route->disabledMiddlewareDefinitions[] = $middlewareDefinition;
258
        return $route;
259
    }
260
261
    /**
262
     * @return self
263
     */
264 2
    public function preFlight(): RouteInterface
265
    {
266 2
        $route = clone $this;
267 2
        if (!in_array(Method::OPTIONS, $this->methods, true)) {
268 2
            $route->methods[] = Method::OPTIONS;
269
        }
270 2
        return $route;
271
    }
272
273 3
    public function __toString(): string
274
    {
275 3
        $result = '';
276
277 3
        if ($this->name !== null) {
278 2
            $result .= '[' . $this->name . '] ';
279
        }
280
281 3
        if ($this->methods !== []) {
282 3
            $result .= implode(',', $this->methods) . ' ';
283
        }
284 3
        if ($this->host !== null && strrpos($this->pattern, $this->host) === false) {
285 1
            $result .= $this->host;
286
        }
287 3
        $result .= $this->pattern;
288
289 3
        return $result;
290
    }
291
292 18
    public function getName(): string
293
    {
294 18
        return $this->name ?? (implode(', ', $this->methods) . ' ' . $this->host . $this->pattern);
295
    }
296
297 23
    public function getMethods(): array
298
    {
299 23
        return $this->methods;
300
    }
301
302 15
    public function getPattern(): string
303
    {
304 15
        return $this->pattern;
305
    }
306
307 2
    public function getHost(): ?string
308
    {
309 2
        return $this->host;
310
    }
311
312 4
    public function isOverride(): bool
313
    {
314 4
        return $this->override;
315
    }
316
317 1
    public function getDefaults(): array
318
    {
319 1
        return $this->defaults;
320
    }
321
322 14
    public function hasMiddlewares(): bool
323
    {
324 14
        return $this->middlewareDefinitions !== [];
325
    }
326
327
    public function __debugInfo()
328
    {
329
        return [
330
            'name' => $this->name,
331
            'methods' => $this->methods,
332
            'pattern' => $this->pattern,
333
            'host' => $this->host,
334
            'defaults' => $this->defaults,
335
            'override' => $this->override,
336
            'actionAdded' => $this->actionAdded,
337
            'middlewareDefinitions' => $this->middlewareDefinitions,
338
            'disabledMiddlewareDefinitions' => $this->disabledMiddlewareDefinitions,
339
            'middlewareDispatcher' => $this->dispatcher,
340
        ];
341
    }
342
}
343