Represents an HTTP request.
Description
This class encapsulates HTTP request data that can be converted to PSR-7 requests by the HTTP transporter.
Methods
| Name | Description |
|---|---|
| Request::__clone | Creates a deep clone of this request. |
| Request::__construct | Constructor. |
| Request::fromArray | {@inheritDoc} |
| Request::fromPsrRequest | Creates a Request instance from a PSR-7 RequestInterface. |
| Request::getBody | Gets the request body. |
| Request::getContentType | Gets the Content-Type header value. |
| Request::getData | Gets the request data array. |
| Request::getHeader | Gets a specific header value. |
| Request::getHeaderAsString | Gets header values as a comma-separated string. |
| Request::getHeaders | Gets the request headers. |
| Request::getJsonSchema | {@inheritDoc} |
| Request::getMethod | Gets the HTTP method. |
| Request::getOptions | Gets the request options. |
| Request::getUri | Gets the request URI. |
| Request::hasHeader | Checks if a header exists. |
| Request::toArray | {@inheritDoc} |
| Request::withData | Returns a new instance with the specified data. |
| Request::withHeader | Returns a new instance with the specified header. |
| Request::withOptions | Returns a new instance with the specified request options. |
Source
class Request extends AbstractDataTransferObject
{
public const KEY_METHOD = 'method';
public const KEY_URI = 'uri';
public const KEY_HEADERS = 'headers';
public const KEY_BODY = 'body';
public const KEY_OPTIONS = 'options';
/**
* @var HttpMethodEnum The HTTP method.
*/
protected HttpMethodEnum $method;
/**
* @var string The request URI.
*/
protected string $uri;
/**
* @var HeadersCollection The request headers.
*/
protected HeadersCollection $headers;
/**
* @var array<string, mixed>|null The request data (for query params or form data).
*/
protected ?array $data = null;
/**
* @var string|null The request body (raw string content).
*/
protected ?string $body = null;
/**
* @var RequestOptions|null Request transport options.
*/
protected ?\WordPress\AiClient\Providers\Http\DTO\RequestOptions $options = null;
/**
* Constructor.
*
* @since 0.1.0
*
* @param HttpMethodEnum $method The HTTP method.
* @param string $uri The request URI.
* @param array<string, string|list<string>> $headers The request headers.
* @param string|array<string, mixed>|null $data The request data.
* @param RequestOptions|null $options The request transport options.
*
* @throws InvalidArgumentException If the URI is empty.
*/
public function __construct(HttpMethodEnum $method, string $uri, array $headers = [], $data = null, ?\WordPress\AiClient\Providers\Http\DTO\RequestOptions $options = null)
{
if (empty($uri)) {
throw new InvalidArgumentException('URI cannot be empty.');
}
$this->method = $method;
$this->uri = $uri;
$this->headers = new HeadersCollection($headers);
// Separate data and body based on type
if (is_string($data)) {
$this->body = $data;
} elseif (is_array($data)) {
$this->data = $data;
}
$this->options = $options;
}
/**
* Creates a deep clone of this request.
*
* Clones the headers collection and request options to ensure
* the cloned request is independent of the original.
* The HTTP method enum is immutable and can be safely shared.
*
* @since 0.4.2
*/
public function __clone()
{
// Clone headers collection
$this->headers = clone $this->headers;
// Clone request options if present (contains only primitives)
if ($this->options !== null) {
$this->options = clone $this->options;
}
// Note: $method is an immutable enum and can be safely shared
}
/**
* Gets the HTTP method.
*
* @since 0.1.0
*
* @return HttpMethodEnum The HTTP method.
*/
public function getMethod(): HttpMethodEnum
{
return $this->method;
}
/**
* Gets the request URI.
*
* For GET requests with array data, appends the data as query parameters.
*
* @since 0.1.0
*
* @return string The URI.
*/
public function getUri(): string
{
// If GET request with data, append as query parameters
if ($this->method === HttpMethodEnum::GET() && $this->data !== null && !empty($this->data)) {
$separator = str_contains($this->uri, '?') ? '&' : '?';
return $this->uri . $separator . http_build_query($this->data);
}
return $this->uri;
}
/**
* Gets the request headers.
*
* @since 0.1.0
*
* @return array<string, list<string>> The headers.
*/
public function getHeaders(): array
{
return $this->headers->getAll();
}
/**
* Gets a specific header value.
*
* @since 0.1.0
*
* @param string $name The header name (case-insensitive).
* @return list<string>|null The header value(s) or null if not found.
*/
public function getHeader(string $name): ?array
{
return $this->headers->get($name);
}
/**
* Gets header values as a comma-separated string.
*
* @since 0.1.0
*
* @param string $name The header name (case-insensitive).
* @return string|null The header values as a comma-separated string, or null if not found.
*/
public function getHeaderAsString(string $name): ?string
{
return $this->headers->getAsString($name);
}
/**
* Checks if a header exists.
*
* @since 0.1.0
*
* @param string $name The header name (case-insensitive).
* @return bool True if the header exists, false otherwise.
*/
public function hasHeader(string $name): bool
{
return $this->headers->has($name);
}
/**
* Gets the request body.
*
* For GET requests, returns null.
* For POST/PUT/PATCH requests:
* - If body is set, returns it as-is
* - If data is set and Content-Type is JSON, returns JSON-encoded data
* - If data is set and Content-Type is form, returns URL-encoded data
*
* @since 0.1.0
*
* @return string|null The body.
* @throws JsonException If the data cannot be encoded to JSON.
*/
public function getBody(): ?string
{
// GET requests don't have a body
if (!$this->method->hasBody()) {
return null;
}
// If body is set, return it as-is
if ($this->body !== null) {
return $this->body;
}
// If data is set, encode based on content type
if ($this->data !== null) {
$contentType = $this->getContentType();
// JSON encoding
if ($contentType !== null && stripos($contentType, 'application/json') !== \false) {
return json_encode($this->data, \JSON_THROW_ON_ERROR);
}
// Default to URL encoding for forms
return http_build_query($this->data);
}
return null;
}
/**
* Gets the Content-Type header value.
*
* @since 0.1.0
*
* @return string|null The Content-Type header value or null if not set.
*/
private function getContentType(): ?string
{
$values = $this->getHeader('Content-Type');
return $values !== null ? $values[0] : null;
}
/**
* Returns a new instance with the specified header.
*
* @since 0.1.0
*
* @param string $name The header name.
* @param string|list<string> $value The header value(s).
* @return self A new instance with the header.
*/
public function withHeader(string $name, $value): self
{
$newHeaders = $this->headers->withHeader($name, $value);
$new = clone $this;
$new->headers = $newHeaders;
return $new;
}
/**
* Returns a new instance with the specified data.
*
* @since 0.1.0
*
* @param string|array<string, mixed> $data The request data.
* @return self A new instance with the data.
*/
public function withData($data): self
{
$new = clone $this;
if (is_string($data)) {
$new->body = $data;
$new->data = null;
} elseif (is_array($data)) {
$new->data = $data;
$new->body = null;
} else {
$new->data = null;
$new->body = null;
}
return $new;
}
/**
* Gets the request data array.
*
* @since 0.1.0
*
* @return array<string, mixed>|null The request data array.
*/
public function getData(): ?array
{
return $this->data;
}
/**
* Gets the request options.
*
* @since 0.2.0
*
* @return RequestOptions|null Request transport options when configured.
*/
public function getOptions(): ?\WordPress\AiClient\Providers\Http\DTO\RequestOptions
{
return $this->options;
}
/**
* Returns a new instance with the specified request options.
*
* @since 0.2.0
*
* @param RequestOptions|null $options The request options to apply.
* @return self A new instance with the options.
*/
public function withOptions(?\WordPress\AiClient\Providers\Http\DTO\RequestOptions $options): self
{
$new = clone $this;
$new->options = $options;
return $new;
}
/**
* {@inheritDoc}
*
* @since 0.1.0
*/
public static function getJsonSchema(): array
{
return ['type' => 'object', 'properties' => [self::KEY_METHOD => ['type' => 'string', 'description' => 'The HTTP method.'], self::KEY_URI => ['type' => 'string', 'description' => 'The request URI.'], self::KEY_HEADERS => ['type' => 'object', 'additionalProperties' => ['type' => 'array', 'items' => ['type' => 'string']], 'description' => 'The request headers.'], self::KEY_BODY => ['type' => ['string'], 'description' => 'The request body.'], self::KEY_OPTIONS => \WordPress\AiClient\Providers\Http\DTO\RequestOptions::getJsonSchema()], 'required' => [self::KEY_METHOD, self::KEY_URI, self::KEY_HEADERS]];
}
/**
* {@inheritDoc}
*
* @since 0.1.0
*
* @return RequestArrayShape
*/
public function toArray(): array
{
$array = [
self::KEY_METHOD => $this->method->value,
self::KEY_URI => $this->getUri(),
// Include query params if GET with data
self::KEY_HEADERS => $this->headers->getAll(),
];
// Include body if present (getBody() handles the conversion)
$body = $this->getBody();
if ($body !== null) {
$array[self::KEY_BODY] = $body;
}
if ($this->options !== null) {
$optionsArray = $this->options->toArray();
if (!empty($optionsArray)) {
$array[self::KEY_OPTIONS] = $optionsArray;
}
}
return $array;
}
/**
* {@inheritDoc}
*
* @since 0.1.0
*/
public static function fromArray(array $array): self
{
static::validateFromArrayData($array, [self::KEY_METHOD, self::KEY_URI, self::KEY_HEADERS]);
return new self(HttpMethodEnum::from($array[self::KEY_METHOD]), $array[self::KEY_URI], $array[self::KEY_HEADERS] ?? [], $array[self::KEY_BODY] ?? null, isset($array[self::KEY_OPTIONS]) ? \WordPress\AiClient\Providers\Http\DTO\RequestOptions::fromArray($array[self::KEY_OPTIONS]) : null);
}
/**
* Creates a Request instance from a PSR-7 RequestInterface.
*
* @since 0.2.0
*
* @param RequestInterface $psrRequest The PSR-7 request to convert.
* @return self A new Request instance.
* @throws InvalidArgumentException If the HTTP method is not supported.
*/
public static function fromPsrRequest(RequestInterface $psrRequest): self
{
$method = HttpMethodEnum::from($psrRequest->getMethod());
$uri = (string) $psrRequest->getUri();
// Convert PSR-7 headers to array format expected by our constructor
/** @var array<string, list<string>> $headers */
$headers = $psrRequest->getHeaders();
// Get body content
$body = $psrRequest->getBody()->getContents();
$bodyOrData = !empty($body) ? $body : null;
return new self($method, $uri, $headers, $bodyOrData);
}
}
Changelog
| Version | Description |
|---|---|
| 0.1.0 | Introduced. |
User Contributed Notes
You must log in before being able to contribute a note or feedback.