Passed
Pull Request — master (#222)
by Sergei
03:30
created

Group::hosts()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 6
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 13
ccs 7
cts 7
cp 1
crap 4
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
10
use function in_array;
11
12
final class Group
13
{
14
    /**
15
     * @var Group[]|Route[]
16
     */
17
    private array $routes = [];
18
19
    /**
20
     * @var array[]|callable[]|string[]
21
     */
22
    private array $middlewares = [];
23
24
    /**
25
     * @var string[]
26
     */
27
    private array $hosts = [];
28
    private ?string $namePrefix = null;
29
    private bool $routesAdded = false;
30
    private bool $middlewareAdded = false;
31
    private array $disabledMiddlewares = [];
32
33
    /**
34
     * @var array|callable|string|null Middleware definition for CORS requests.
35
     */
36
    private $corsMiddleware = null;
37
38 38
    private function __construct(
39
        private ?string $prefix = null
40
    ) {
41 38
    }
42
43
    /**
44
     * Create a new group instance.
45
     *
46
     * @param string|null $prefix URL prefix to prepend to all routes of the group.
47
     */
48 38
    public static function create(?string $prefix = null): self
49
    {
50 38
        return new self($prefix);
51
    }
52
53 29
    public function routes(self|Route ...$routes): self
54
    {
55 29
        if ($this->middlewareAdded) {
56 1
            throw new RuntimeException('routes() can not be used after prependMiddleware().');
57
        }
58
59 28
        $new = clone $this;
60 28
        $new->routes = $routes;
61 28
        $new->routesAdded = true;
62
63 28
        return $new;
64
    }
65
66
    /**
67
     * Adds a middleware definition that handles CORS requests.
68
     * If set, routes for {@see Method::OPTIONS} request will be added automatically.
69
     *
70
     * @param array|callable|string|null $middlewareDefinition Middleware definition for CORS requests.
71
     */
72 8
    public function withCors(array|callable|string|null $middlewareDefinition): self
73
    {
74 8
        $group = clone $this;
75 8
        $group->corsMiddleware = $middlewareDefinition;
76
77 8
        return $group;
78
    }
79
80
    /**
81
     * Appends a handler middleware definition that should be invoked for a matched route.
82
     * First added handler will be executed first.
83
     */
84 12
    public function middleware(array|callable|string ...$definition): self
85
    {
86 12
        if ($this->routesAdded) {
87 1
            throw new RuntimeException('middleware() can not be used after routes().');
88
        }
89
90 11
        $new = clone $this;
91 11
        array_push(
92 11
            $new->middlewares,
93 11
            ...array_values($definition)
94 11
        );
95
96 11
        return $new;
97
    }
98
99
    /**
100
     * Prepends a handler middleware definition that should be invoked for a matched route.
101
     * First added handler will be executed last.
102
     */
103 27
    public function prependMiddleware(array|callable|string ...$definition): self
104
    {
105 27
        $new = clone $this;
106 27
        array_unshift(
107 27
            $new->middlewares,
108 27
            ...array_values($definition)
109 27
        );
110 27
        $new->middlewareAdded = true;
111 27
        return $new;
112
    }
113
114 4
    public function namePrefix(string $namePrefix): self
115
    {
116 4
        $new = clone $this;
117 4
        $new->namePrefix = $namePrefix;
118 4
        return $new;
119
    }
120
121 2
    public function host(string $host): self
122
    {
123 2
        return $this->hosts($host);
124
    }
125
126 5
    public function hosts(string ...$hosts): self
127
    {
128 5
        $new = clone $this;
129
130 5
        foreach ($hosts as $host) {
131 4
            $host = rtrim($host, '/');
132
133 4
            if ($host !== '' && !in_array($host, $new->hosts, true)) {
134 4
                $new->hosts[] = $host;
135
            }
136
        }
137
138 5
        return $new;
139
    }
140
141
    /**
142
     * Excludes middleware from being invoked when action is handled.
143
     * It is useful to avoid invoking one of the parent group middleware for
144
     * a certain route.
145
     */
146 4
    public function disableMiddleware(mixed ...$definition): self
147
    {
148 4
        $new = clone $this;
149 4
        array_push(
150 4
            $new->disabledMiddlewares,
151 4
            ...array_values($definition),
152 4
        );
153 4
        return $new;
154
    }
155
156
    /**
157
     * @psalm-template T as string
158
     *
159
     * @psalm-param T $key
160
     *
161
     * @psalm-return (
162
     *   T is ('prefix'|'namePrefix'|'host') ? string|null :
163
     *   (T is 'routes' ? Group[]|Route[] :
164
     *     (T is 'hosts' ? array<array-key, string> :
165
     *       (T is ('hasCorsMiddleware') ? bool :
166
     *         (T is 'enabledMiddlewares' ? list<array|callable|string> :
167
     *           (T is 'corsMiddleware' ? array|callable|string|null : mixed)
168
     *         )
169
     *       )
170
     *     )
171
     *   )
172
     * )
173
     */
174 32
    public function getData(string $key): mixed
175
    {
176 32
        return match ($key) {
177 32
            'prefix' => $this->prefix,
178 32
            'namePrefix' => $this->namePrefix,
179 32
            'host' => $this->hosts[0] ?? null,
180 32
            'hosts' => $this->hosts,
181 32
            'corsMiddleware' => $this->corsMiddleware,
182 32
            'routes' => $this->routes,
183 32
            'hasCorsMiddleware' => $this->corsMiddleware !== null,
184 32
            'enabledMiddlewares' => $this->getEnabledMiddlewares(),
185 32
            default => throw new InvalidArgumentException('Unknown data key: ' . $key),
186 32
        };
187
    }
188
189 22
    private function getEnabledMiddlewares(): array
190
    {
191 22
        foreach ($this->middlewares as $index => $definition) {
192 12
            if (in_array($definition, $this->disabledMiddlewares, true)) {
193 3
                unset($this->middlewares[$index]);
194
            }
195
        }
196
197 22
        return array_values($this->middlewares);
198
    }
199
}
200