Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@
"psr/http-factory": "^1.1",
"psr/http-message": "^2.0",
"tiny-blocks/mapper": "^3.2",
"tiny-blocks/time": "^2.6"
"tiny-blocks/time": "^2.7"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.52",
"guzzlehttp/guzzle": "^8.0",
"infection/infection": "^0.34",
"laminas/laminas-httphandlerrunner": "^2.13",
"ergebnis/composer-normalize": "^2.54",
"guzzlehttp/guzzle": "^8.3",
"infection/infection": "^0.35",
"laminas/laminas-httphandlerrunner": "^2.14",
"nyholm/psr7": "^1.8",
"phpstan/phpstan": "^2.2",
"phpunit/phpunit": "^13.2",
"phpstan/phpstan": "^2.3",
"phpunit/phpunit": "^13.4",
"psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0",
"slevomat/coding-standard": "^8.31",
Expand Down Expand Up @@ -86,7 +86,7 @@
"test-file": "@php ./vendor/bin/phpunit --configuration phpunit.xml --no-coverage --filter",
"tests": [
"@php -d memory_limit=2G ./vendor/bin/phpunit --configuration phpunit.xml tests",
"@php ./vendor/bin/infection --threads=max --logger-html=reports/coverage/mutation-report.html --coverage=reports/coverage"
"@php ./vendor/bin/infection --threads=max --logger-html=reports/coverage/mutation-report.html"
]
}
}
40 changes: 20 additions & 20 deletions src/Client/Resilience/RetryingClientBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ public function build(): RetryingClient
}

/**
* Sets the delay policy applied between attempts and returns the builder.
* Sets the monotonic clock measuring each attempt and returns the builder.
*
* @param Backoff $backoff The delay policy applied between attempts.
* @param MonotonicClock $clock The monotonic clock measuring each attempt.
* @return RetryingClientBuilder The builder instance for fluent configuration.
*/
public function withBackoff(Backoff $backoff): RetryingClientBuilder
public function withClock(MonotonicClock $clock): RetryingClientBuilder
{
$this->backoff = $backoff;
$this->clock = $clock;
return $this;
}

Expand All @@ -79,14 +79,26 @@ public function withClient(ClientInterface $client): RetryingClientBuilder
}

/**
* Sets the monotonic clock measuring each attempt and returns the builder.
* Sets the delay policy applied between attempts and returns the builder.
*
* @param MonotonicClock $clock The monotonic clock measuring each attempt.
* @param Backoff $backoff The delay policy applied between attempts.
* @return RetryingClientBuilder The builder instance for fluent configuration.
*/
public function withClock(MonotonicClock $clock): RetryingClientBuilder
public function withBackoff(Backoff $backoff): RetryingClientBuilder
{
$this->clock = $clock;
$this->backoff = $backoff;
return $this;
}

/**
* Sets the suspension applied between attempts and returns the builder.
*
* @param Sleeper $sleeper The suspension applied between attempts.
* @return RetryingClientBuilder The builder instance for fluent configuration.
*/
public function withSleeper(Sleeper $sleeper): RetryingClientBuilder
{
$this->sleeper = $sleeper;
return $this;
}

Expand Down Expand Up @@ -116,16 +128,4 @@ public function withMaxAttempts(int $maxAttempts): RetryingClientBuilder
$this->maxAttempts = $maxAttempts;
return $this;
}

/**
* Sets the suspension applied between attempts and returns the builder.
*
* @param Sleeper $sleeper The suspension applied between attempts.
* @return RetryingClientBuilder The builder instance for fluent configuration.
*/
public function withSleeper(Sleeper $sleeper): RetryingClientBuilder
{
$this->sleeper = $sleeper;
return $this;
}
}
10 changes: 5 additions & 5 deletions src/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
* HTTP response status codes indicate whether a specific HTTP request has been successfully completed.
* Responses are grouped in five classes:
*
* Informational (100 – 199)
* Successful (200 – 299)
* Redirection (300 – 399)
* Client error (400 – 499)
* Server error (500 – 599)
* Informational (100 to 199)
* Successful (200 to 299)
* Redirection (300 to 399)
* Client error (400 to 499)
* Server error (500 to 599)
*
* The <code>is*()</code> instance helpers validate by enum case, so they cover only the status codes
* represented here. Status codes outside this list (for example 250) return false for every helper.
Expand Down
30 changes: 15 additions & 15 deletions src/Internal/Server/Response/ResponseHeaders.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ private static function mergeInto(Headerable $header, array $merged): array
return $merged;
}

public static function fromWithDefaultContentType(Headerable ...$headers): ResponseHeaders
{
$provided = ResponseHeaders::fromWithoutDefaultContentType(...$headers);

if ($provided->hasHeader(name: ResponseHeaders::CONTENT_TYPE)) {
return $provided;
}

$contentType = ContentType::applicationJson(charset: Charset::UTF_8);

return new ResponseHeaders(
headers: ResponseHeaders::mergeInto(header: $contentType, merged: $provided->toArray())
);
}

