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

Group::getItems()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
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