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

Group::withAutoOptions()   B

Complexity

Conditions 10
Paths 9

Size

Total Lines 43
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 10.0363

Importance

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