Skip to content

Commit

Permalink
add PSR18 http adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
Naoray committed Jun 24, 2024
1 parent edcc1e8 commit c10e175
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 86 deletions.
95 changes: 49 additions & 46 deletions src/Exceptions/ApiException.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,74 @@
namespace Mollie\Api\Exceptions;

use DateTime;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class ApiException extends \Exception
{
/**
* @var string
*/
protected $field;
protected ?string $field;

/**
* @var string
*/
protected $plainMessage;
protected string $plainMessage;

/**
* @var \Psr\Http\Message\RequestInterface|null
* @var RequestInterface|null
*/
protected $request;
protected ?RequestInterface $request;

/**
* @var \Psr\Http\Message\ResponseInterface|null
* @var ResponseInterface|null
*/
protected $response;
protected ?ResponseInterface $response;

/**
* ISO8601 representation of the moment this exception was thrown
*
* @var \DateTimeImmutable
*/
protected $raisedAt;
protected \DateTimeImmutable $raisedAt;

/**
* @var array
*/
protected $links = [];
protected array $links = [];

/**
* @param string $message
* @param int $code
* @param string|null $field
* @param \Psr\Http\Message\RequestInterface|null $request
* @param \Psr\Http\Message\ResponseInterface|null $response
* @param \Throwable|null $previous
* @throws \Mollie\Api\Exceptions\ApiException
* @param RequestInterface|null $request
* @param ResponseInterface|null $response
* @param Throwable|null $previous
* @throws ApiException
*/
public function __construct(
$message = "",
$code = 0,
$field = null,
$request = null,
$response = null,
$previous = null
string $message = "",
int $code = 0,
?string $field = null,
?RequestInterface $request = null,
?ResponseInterface $response = null,
?Throwable $previous = null
) {
$this->plainMessage = $message;

$this->raisedAt = new \DateTimeImmutable();

$formattedRaisedAt = $this->raisedAt->format(DateTime::ISO8601);
$formattedRaisedAt = $this->raisedAt->format(DateTime::ATOM);
$message = "[{$formattedRaisedAt}] " . $message;

if (! empty($field)) {
if (!empty($field)) {
$this->field = (string)$field;
$message .= ". Field: {$this->field}";
}

if (! empty($response)) {
if (!empty($response)) {
$this->response = $response;

$object = static::parseResponseBody($this->response);
Expand Down Expand Up @@ -96,18 +99,18 @@ public function __construct(
}

/**
* @param \Psr\Http\Message\ResponseInterface $response
* @param \Psr\Http\Message\RequestInterface $request
* @param \Throwable|null $previous
* @return \Mollie\Api\Exceptions\ApiException
* @throws \Mollie\Api\Exceptions\ApiException
* @param ResponseInterface $response
* @param ?RequestInterface $request
* @param Throwable|null $previous
* @return ApiException
* @throws ApiException
*/
public static function createFromResponse($response, $request = null, $previous = null)
public static function createFromResponse(ResponseInterface $response, ?RequestInterface $request = null, ?Throwable $previous = null): self
{
$object = static::parseResponseBody($response);

$field = null;
if (! empty($object->field)) {
if (!empty($object->field)) {
$field = $object->field;
}

Expand All @@ -124,48 +127,48 @@ public static function createFromResponse($response, $request = null, $previous
/**
* @return string|null
*/
public function getField()
public function getField(): ?string
{
return $this->field;
}

/**
* @return string|null
*/
public function getDocumentationUrl()
public function getDocumentationUrl(): ?string
{
return $this->getUrl('documentation');
}

/**
* @return string|null
*/
public function getDashboardUrl()
public function getDashboardUrl(): ?string
{
return $this->getUrl('dashboard');
}

/**
* @return \Psr\Http\Message\ResponseInterface|null
* @return ResponseInterface|null
*/
public function getResponse()
public function getResponse(): ?ResponseInterface
{
return $this->response;
}

/**
* @return bool
*/
public function hasResponse()
public function hasResponse(): bool
{
return $this->response !== null;
return !!$this->response;
}

/**
* @param string $key
* @return bool
*/
public function hasLink($key)
public function hasLink($key): bool
{
return array_key_exists($key, $this->links);
}
Expand All @@ -174,7 +177,7 @@ public function hasLink($key)
* @param string $key
* @return mixed|null
*/
public function getLink($key)
public function getLink($key): ?\stdClass
{
if ($this->hasLink($key)) {
return $this->links[$key];
Expand All @@ -185,9 +188,9 @@ public function getLink($key)

/**
* @param string $key
* @return null
* @return string|null
*/
public function getUrl($key)
public function getUrl($key): ?string
{
if ($this->hasLink($key)) {
return $this->getLink($key)->href;
Expand All @@ -197,9 +200,9 @@ public function getUrl($key)
}

/**
* @return \Psr\Http\Message\RequestInterface
* @return null|RequestInterface
*/
public function getRequest()
public function getRequest(): ?RequestInterface
{
return $this->request;
}
Expand All @@ -209,17 +212,17 @@ public function getRequest()
*
* @return \DateTimeImmutable
*/
public function getRaisedAt()
public function getRaisedAt(): \DateTimeImmutable
{
return $this->raisedAt;
}

/**
* @param \Psr\Http\Message\ResponseInterface $response
* @param ResponseInterface $response
* @return \stdClass
* @throws \Mollie\Api\Exceptions\ApiException
* @throws ApiException
*/
protected static function parseResponseBody($response)
protected static function parseResponseBody($response): \stdClass
{
$body = (string) $response->getBody();

Expand All @@ -237,7 +240,7 @@ protected static function parseResponseBody($response)
*
* @return string
*/
public function getPlainMessage()
public function getPlainMessage(): string
{
return $this->plainMessage;
}
Expand Down
26 changes: 13 additions & 13 deletions src/HttpAdapter/CurlMollieHttpAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ final class CurlMollieHttpAdapter implements MollieHttpAdapterInterface
* @throws \Mollie\Api\Exceptions\ApiException
* @throws \Mollie\Api\Exceptions\CurlConnectTimeoutException
*/
public function send($httpMethod, $url, $headers, $httpBody)
public function send(string $httpMethod, string $url, $headers, ?string $httpBody): ?\stdClass
{
for ($i = 0; $i <= self::MAX_RETRIES; $i++) {
usleep($i * self::DELAY_INCREASE_MS);

try {
return $this->attemptRequest($httpMethod, $url, $headers, $httpBody);
} catch (CurlConnectTimeoutException $e) {
// Nothing
return null;
}
}

throw new CurlConnectTimeoutException(
"Unable to connect to Mollie. Maximum number of retries (". self::MAX_RETRIES .") reached."
"Unable to connect to Mollie. Maximum number of retries (" . self::MAX_RETRIES . ") reached."
);
}

Expand All @@ -68,7 +68,7 @@ public function send($httpMethod, $url, $headers, $httpBody)
* @return \stdClass|void|null
* @throws \Mollie\Api\Exceptions\ApiException
*/
protected function attemptRequest($httpMethod, $url, $headers, $httpBody)
protected function attemptRequest(string $httpMethod, string $url, array $headers, string $httpBody): ?\stdClass
{
$curl = curl_init($url);
$headers["Content-Type"] = "application/json";
Expand Down Expand Up @@ -99,7 +99,7 @@ protected function attemptRequest($httpMethod, $url, $headers, $httpBody)

break;
default:
throw new \InvalidArgumentException("Invalid http method: ". $httpMethod);
throw new \InvalidArgumentException("Invalid http method: " . $httpMethod);
}

$startTime = microtime(true);
Expand Down Expand Up @@ -130,7 +130,7 @@ protected function attemptRequest($httpMethod, $url, $headers, $httpBody)
*
* @return string|null
*/
public function versionString()
public function versionString(): string
{
return 'Curl/*';
}
Expand All @@ -139,9 +139,9 @@ public function versionString()
* Whether this http adapter provides a debugging mode. If debugging mode is enabled, the
* request will be included in the ApiException.
*
* @return false
* @return bool
*/
public function supportsDebugging()
public function supportsDebugging(): bool
{
return false;
}
Expand All @@ -151,7 +151,7 @@ public function supportsDebugging()
* @param string|float $executionTime
* @return bool
*/
protected function isConnectTimeoutError($curlErrorNumber, $executionTime)
protected function isConnectTimeoutError(int $curlErrorNumber, $executionTime): bool
{
$connectErrors = [
\CURLE_COULDNT_RESOLVE_HOST => true,
Expand Down Expand Up @@ -182,7 +182,7 @@ protected function isConnectTimeoutError($curlErrorNumber, $executionTime)
* @return \stdClass|null
* @throws \Mollie\Api\Exceptions\ApiException
*/
protected function parseResponseBody($response, $statusCode, $httpBody)
protected function parseResponseBody(string $response, int $statusCode, string $httpBody): ?\stdClass
{
if (empty($response)) {
if ($statusCode === self::HTTP_NO_CONTENT) {
Expand All @@ -208,7 +208,7 @@ protected function parseResponseBody($response, $statusCode, $httpBody)

$field = null;

if (! empty($body->field)) {
if (!empty($body->field)) {
$field = $body->field;
}

Expand All @@ -226,12 +226,12 @@ protected function parseResponseBody($response, $statusCode, $httpBody)
return $body;
}

protected function parseHeaders($headers)
protected function parseHeaders(array $headers): array
{
$result = [];

foreach ($headers as $key => $value) {
$result[] = $key .': ' . $value;
$result[] = $key . ': ' . $value;
}

return $result;
Expand Down
Loading

0 comments on commit c10e175

Please sign in to comment.