Passed
Pull Request — master (#134)
by Rustam
07:47
created

Group::withAutoOptions()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7.0099

Importance

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