• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

willy68 / pg-router / 16205018743

10 Jul 2025 08:08PM UTC coverage: 94.928% (-0.05%) from 94.978%
16205018743

push

github

willy68
First commit

3 of 3 new or added lines in 1 file covered. (100.0%)

17 existing lines in 4 files now uncovered.

917 of 966 relevant lines covered (94.93%)

8.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.1
/src/Route.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Pg\Router;
6

7
use Pg\Router\Exception\ImmutableProperty;
8
use Pg\Router\Exception\InvalidArgumentException;
9
use Pg\Router\Middlewares\MiddlewareAwareStackTrait;
10

11
use function array_map;
12
use function implode;
13
use function in_array;
14
use function is_array;
15
use function is_string;
16
use function strcmp;
17
use function strlen;
18
use function strtolower;
19
use function strtoupper;
20
use function substr;
21

22
class Route
23
{
24
    use MiddlewareAwareStackTrait;
25

26
    public const HTTP_METHOD_ANY = null;
27
    public const HTTP_METHOD_SEPARATOR = ':';
28
    public const HTTP_SCHEME_ANY = null;
29

30
    protected string $path;
31
    protected ?array $method;
32
    protected ?string $host = null;
33
    protected ?int $port = null;
34
    protected ?array $schemes = null;
35
    protected $callback;
36
    protected ?RouteGroup $group = null;
37
    protected ?string $name = null;
38
    protected ?array $methods = null;
39
    /** @var array  Default tokens ["tokenName" => "regex"]*/
40
    protected array $tokens = [];
41

42

43
    public function __construct(
80✔
44
        string $path,
45
        callable|array|string $callback,
46
        ?string $name = null,
47
        ?array $methods = self::HTTP_METHOD_ANY
48
    ) {
49
        $methods = is_string($methods) ? [$methods] : $methods;
80✔
50

51
        // Place to validate http methods
52
        $this->methods = is_array($methods) ? $this->validateHttpMethods($methods) : self::HTTP_METHOD_ANY;
80✔
53

54
        if ($name === null || $name === '') {
79✔
55
            $name = $this->methods === self::HTTP_METHOD_ANY
8✔
56
                ? $path
6✔
57
                : $path . '^' . implode(self::HTTP_METHOD_SEPARATOR, $this->methods);
2✔
58
        }
59

60
        $this->name = $name;
79✔
61
        $this->callback = $callback;
79✔
62
        $this->path = $path;
79✔
63
    }
64

65
    public function getCallback(): callable|array|string
1✔
66
    {
67
        return $this->callback;
1✔
68
    }
69

70
    /**
71
     * Get the parent group
72
     */
73
    public function getParentGroup(): ?RouteGroup
1✔
74
    {
75
        return $this->group;
1✔
76
    }
77

78
    /**
79
     * Set the parent group
80
     *
81
     * @param RouteGroup $group
82
     * @return Route
83
     */
84
    public function setParentGroup(RouteGroup $group): self
4✔
85
    {
86
        $prefix = $group->getPrefix();
4✔
87
        $path = $this->getPath();
4✔
88

89
        if (strcmp($prefix, substr($path, 0, strlen($prefix))) === 0) {
4✔
90
            $this->group = $group;
4✔
91
        }
92

93
        return $this;
4✔
94
    }
95

96
    public function getPath(): string
52✔
97
    {
98
        return $this->path;
52✔
99
    }
100

101
    public function getName(): string
54✔
102
    {
103
        return $this->name;
54✔
104
    }
105

106
    /**
107
     * Set the route name if null.
108
     *
109
     * @param non-empty-string $name
110
     * @return Route
111
     */
112
    public function setName(string $name): self
1✔
113
    {
114
        if (null !== $this->name) {
1✔
115
            $message = static::class . ' ::$name is immutable once set';
1✔
116
            throw new ImmutableProperty($message);
1✔
117
        }
UNCOV
118
        $this->name = $name;
×
UNCOV
119
        return $this;
×
120
    }
121

122
    public function getAllowedMethods(): ?array
32✔
123
    {
124
        return $this->methods;
32✔
125
    }
126

127
    /**
128
     * Indicate whether the route allows the specified method.
129
     *
130
     * @param string $method HTTP method to test.
131
     */
132
    public function allowsMethod(string $method): bool
1✔
133
    {
134
        $method = strtoupper($method);
1✔
135
        return $this->allowsAnyMethod() || in_array($method, $this->methods ?? [], true);
1✔
136
    }
137

138
    /**
139
     * Indicates whether the route allows any HTTP method.
140
     */
141
    public function allowsAnyMethod(): bool
11✔
142
    {
143
        return $this->methods === self::HTTP_METHOD_ANY;
11✔
144
    }
145

146
    public function getHost(): ?string
2✔
147
    {
148
        return $this->host;
2✔
149
    }
150

151
    public function setHost(string $host): self
1✔
152
    {
153
        $this->host = $host;
1✔
154
        return $this;
1✔
155
    }
156

157
    public function getPort(): ?int
2✔
158
    {
159
        return $this->port;
2✔
160
    }
161

162
    public function setPort(int $port): self
1✔
163
    {
164
        $this->port = $port;
1✔
165
        return $this;
1✔
166
    }
167

168
    /**
169
     * Get all schemes array available for this route
170
     *
171
     * @return null|string[] Returns HTTP_SCHEME_ANY or string of allowed schemes.
172
     */
173
    public function getSchemes(): ?array
2✔
174
    {
175
        return $this->schemes;
2✔
176
    }
177

178
    /**
179
     * Set schemes available for this route
180
     *
181
     * @param array|null $schemes
182
     * @return Route
183
     */
184
    public function setSchemes(?array $schemes = null): self
2✔
185
    {
186
        $schemes = is_array($schemes) ? array_map('strtolower', $schemes) : $schemes;
2✔
187
        $this->schemes = $schemes;
2✔
188
        return $this;
2✔
189
    }
190

191
    /**
192
     * Check if the route allows the specified scheme.
193
     *
194
     * @param string $scheme
195
     * @return bool
196
     */
197
    public function allowsScheme(string $scheme): bool
1✔
198
    {
199
        $schemes = strtolower($scheme);
1✔
200
        return $this->allowsAnyScheme() || in_array($schemes, $this->schemes, true);
1✔
201
    }
202

203
    /**
204
     * Checks if the route allows any scheme.
205
     */
206
    public function allowsAnyScheme(): bool
2✔
207
    {
208
        return $this->schemes === self::HTTP_SCHEME_ANY;
2✔
209
    }
210

211
    /**
212
     * Add new tokens, but preserve existing tokens
213
     * Through this method you can set tokens in an array ["id" => "[0-9]+", "slug" => "[a-zA-Z-]+[a-zA-Z0-9_-]+"]
214
     * @param array $tokens
215
     * @return $this
216
     */
217
    public function setTokens(array $tokens): self
3✔
218
    {
219
        $this->tokens = $this->tokens + $tokens;
3✔
220
        return $this;
3✔
221
    }
222

223
    /**
224
     * Override existing tokens and/or add new
225
     * Through this method you can set tokens in an array ["id" => "[0-9]+", "slug" => "[a-zA-Z0-9_-]+"]
226
     * @param array $tokens
227
     * @return $this
228
     */
229
    public function updateTokens(array $tokens): self
1✔
230
    {
231
        $this->tokens = $tokens + $this->tokens;
1✔
232
        return $this;
1✔
233
    }
234

235
    /**
236
     * Get tokens
237
     *
238
     * @return array
239
     */
240
    public function getTokens(): array
27✔
241
    {
242
        return $this->tokens;
27✔
243
    }
244

245
    protected function validateHttpMethods(array $methods): array
39✔
246
    {
247
        if (empty($methods)) {
39✔
248
            throw new InvalidArgumentException('Http methods array is empty');
1✔
249
        }
250

251
        // Define allowed HTTP methods
252
        $validMethods = [
38✔
253
            'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD', 'CONNECT', 'TRACE'
38✔
254
        ];
38✔
255

256
        // Normalize and validate each method
257
        $normalized = array_map('strtoupper', $methods);
38✔
258

259
        foreach ($normalized as $method) {
38✔
260
            if (!in_array($method, $validMethods, true)) {
38✔
UNCOV
261
                throw new InvalidArgumentException(sprintf('Invalid HTTP method: %s', $method));
×
262
            }
263
        }
264

265
        return $normalized;
38✔
266
    }
267
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc