Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
100.00% |
94 / 94 |
|
96.43% |
81 / 84 |
|
66.67% |
50 / 75 |
|
94.12% |
32 / 34 |
CRAP | |
0.00% |
0 / 1 |
| Request | |
100.00% |
94 / 94 |
|
96.43% |
81 / 84 |
|
66.67% |
50 / 75 |
|
100.00% |
34 / 34 |
162.00 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| unwrap | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| params | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| param | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| form | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| field | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| cookies | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| cookie | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| serverParams | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| server | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| header | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| headerArray | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| headers | |
100.00% |
4 / 4 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| withHeader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| withAddedHeader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| withoutHeader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| hasHeader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| attributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| with | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| get | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| uri | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| origin | |
100.00% |
6 / 6 |
|
71.43% |
5 / 7 |
|
25.00% |
1 / 4 |
|
100.00% |
1 / 1 |
6.80 | |||
| target | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| method | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| isMethod | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| body | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| json | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| files | |
100.00% |
9 / 9 |
|
100.00% |
11 / 11 |
|
40.00% |
4 / 10 |
|
100.00% |
1 / 1 |
10.40 | |||
| file | |
100.00% |
17 / 17 |
|
100.00% |
13 / 13 |
|
57.14% |
4 / 7 |
|
100.00% |
1 / 1 |
8.83 | |||
| parsedBody | |
100.00% |
4 / 4 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| returnOrFail | |
100.00% |
5 / 5 |
|
100.00% |
7 / 7 |
|
66.67% |
4 / 6 |
|
100.00% |
1 / 1 |
4.59 | |||
| formatKeys | |
100.00% |
4 / 4 |
|
75.00% |
3 / 4 |
|
50.00% |
1 / 2 |
|
100.00% |
1 / 1 |
1.12 | |||
| validateKeys | |
100.00% |
8 / 8 |
|
100.00% |
10 / 10 |
|
37.50% |
6 / 16 |
|
100.00% |
1 / 1 |
11.10 | |||
| wrapping | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Celema\Core; |
| 6 | |
| 7 | use Celema\Core\Exception\OutOfBoundsException; |
| 8 | use Celema\Core\Exception\RuntimeException; |
| 9 | use Celema\Router\RequestWrapper; |
| 10 | use Override; |
| 11 | use Psr\Http\Message\ServerRequestInterface as PsrServerRequest; |
| 12 | use Psr\Http\Message\StreamInterface as PsrStream; |
| 13 | use Psr\Http\Message\UploadedFileInterface as PsrUploadedFile; |
| 14 | use Psr\Http\Message\UriInterface as PsrUri; |
| 15 | |
| 16 | /** |
| 17 | * A reading API over a PSR-7 server request. Like the request it wraps, it |
| 18 | * is immutable: the `with*()` methods return a new wrapper, so a change is |
| 19 | * never visible to other holders of the same wrapper. |
| 20 | * |
| 21 | * @api |
| 22 | */ |
| 23 | class Request implements RequestWrapper |
| 24 | { |
| 25 | public function __construct( |
| 26 | protected readonly PsrServerRequest $psrRequest, |
| 27 | ) {} |
| 28 | |
| 29 | #[Override] |
| 30 | public function unwrap(): PsrServerRequest |
| 31 | { |
| 32 | return $this->psrRequest; |
| 33 | } |
| 34 | |
| 35 | /** @return array<array-key, mixed> */ |
| 36 | public function params(): array |
| 37 | { |
| 38 | return $this->psrRequest->getQueryParams(); |
| 39 | } |
| 40 | |
| 41 | public function param(string $key, mixed $default = null): mixed |
| 42 | { |
| 43 | $params = $this->psrRequest->getQueryParams(); |
| 44 | $error = 'Query string variable not found'; |
| 45 | |
| 46 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 47 | } |
| 48 | |
| 49 | /** @return array<array-key, mixed>|null */ |
| 50 | public function form(): ?array |
| 51 | { |
| 52 | return $this->parsedBody(); |
| 53 | } |
| 54 | |
| 55 | public function field(string $key, mixed $default = null): mixed |
| 56 | { |
| 57 | $body = $this->parsedBody(); |
| 58 | $error = 'Form field not found'; |
| 59 | |
| 60 | return $this->returnOrFail($body, $key, $default, $error, func_num_args()); |
| 61 | } |
| 62 | |
| 63 | /** @return array<array-key, mixed> */ |
| 64 | public function cookies(): array |
| 65 | { |
| 66 | return $this->psrRequest->getCookieParams(); |
| 67 | } |
| 68 | |
| 69 | public function cookie(string $key, mixed $default = null): mixed |
| 70 | { |
| 71 | $params = $this->psrRequest->getCookieParams(); |
| 72 | $error = 'Cookie not found'; |
| 73 | |
| 74 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 75 | } |
| 76 | |
| 77 | /** @return array<array-key, mixed> */ |
| 78 | public function serverParams(): array |
| 79 | { |
| 80 | return $this->psrRequest->getServerParams(); |
| 81 | } |
| 82 | |
| 83 | public function server(string $key, mixed $default = null): mixed |
| 84 | { |
| 85 | $params = $this->psrRequest->getServerParams(); |
| 86 | $error = 'Server parameter not found'; |
| 87 | |
| 88 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 89 | } |
| 90 | |
| 91 | public function header(string $name): string |
| 92 | { |
| 93 | return $this->psrRequest->getHeaderLine($name); |
| 94 | } |
| 95 | |
| 96 | /** @return string[] */ |
| 97 | public function headerArray(string $header): array |
| 98 | { |
| 99 | return $this->psrRequest->getHeader($header); |
| 100 | } |
| 101 | |
| 102 | /** @return ($firstOnly is true ? array<array-key, string> : array<array-key, string[]>) */ |
| 103 | public function headers(bool $firstOnly = false): array |
| 104 | { |
| 105 | $headers = $this->psrRequest->getHeaders(); |
| 106 | |
| 107 | if ($firstOnly) { |
| 108 | return array_map(static fn(array $val): string => $val[0] ?? '', $headers); |
| 109 | } |
| 110 | |
| 111 | return $headers; |
| 112 | } |
| 113 | |
| 114 | public function withHeader(string $header, string $value): static |
| 115 | { |
| 116 | return $this->wrapping($this->psrRequest->withHeader($header, $value)); |
| 117 | } |
| 118 | |
| 119 | public function withAddedHeader(string $header, string $value): static |
| 120 | { |
| 121 | return $this->wrapping($this->psrRequest->withAddedHeader($header, $value)); |
| 122 | } |
| 123 | |
| 124 | public function withoutHeader(string $header): static |
| 125 | { |
| 126 | return $this->wrapping($this->psrRequest->withoutHeader($header)); |
| 127 | } |
| 128 | |
| 129 | public function hasHeader(string $header): bool |
| 130 | { |
| 131 | return $this->psrRequest->hasHeader($header); |
| 132 | } |
| 133 | |
| 134 | /** @return array<array-key, mixed> */ |
| 135 | public function attributes(): array |
| 136 | { |
| 137 | return $this->psrRequest->getAttributes(); |
| 138 | } |
| 139 | |
| 140 | /** A new wrapper whose request carries the attribute. */ |
| 141 | public function with(string $attribute, mixed $value): static |
| 142 | { |
| 143 | return $this->wrapping($this->psrRequest->withAttribute($attribute, $value)); |
| 144 | } |
| 145 | |
| 146 | public function get(string $key, mixed $default = null): mixed |
| 147 | { |
| 148 | $params = $this->psrRequest->getAttributes(); |
| 149 | $error = 'Request attribute not found'; |
| 150 | |
| 151 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 152 | } |
| 153 | |
| 154 | public function uri(): PsrUri |
| 155 | { |
| 156 | return $this->psrRequest->getUri(); |
| 157 | } |
| 158 | |
| 159 | public function origin(): string |
| 160 | { |
| 161 | $uri = $this->psrRequest->getUri(); |
| 162 | $scheme = $uri->getScheme(); |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 164 | $authority = $uri->getAuthority(); |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 166 | |
| 167 | return $origin; |
| 168 | } |
| 169 | |
| 170 | public function target(): string |
| 171 | { |
| 172 | return $this->psrRequest->getRequestTarget(); |
| 173 | } |
| 174 | |
| 175 | public function method(): string |
| 176 | { |
| 177 | return strtoupper($this->psrRequest->getMethod()); |
| 178 | } |
| 179 | |
| 180 | public function isMethod(string $method): bool |
| 181 | { |
| 182 | return strtoupper($method) === $this->method(); |
| 183 | } |
| 184 | |
| 185 | public function body(): PsrStream |
| 186 | { |
| 187 | return $this->psrRequest->getBody(); |
| 188 | } |
| 189 | |
| 190 | public function json( |
| 191 | int $flags = JSON_OBJECT_AS_ARRAY, |
| 192 | ): mixed { |
| 193 | $body = (string) $this->psrRequest->getBody(); |
| 194 | |
| 195 | return json_decode($body, true, flags: $flags); |
| 196 | } |
| 197 | |
| 198 | /** |
| 199 | * Returns the uploaded files at the given keys. A single file is |
| 200 | * wrapped in a list; nested keys keep their structure. |
| 201 | * |
| 202 | * @no-named-arguments |
| 203 | * |
| 204 | * @param list<string>|string ...$keys |
| 205 | * |
| 206 | * @return array<array-key, mixed> |
| 207 | * |
| 208 | * @throws OutOfBoundsException RuntimeException |
| 209 | */ |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 233 | return [$files]; |
| 234 | } |
| 235 | |
| 236 | assert(is_array($files), 'Uploaded files selection must resolve to an array'); |
| 237 | |
| 238 | return $files; |
| 239 | } |
| 240 | |
| 241 | /** |
| 242 | * @no-named-arguments |
| 243 | * |
| 244 | * @param list<non-empty-string>|string ...$keys |
| 245 | * |
| 246 | * @throws OutOfBoundsException RuntimeException |
| 247 | */ |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 253 | throw new RuntimeException('No file key given'); |
| 254 | } |
| 255 | |
| 256 | $files = $this->psrRequest->getUploadedFiles(); |
| 257 | $i = 0; |
| 258 | |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 261 | /** @var array<array-key, mixed>|PsrUploadedFile $files */ |
| 262 | $files = $files[$key]; |
| 263 | $i++; |
| 264 | |
| 265 | if ($files instanceof PsrUploadedFile) { |
| 266 | if ($i < count($keys)) { |
| 267 | throw new OutOfBoundsException( |
| 268 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 269 | ); |
| 270 | } |
| 271 | |
| 272 | return $files; |
| 273 | } |
| 274 | } else { |
| 275 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | throw new RuntimeException('Multiple files available at key ' . $this->formatKeys($keys)); |
| 280 | } |
| 281 | |
| 282 | /** @return array<array-key, mixed>|null */ |
| 283 | private function parsedBody(): ?array |
| 284 | { |
| 285 | $body = $this->psrRequest->getParsedBody(); |
| 286 | |
| 287 | if (is_object($body)) { |
| 288 | throw new RuntimeException('The parsed body is an object, not form data'); |
| 289 | } |
| 290 | |
| 291 | return $body; |
| 292 | } |
| 293 | |
| 294 | /** @param array<array-key, mixed>|null $array */ |
| 295 | private function returnOrFail( |
| 296 | ?array $array, |
| 297 | string $key, |
| 298 | mixed $default, |
| 299 | string $error, |
| 300 | int $numArgs, |
| 301 | ): mixed { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 303 | return $array[$key]; |
| 304 | } |
| 305 | |
| 306 | if ($numArgs > 1) { |
| 307 | return $default; |
| 308 | } |
| 309 | |
| 310 | throw new OutOfBoundsException("{$error}: '{$key}'"); |
| 311 | } |
| 312 | |
| 313 | /** @param non-empty-list<string> $keys */ |
| 314 | private function formatKeys(array $keys): string |
| 315 | { |
| 316 | return implode('', array_map( |
| 317 | static fn(string $key): string => "['" . $key . "']", |
| 318 | $keys, |
| 319 | )); |
| 320 | } |
| 321 | |
| 322 | /** |
| 323 | * @param list<list<string>|string> $keys |
| 324 | * |
| 325 | * @return list<string> |
| 326 | */ |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 345 | |
| 346 | /** A copy for the changed request; subclasses keep their own state. */ |
| 347 | private function wrapping(PsrServerRequest $request): static |
| 348 | { |
| 349 | return clone($this, ['psrRequest' => $request]); |
| 350 | } |
| 351 | } |
Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not
necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once.
Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 26 | protected readonly PsrServerRequest $psrRequest, |
| 27 | ) {} |
| 137 | return $this->psrRequest->getAttributes(); |
| 138 | } |
| 187 | return $this->psrRequest->getBody(); |
| 188 | } |
| 69 | public function cookie(string $key, mixed $default = null): mixed |
| 70 | { |
| 71 | $params = $this->psrRequest->getCookieParams(); |
| 72 | $error = 'Cookie not found'; |
| 73 | |
| 74 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 75 | } |
| 66 | return $this->psrRequest->getCookieParams(); |
| 67 | } |
| 55 | public function field(string $key, mixed $default = null): mixed |
| 56 | { |
| 57 | $body = $this->parsedBody(); |
| 58 | $error = 'Form field not found'; |
| 59 | |
| 60 | return $this->returnOrFail($body, $key, $default, $error, func_num_args()); |
| 61 | } |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 253 | throw new RuntimeException('No file key given'); |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 256 | $files = $this->psrRequest->getUploadedFiles(); |
| 257 | $i = 0; |
| 258 | |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 262 | $files = $files[$key]; |
| 263 | $i++; |
| 264 | |
| 265 | if ($files instanceof PsrUploadedFile) { |
| 266 | if ($i < count($keys)) { |
| 267 | throw new OutOfBoundsException( |
| 268 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 256 | $files = $this->psrRequest->getUploadedFiles(); |
| 257 | $i = 0; |
| 258 | |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 262 | $files = $files[$key]; |
| 263 | $i++; |
| 264 | |
| 265 | if ($files instanceof PsrUploadedFile) { |
| 266 | if ($i < count($keys)) { |
| 272 | return $files; |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 256 | $files = $this->psrRequest->getUploadedFiles(); |
| 257 | $i = 0; |
| 258 | |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 262 | $files = $files[$key]; |
| 263 | $i++; |
| 264 | |
| 265 | if ($files instanceof PsrUploadedFile) { |
| 260 | if (isset($files[$key])) { |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 261 | /** @var array<array-key, mixed>|PsrUploadedFile $files */ |
| 262 | $files = $files[$key]; |
| 263 | $i++; |
| 264 | |
| 265 | if ($files instanceof PsrUploadedFile) { |
| 266 | if ($i < count($keys)) { |
| 267 | throw new OutOfBoundsException( |
| 268 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 269 | ); |
| 270 | } |
| 271 | |
| 272 | return $files; |
| 273 | } |
| 274 | } else { |
| 275 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | throw new RuntimeException('Multiple files available at key ' . $this->formatKeys($keys)); |
| 280 | } |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 256 | $files = $this->psrRequest->getUploadedFiles(); |
| 257 | $i = 0; |
| 258 | |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 275 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 256 | $files = $this->psrRequest->getUploadedFiles(); |
| 257 | $i = 0; |
| 258 | |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 261 | /** @var array<array-key, mixed>|PsrUploadedFile $files */ |
| 262 | $files = $files[$key]; |
| 263 | $i++; |
| 264 | |
| 265 | if ($files instanceof PsrUploadedFile) { |
| 266 | if ($i < count($keys)) { |
| 267 | throw new OutOfBoundsException( |
| 268 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 269 | ); |
| 270 | } |
| 271 | |
| 272 | return $files; |
| 273 | } |
| 274 | } else { |
| 275 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | throw new RuntimeException('Multiple files available at key ' . $this->formatKeys($keys)); |
| 280 | } |
| 248 | public function file(array|string ...$keys): PsrUploadedFile |
| 249 | { |
| 250 | $keys = $this->validateKeys($keys); |
| 251 | |
| 252 | if (count($keys) === 0) { |
| 256 | $files = $this->psrRequest->getUploadedFiles(); |
| 257 | $i = 0; |
| 258 | |
| 259 | foreach ($keys as $key) { |
| 259 | foreach ($keys as $key) { |
| 260 | if (isset($files[$key])) { |
| 261 | /** @var array<array-key, mixed>|PsrUploadedFile $files */ |
| 262 | $files = $files[$key]; |
| 263 | $i++; |
| 264 | |
| 265 | if ($files instanceof PsrUploadedFile) { |
| 266 | if ($i < count($keys)) { |
| 267 | throw new OutOfBoundsException( |
| 268 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 269 | ); |
| 270 | } |
| 271 | |
| 272 | return $files; |
| 273 | } |
| 274 | } else { |
| 275 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | throw new RuntimeException('Multiple files available at key ' . $this->formatKeys($keys)); |
| 280 | } |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 233 | return [$files]; |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 236 | assert(is_array($files), 'Uploaded files selection must resolve to an array'); |
| 237 | |
| 238 | return $files; |
| 239 | } |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 233 | return [$files]; |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 236 | assert(is_array($files), 'Uploaded files selection must resolve to an array'); |
| 237 | |
| 238 | return $files; |
| 239 | } |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 233 | return [$files]; |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 236 | assert(is_array($files), 'Uploaded files selection must resolve to an array'); |
| 237 | |
| 238 | return $files; |
| 239 | } |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 233 | return [$files]; |
| 210 | public function files(array|string ...$keys): array |
| 211 | { |
| 212 | $files = $this->psrRequest->getUploadedFiles(); |
| 213 | $keys = $this->validateKeys($keys); |
| 214 | |
| 215 | // Walk into the uploaded files structure |
| 216 | foreach ($keys as $key) { |
| 216 | foreach ($keys as $key) { |
| 217 | if (is_array($files) && array_key_exists($key, $files)) { |
| 218 | /** |
| 219 | * @psalm-suppress MixedAssignment |
| 220 | * |
| 221 | * Psalm does not support recursive types like: |
| 222 | * T = array<string, string|T> |
| 223 | */ |
| 224 | $files = $files[$key]; |
| 225 | } else { |
| 226 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Check if it is a single file upload. |
| 231 | // A multifile upload would already produce an array |
| 232 | if ($files instanceof PsrUploadedFile) { |
| 236 | assert(is_array($files), 'Uploaded files selection must resolve to an array'); |
| 237 | |
| 238 | return $files; |
| 239 | } |
| 52 | return $this->parsedBody(); |
| 53 | } |
| 314 | private function formatKeys(array $keys): string |
| 315 | { |
| 316 | return implode('', array_map( |
| 316 | return implode('', array_map( |
| 317 | static fn(string $key): string => "['" . $key . "']", |
| 318 | $keys, |
| 319 | )); |
| 320 | } |
| 314 | private function formatKeys(array $keys): string |
| 315 | { |
| 316 | return implode('', array_map( |
| 316 | return implode('', array_map( |
| 317 | static fn(string $key): string => "['" . $key . "']", |
| 317 | static fn(string $key): string => "['" . $key . "']", |
| 318 | $keys, |
| 319 | )); |
| 320 | } |
| 146 | public function get(string $key, mixed $default = null): mixed |
| 147 | { |
| 148 | $params = $this->psrRequest->getAttributes(); |
| 149 | $error = 'Request attribute not found'; |
| 150 | |
| 151 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 152 | } |
| 129 | public function hasHeader(string $header): bool |
| 130 | { |
| 131 | return $this->psrRequest->hasHeader($header); |
| 132 | } |
| 91 | public function header(string $name): string |
| 92 | { |
| 93 | return $this->psrRequest->getHeaderLine($name); |
| 94 | } |
| 97 | public function headerArray(string $header): array |
| 98 | { |
| 99 | return $this->psrRequest->getHeader($header); |
| 100 | } |
| 103 | public function headers(bool $firstOnly = false): array |
| 104 | { |
| 105 | $headers = $this->psrRequest->getHeaders(); |
| 106 | |
| 107 | if ($firstOnly) { |
| 108 | return array_map(static fn(array $val): string => $val[0] ?? '', $headers); |
| 103 | public function headers(bool $firstOnly = false): array |
| 104 | { |
| 105 | $headers = $this->psrRequest->getHeaders(); |
| 106 | |
| 107 | if ($firstOnly) { |
| 111 | return $headers; |
| 112 | } |
| 180 | public function isMethod(string $method): bool |
| 181 | { |
| 182 | return strtoupper($method) === $this->method(); |
| 183 | } |
| 191 | int $flags = JSON_OBJECT_AS_ARRAY, |
| 192 | ): mixed { |
| 193 | $body = (string) $this->psrRequest->getBody(); |
| 194 | |
| 195 | return json_decode($body, true, flags: $flags); |
| 196 | } |
| 177 | return strtoupper($this->psrRequest->getMethod()); |
| 178 | } |
| 161 | $uri = $this->psrRequest->getUri(); |
| 162 | $scheme = $uri->getScheme(); |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 164 | $authority = $uri->getAuthority(); |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 166 | |
| 167 | return $origin; |
| 168 | } |
| 161 | $uri = $this->psrRequest->getUri(); |
| 162 | $scheme = $uri->getScheme(); |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 164 | $authority = $uri->getAuthority(); |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 166 | |
| 167 | return $origin; |
| 168 | } |
| 161 | $uri = $this->psrRequest->getUri(); |
| 162 | $scheme = $uri->getScheme(); |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 164 | $authority = $uri->getAuthority(); |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 166 | |
| 167 | return $origin; |
| 168 | } |
| 161 | $uri = $this->psrRequest->getUri(); |
| 162 | $scheme = $uri->getScheme(); |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 163 | $origin = $scheme !== '' ? $scheme . ':' : ''; |
| 164 | $authority = $uri->getAuthority(); |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 165 | $origin .= $authority !== '' ? '//' . $authority : ''; |
| 166 | |
| 167 | return $origin; |
| 168 | } |
| 41 | public function param(string $key, mixed $default = null): mixed |
| 42 | { |
| 43 | $params = $this->psrRequest->getQueryParams(); |
| 44 | $error = 'Query string variable not found'; |
| 45 | |
| 46 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 47 | } |
| 38 | return $this->psrRequest->getQueryParams(); |
| 39 | } |
| 285 | $body = $this->psrRequest->getParsedBody(); |
| 286 | |
| 287 | if (is_object($body)) { |
| 288 | throw new RuntimeException('The parsed body is an object, not form data'); |
| 285 | $body = $this->psrRequest->getParsedBody(); |
| 286 | |
| 287 | if (is_object($body)) { |
| 291 | return $body; |
| 292 | } |
| 296 | ?array $array, |
| 297 | string $key, |
| 298 | mixed $default, |
| 299 | string $error, |
| 300 | int $numArgs, |
| 301 | ): mixed { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 303 | return $array[$key]; |
| 296 | ?array $array, |
| 297 | string $key, |
| 298 | mixed $default, |
| 299 | string $error, |
| 300 | int $numArgs, |
| 301 | ): mixed { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 306 | if ($numArgs > 1) { |
| 307 | return $default; |
| 296 | ?array $array, |
| 297 | string $key, |
| 298 | mixed $default, |
| 299 | string $error, |
| 300 | int $numArgs, |
| 301 | ): mixed { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 306 | if ($numArgs > 1) { |
| 310 | throw new OutOfBoundsException("{$error}: '{$key}'"); |
| 311 | } |
| 296 | ?array $array, |
| 297 | string $key, |
| 298 | mixed $default, |
| 299 | string $error, |
| 300 | int $numArgs, |
| 301 | ): mixed { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 303 | return $array[$key]; |
| 296 | ?array $array, |
| 297 | string $key, |
| 298 | mixed $default, |
| 299 | string $error, |
| 300 | int $numArgs, |
| 301 | ): mixed { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 306 | if ($numArgs > 1) { |
| 307 | return $default; |
| 296 | ?array $array, |
| 297 | string $key, |
| 298 | mixed $default, |
| 299 | string $error, |
| 300 | int $numArgs, |
| 301 | ): mixed { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 302 | if ($array !== null && array_key_exists($key, $array)) { |
| 306 | if ($numArgs > 1) { |
| 310 | throw new OutOfBoundsException("{$error}: '{$key}'"); |
| 311 | } |
| 83 | public function server(string $key, mixed $default = null): mixed |
| 84 | { |
| 85 | $params = $this->psrRequest->getServerParams(); |
| 86 | $error = 'Server parameter not found'; |
| 87 | |
| 88 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 89 | } |
| 80 | return $this->psrRequest->getServerParams(); |
| 81 | } |
| 172 | return $this->psrRequest->getRequestTarget(); |
| 173 | } |
| 32 | return $this->psrRequest; |
| 33 | } |
| 156 | return $this->psrRequest->getUri(); |
| 157 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 330 | $keys = $keys[0]; |
| 331 | } |
| 332 | |
| 333 | $strings = []; |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 327 | private function validateKeys(array $keys): array |
| 328 | { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 329 | if (count($keys) === 1 && is_array($keys[0])) { |
| 333 | $strings = []; |
| 334 | |
| 335 | foreach ($keys as $key) { |
| 335 | foreach ($keys as $key) { |
| 336 | if (is_array($key)) { |
| 337 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 338 | } |
| 339 | |
| 340 | $strings[] = $key; |
| 341 | } |
| 342 | |
| 343 | return $strings; |
| 344 | } |
| 141 | public function with(string $attribute, mixed $value): static |
| 142 | { |
| 143 | return $this->wrapping($this->psrRequest->withAttribute($attribute, $value)); |
| 144 | } |
| 119 | public function withAddedHeader(string $header, string $value): static |
| 120 | { |
| 121 | return $this->wrapping($this->psrRequest->withAddedHeader($header, $value)); |
| 122 | } |
| 114 | public function withHeader(string $header, string $value): static |
| 115 | { |
| 116 | return $this->wrapping($this->psrRequest->withHeader($header, $value)); |
| 117 | } |
| 124 | public function withoutHeader(string $header): static |
| 125 | { |
| 126 | return $this->wrapping($this->psrRequest->withoutHeader($header)); |
| 127 | } |
| 347 | private function wrapping(PsrServerRequest $request): static |
| 348 | { |
| 349 | return clone($this, ['psrRequest' => $request]); |
| 350 | } |
| 108 | return array_map(static fn(array $val): string => $val[0] ?? '', $headers); |
| 317 | static fn(string $key): string => "['" . $key . "']", |