get(Session::class); } #[SkipValidation] public array $cookies = []; public function __construct( Method $method, string $uri, array $body = [], array $headers = [], array $files = [], ?string $raw = null, ) { $this->method = $method; $this->uri = $uri; $this->body = $body; $this->headers = RequestHeaders::normalizeFromArray($headers); $this->files = $files; $this->raw = $raw; $this->path ??= $this->resolvePath(); $this->query ??= $this->resolveQuery(); } public function get(string $key, mixed $default = null): mixed { if (array_key_exists($key, $this->body)) { return get_by_key($this->body, $key); } if (array_key_exists($key, $this->query)) { return get_by_key($this->query, $key); } return $default; } public function getSessionValue(string $name): mixed { /** @var Session $session */ $session = get(Session::class); return $session->get($name); } public function getCookie(string $name): ?Cookie { return $this->cookies[$name] ?? null; } private function resolvePath(): string { $decodedUri = rawurldecode($this->uri); $parsedUrl = parse_url($decodedUri); return $parsedUrl['path'] ?? ''; } private function resolveQuery(): array { $decodedUri = rawurldecode($this->uri); $parsedUrl = parse_url($decodedUri); $queryString = $parsedUrl['query'] ?? ''; parse_str($queryString, $query); return $query; } public function has(string $key): bool { if ($this->hasBody($key)) { return true; } return $this->hasQuery($key); } public function hasBody(?string $key = null): bool { if ($key) { return has_key($this->body, $key); } return count($this->body) || (bool) $this->raw; } public function hasQuery(string $key): bool { return has_key($this->query, $key); } public function accepts(ContentType ...$contentTypes): bool { $header = $this->headers->get(name: 'accept') ?? ''; /** @var list */ $acceptedMediaTypes = []; foreach (str($header)->explode(separator: ',') as $acceptedType) { $acceptedType = str($acceptedType)->trim(); if ($acceptedType->isEmpty()) { continue; } $acceptedMediaTypes[] = [ 'mediaType' => $acceptedType->before('/')->toString(), 'subType' => $acceptedType->afterFirst('/')->beforeLast(';q')->toString(), ]; } if (count($acceptedMediaTypes) === 0) { return true; } foreach ($contentTypes as $contentType) { [$mediaType, $subType] = explode('/', string: $contentType->value); foreach ($acceptedMediaTypes as $acceptedType) { if ( ($acceptedType['mediaType'] === '*' || $acceptedType['mediaType'] === $mediaType) && ($acceptedType['subType'] === '*' || $acceptedType['subType'] === $subType) ) { return true; } } } return false; } public function withMethod(Method $method): self { $clone = clone $this; $clone->method = $method; return $clone; } }