/**
* Merges the supplied headers exactly as given, with no media type of the library's own. A response built
* without a body has no payload to describe, and announcing one over zero bytes misleads a strict client
Expand All @@ -42,21 +57,6 @@ public static function fromWithoutDefaultContentType(Headerable ...$headers): Re
return new ResponseHeaders(headers: $merged);
}

public static function fromWithDefaultContentType(Headerable ...$headers): ResponseHeaders
{
$provided = ResponseHeaders::fromWithoutDefaultContentType(...$headers);

if ($provided->hasHeader(name: ResponseHeaders::CONTENT_TYPE)) {
return $provided;
}

$contentType = ContentType::applicationJson(charset: Charset::UTF_8);

return new ResponseHeaders(
headers: ResponseHeaders::mergeInto(header: $contentType, merged: $provided->toArray())
);
}

private function findKey(string $name): ?string
{
$lowered = strtolower($name);
Expand Down
2 changes: 1 addition & 1 deletion src/Internal/Server/Stream/Stream.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ final class Stream implements StreamInterface

private mixed $resource;

private function __construct(private readonly bool $seekable, mixed $resource)
private function __construct(mixed $resource, private readonly bool $seekable)
{
$this->resource = $resource;
}
Expand Down
48 changes: 24 additions & 24 deletions src/Server/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ private function __construct()
{
}

public static function from(mixed $body, Code $code, Headerable ...$headers): ResponseInterface
public static function ok(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, $code, ...$headers);
return InternalResponse::createWithBody($body, Code::OK, ...$headers);
}

public static function ok(mixed $body, Headerable ...$headers): ResponseInterface
public static function from(mixed $body, Code $code, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::OK, ...$headers);
return InternalResponse::createWithBody($body, $code, ...$headers);
}

public static function created(mixed $body, Headerable ...$headers): ResponseInterface
Expand All @@ -40,53 +40,53 @@ public static function accepted(mixed $body, Headerable ...$headers): ResponseIn
return InternalResponse::createWithBody($body, Code::ACCEPTED, ...$headers);
}

public static function noContent(Headerable ...$headers): ResponseInterface
public static function conflict(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithoutBody(Code::NO_CONTENT, ...$headers);
return InternalResponse::createWithBody($body, Code::CONFLICT, ...$headers);
}

public static function badRequest(mixed $body, Headerable ...$headers): ResponseInterface
public static function notFound(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::BAD_REQUEST, ...$headers);
return InternalResponse::createWithBody($body, Code::NOT_FOUND, ...$headers);
}

public static function unauthorized(mixed $body, Headerable ...$headers): ResponseInterface
public static function forbidden(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::UNAUTHORIZED, ...$headers);
return InternalResponse::createWithBody($body, Code::FORBIDDEN, ...$headers);
}

public static function forbidden(mixed $body, Headerable ...$headers): ResponseInterface
public static function noContent(Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::FORBIDDEN, ...$headers);
return InternalResponse::createWithoutBody(Code::NO_CONTENT, ...$headers);
}

public static function notFound(mixed $body, Headerable ...$headers): ResponseInterface
public static function badGateway(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::NOT_FOUND, ...$headers);
return InternalResponse::createWithBody($body, Code::BAD_GATEWAY, ...$headers);
}

public static function conflict(mixed $body, Headerable ...$headers): ResponseInterface
public static function badRequest(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::CONFLICT, ...$headers);
return InternalResponse::createWithBody($body, Code::BAD_REQUEST, ...$headers);
}

public static function unprocessableEntity(mixed $body, Headerable ...$headers): ResponseInterface
public static function unauthorized(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::UNPROCESSABLE_ENTITY, ...$headers);
return InternalResponse::createWithBody($body, Code::UNAUTHORIZED, ...$headers);
}

public static function internalServerError(mixed $body, Headerable ...$headers): ResponseInterface
public static function serviceUnavailable(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::INTERNAL_SERVER_ERROR, ...$headers);
return InternalResponse::createWithBody($body, Code::SERVICE_UNAVAILABLE, ...$headers);
}

public static function badGateway(mixed $body, Headerable ...$headers): ResponseInterface
public static function internalServerError(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::BAD_GATEWAY, ...$headers);
return InternalResponse::createWithBody($body, Code::INTERNAL_SERVER_ERROR, ...$headers);
}

public static function serviceUnavailable(mixed $body, Headerable ...$headers): ResponseInterface
public static function unprocessableEntity(mixed $body, Headerable ...$headers): ResponseInterface
{
return InternalResponse::createWithBody($body, Code::SERVICE_UNAVAILABLE, ...$headers);
return InternalResponse::createWithBody($body, Code::UNPROCESSABLE_ENTITY, ...$headers);
}
}
Loading