Passed
Pull Request — master (#134)
by Rustam
02:58
created

Group::withAutoOptions()   B

Complexity

Conditions 10
Paths 9

Size

Total Lines 45
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 10.1105

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 29
c 1
b 0
f 0
nc 9
nop 1
dl 0
loc 45
ccs 26
cts 29
cp 0.8966
crap 10.1105
rs 7.6666

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
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\RequestHandlerInterface;
10
use RuntimeException;
11
use Yiisoft\Http\Method;
12
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
13
14
use function get_class;
15
use function in_array;
16
use function is_object;
17
18
final class Group implements GroupInterface
19
{
20
    /**
21
     * @var Group[]|Route[]
22
     */
23
    private array $items = [];
24
    private ?string $prefix;
25
    private array $middlewareDefinitions = [];
26
    private ?string $host = null;
27
    private ?string $namePrefix = null;
28
    private bool $routesAdded = false;
29
    private bool $middlewareAdded = false;
30
    private array $disabledMiddlewareDefinitions = [];
31
    private ?MiddlewareDispatcher $dispatcher;
32
33 24
    private function __construct(?string $prefix = null, MiddlewareDispatcher $dispatcher = null)
34
    {
35 24
        $this->dispatcher = $dispatcher;
36 24
        $this->prefix = $prefix;
37 24
    }
38
39
    /**
40
     * Create a new group instance.
41
     *
42
     * @param string|null $prefix URL prefix to prepend to all routes of the group.
43
     * @param MiddlewareDispatcher|null $dispatcher Middleware dispatcher to use for the group.
44
     *
45
     * @return GroupInterface
46
     */
47 24
    public static function create(
48
        ?string $prefix = null,
49
        MiddlewareDispatcher $dispatcher = null
50
    ): GroupInterface {
51 24
        return new self($prefix, $dispatcher);
52
    }
53
54 21
    public function routes(...$routes): GroupInterface
55
    {
56 21
        if ($this->middlewareAdded) {
57 1
            throw new RuntimeException('routes() can not be used after prependMiddleware().');
58
        }
59 20
        $new = clone $this;
60 20
        foreach ($routes as $route) {
61 20
            if ($route instanceof Route || $route instanceof self) {
62 19
                if (!$route->hasDispatcher() && $new->hasDispatcher()) {
63 5
                    $route = $route->withDispatcher($new->dispatcher);
64
                }
65 19
                $new->items[] = $route;
66
            } else {
67 1
                $type = is_object($route) ? get_class($route) : gettype($route);
68 1
                throw new InvalidArgumentException(
69 1
                    sprintf('Route should be either an instance of Route or Group, %s given.', $type)
70
                );
71
            }
72
        }
73
74 19
        $new->routesAdded = true;
75
76 19
        return $new;
77
    }
78
79 2
    public function withDispatcher(MiddlewareDispatcher $dispatcher): GroupInterface
80
    {
81 2
        $group = clone $this;
82 2
        $group->dispatcher = $dispatcher;
83 2
        foreach ($group->items as $index => $item) {
84 2
            if (!$item->hasDispatcher()) {
85 2
                $item = $item->withDispatcher($dispatcher);
86 2
                $group->items[$index] = $item;
87
            }
88
        }
89
90 2
        return $group;
91
    }
92
93 3
    public function withAutoOptions(...$middlewares): GroupInterface
94
    {
95 3
        if (!$this->routesAdded) {
96
            throw new RuntimeException('withAutoOptions() can not be used before routes().');
97
        }
98
99 3
        if (empty($middlewares)) {
100
            throw new InvalidArgumentException('At least one middleware must be specified.');
101
        }
102
103 3
        $group = clone $this;
104 3
        $pattern = null;
105 3
        $host = null;
106 3
        foreach ($group->items as $index => $item) {
107 3
            if ($item instanceof self) {
108 1
                $item = $item->withAutoOptions(...$middlewares);
109 1
                $group->items[$index] = $item;
110
            } else {
111
                // Avoid duplicates
112
                if (
113 3
                    ($pattern === $item->getPattern() && $host === $item->getHost())
114 3
                    || in_array(Method::OPTIONS, $item->getMethods(), true)
115
                ) {
116 3
                    continue;
117
                }
118 3
                $pattern = $item->getPattern();
119 3
                $host = $item->getHost();
120 3
                $route = Route::options($pattern);
121 3
                if ($host !== null) {
122 1
                    $route = $route->host($host);
123
                }
124 3
                foreach ($middlewares as $middleware) {
125 3
                    $route = $route->middleware($middleware);
126 3
                    $item = $item->prependMiddleware($middleware);
127
                }
128 3
                $group->items[$index] = $item;
129 3
                $group->items[] = $route->action(
130 3
                    static fn (ServerRequestInterface $request, RequestHandlerInterface $handler) => $handler->handle(
131
                        $request
132
                    )
133 3
                );
134
            }
135
        }
136
137 3
        return $group;
138
    }
139
140 19
    public function hasDispatcher(): bool
141
    {
142 19
        return $this->dispatcher !== null;
143
    }
144
145 7
    public function middleware($middlewareDefinition): GroupInterface
146
    {
147 7
        if ($this->routesAdded) {
148
            throw new RuntimeException('middleware() can not be used after routes().');
149
        }
150 7
        $new = clone $this;
151 7
        array_unshift($new->middlewareDefinitions, $middlewareDefinition);
152 7
        return $new;
153
    }
154
155 3
    public function prependMiddleware($middlewareDefinition): GroupInterface
156
    {
157 3
        $new = clone $this;
158 3
        $new->middlewareDefinitions[] = $middlewareDefinition;
159 3
        $new->middlewareAdded = true;
160 3
        return $new;
161
    }
162
163 3
    public function namePrefix(string $namePrefix): GroupInterface
164
    {
165 3
        $new = clone $this;
166 3
        $new->namePrefix = $namePrefix;
167 3
        return $new;
168
    }
169
170 2
    public function host(string $host): GroupInterface
171
    {
172 2
        $new = clone $this;
173 2
        $new->host = rtrim($host, '/');
174 2
        return $new;
175
    }
176
177
    public function disableMiddleware($middlewareDefinition): GroupInterface
178
    {
179
        $new = clone $this;
180
        $new->disabledMiddlewareDefinitions[] = $middlewareDefinition;
181
        return $new;
182
    }
183
184
    /**
185
     * @return Group[]|Route[]
186
     */
187 18
    public function getItems(): array
188
    {
189 18
        return $this->items;
190
    }
191
192 17
    public function getPrefix(): ?string
193
    {
194 17
        return $this->prefix;
195
    }
196
197 17
    public function getNamePrefix(): ?string
198
    {
199 17
        return $this->namePrefix;
200
    }
201
202 17
    public function getHost(): ?string
203
    {
204 17
        return $this->host;
205
    }
206
207 14
    public function getMiddlewareDefinitions(): array
208
    {
209 14
        foreach ($this->middlewareDefinitions as $index => $definition) {
210 8
            if (in_array($definition, $this->disabledMiddlewareDefinitions, true)) {
211
                unset($this->middlewareDefinitions[$index]);
212
            }
213
        }
214
215 14
        return $this->middlewareDefinitions;
216
    }
217
}
218