Skip to content

Commit

Permalink
refactor: resources are required to always provide a response, respon…
Browse files Browse the repository at this point in the history
…ses are only hydrated if body is not empty
  • Loading branch information
Naoray committed Feb 7, 2025
1 parent 2e5fe56 commit 3a8e0da
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/Contracts/IsResponseAware.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

interface IsResponseAware extends ViableResponse
{
public function getResponse(): ?Response;
public function getResponse(): Response;

public function setResponse(?Response $response): self;
public function setResponse(Response $response): self;
}
4 changes: 2 additions & 2 deletions src/EndpointCollection/SubscriptionEndpointCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function update(string $customerId, string $subscriptionId, array $payloa
*
* @throws RequestException
*/
public function cancelFor(Customer $customer, string $subscriptionId, bool $testmode = false): ?Subscription
public function cancelFor(Customer $customer, string $subscriptionId, bool $testmode = false): Subscription
{
return $this->cancelForId($customer->id, $subscriptionId, $testmode);
}
Expand All @@ -100,7 +100,7 @@ public function cancelFor(Customer $customer, string $subscriptionId, bool $test
*
* @throws RequestException
*/
public function cancelForId(string $customerId, string $subscriptionId, bool $testmode = false): ?Subscription
public function cancelForId(string $customerId, string $subscriptionId, bool $testmode = false): Subscription
{
return $this->send((new CancelSubscriptionRequest($customerId, $subscriptionId))->test($testmode));
}
Expand Down
7 changes: 2 additions & 5 deletions src/Fake/MockResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,9 @@ public static function created($body = [], string $resourceKey = ''): self
return new self($body, 201, $resourceKey);
}

/**
* @param string|array $body
*/
public static function noContent($body = [], string $resourceKey = ''): self
public static function noContent(string $resourceKey = ''): self
{
return new self($body, 204, $resourceKey);
return new self('', 204, $resourceKey);
}

public static function notFound(string $resourceKey = ''): self
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Middleware/Hydrate.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function __invoke(Response $response)
{
$request = $response->getRequest();

if ($request instanceof ResourceHydratableRequest && $request->isHydratable()) {
if (!$response->isEmpty() &&$request instanceof ResourceHydratableRequest && $request->isHydratable()) {
return (new ResourceHydrator)->hydrate($request, $response);
}

Expand Down
10 changes: 3 additions & 7 deletions src/Traits/HasResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@

trait HasResponse
{
protected ?Response $response = null;
protected Response $response;

public function getResponse(): ?Response
public function getResponse(): Response
{
return $this->response;
}

public function setResponse(?Response $response): self
public function setResponse(Response $response): self
{
$this->response = $response;

Expand All @@ -24,10 +24,6 @@ public function setResponse(?Response $response): self

public function getPendingRequest(): PendingRequest
{
if (! $this->response) {
throw new LogicException('Response is not set');
}

return $this->response->getPendingRequest();
}
}
12 changes: 6 additions & 6 deletions tests/EndpointCollection/ProfileMethodEndpointCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

use Mollie\Api\Fake\MockMollieClient;
use Mollie\Api\Fake\MockResponse;
use Mollie\Api\Http\Requests\DisableProfileMethodRequest;
use Mollie\Api\Http\Requests\EnableProfileMethodRequest;
use Mollie\Api\Http\Requests\DisableMethodRequest;
use Mollie\Api\Http\Requests\EnableMethodRequest;
use Mollie\Api\Resources\Method;
use PHPUnit\Framework\TestCase;

Expand All @@ -15,7 +15,7 @@ class ProfileMethodEndpointCollectionTest extends TestCase
public function enable_for_id()
{
$client = new MockMollieClient([
EnableProfileMethodRequest::class => MockResponse::ok('method', 'ideal'),
EnableMethodRequest::class => MockResponse::ok('method', 'ideal'),
]);

/** @var Method $method */
Expand All @@ -28,7 +28,7 @@ public function enable_for_id()
public function enable()
{
$client = new MockMollieClient([
EnableProfileMethodRequest::class => MockResponse::ok('method', 'ideal'),
EnableMethodRequest::class => MockResponse::ok('method', 'ideal'),
]);

/** @var Method $method */
Expand All @@ -41,7 +41,7 @@ public function enable()
public function disable_for_id()
{
$client = new MockMollieClient([
DisableProfileMethodRequest::class => MockResponse::noContent(),
DisableMethodRequest::class => MockResponse::noContent(),
]);

$client->profileMethods->disableForId('pfl_v9hTwCvYqw', 'ideal');
Expand All @@ -54,7 +54,7 @@ public function disable_for_id()
public function disable()
{
$client = new MockMollieClient([
DisableProfileMethodRequest::class => MockResponse::noContent(),
DisableMethodRequest::class => MockResponse::noContent(),
]);

$client->profileMethods->disable('ideal');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public function update_for()
public function cancel_for()
{
$client = new MockMollieClient([
CancelSubscriptionRequest::class => MockResponse::noContent(),
CancelSubscriptionRequest::class => MockResponse::ok('subscription'),
]);

$customer = new Customer($client);
Expand Down
2 changes: 1 addition & 1 deletion tests/Http/Requests/CancelPaymentRefundRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CancelPaymentRefundRequestTest extends TestCase
public function it_can_cancel_payment_refund()
{
$client = new MockMollieClient([
CancelPaymentRefundRequest::class => MockResponse::noContent(''),
CancelPaymentRefundRequest::class => MockResponse::noContent(),
]);

$paymentId = 'tr_7UhSN1zuXS';
Expand Down
2 changes: 1 addition & 1 deletion tests/Http/Requests/DeleteProfileRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DeleteProfileRequestTest extends TestCase
public function it_can_delete_profile()
{
$client = new MockMollieClient([
DeleteProfileRequest::class => MockResponse::noContent(''),
DeleteProfileRequest::class => MockResponse::noContent(),
]);

$profileId = 'pfl_v9hTwCvYqw';
Expand Down
2 changes: 1 addition & 1 deletion tests/Http/Requests/RevokeMandateRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class RevokeMandateRequestTest extends TestCase
public function it_can_revoke_mandate()
{
$client = new MockMollieClient([
RevokeMandateRequest::class => MockResponse::noContent(''),
RevokeMandateRequest::class => MockResponse::noContent(),
]);

$customerId = 'cst_kEn1PlbGa';
Expand Down
18 changes: 18 additions & 0 deletions tests/MollieApiClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Mollie\Api\Http\PendingRequest;
use Mollie\Api\Http\Request;
use Mollie\Api\Http\Requests\CreatePaymentRequest;
use Mollie\Api\Http\Requests\DynamicPostRequest;
use Mollie\Api\Http\Requests\UpdatePaymentRequest;
use Mollie\Api\Http\Response;
use Mollie\Api\Idempotency\FakeIdempotencyKeyGenerator;
Expand Down Expand Up @@ -496,6 +497,23 @@ public function empty_or_null_payload_parameters_are_not_added_to_the_request()

$client->send($request);
}

/** @test */
public function a_response_with_empty_body_is_not_hydrated()
{
$client = new MockMollieClient([
DynamicPostRequest::class => MockResponse::noContent(),
]);

$request = new DynamicPostRequest('dummy');

$request->setHydratableResource(new WrapperResource(DummyResourceWrapper::class));

/** @var Response $response */
$response = $client->send($request);

$this->assertInstanceOf(Response::class, $response);
}
}

class DummyResourceWrapper extends ResourceWrapper
Expand Down
13 changes: 11 additions & 2 deletions tests/Resources/BaseCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tests\Resources;

use Mollie\Api\Contracts\Connector;
use Mollie\Api\Http\Response;
use Mollie\Api\Resources\BaseCollection;
use PHPUnit\Framework\TestCase;
use stdClass;
Expand All @@ -11,9 +12,12 @@ class BaseCollectionTest extends TestCase
{
private Connector $connectorMock;

private Response $response;

protected function setUp(): void
{
$this->connectorMock = $this->createMock(Connector::class);
$this->response = $this->createMock(Response::class);
}

/** @test */
Expand All @@ -25,6 +29,8 @@ public function constructor_initializes_collection_properly()

$collection = new TestCollection($this->connectorMock, $items, $links);

$collection->setResponse($this->response);

$this->assertCount(2, $collection);
$this->assertSame($items, $collection->getArrayCopy());
$this->assertSame($links, $collection->_links);
Expand All @@ -40,6 +46,7 @@ public function contains_returns_true_when_item_exists()
];

$collection = new TestCollection($this->connectorMock, $items);
$collection->setResponse($this->response);

$this->assertTrue($collection->contains(fn ($item) => $item === 'banana'));
}
Expand All @@ -54,7 +61,7 @@ public function contains_returns_false_when_item_does_not_exist()
];

$collection = new TestCollection($this->connectorMock, $items);

$collection->setResponse($this->response);
$this->assertFalse($collection->contains(fn ($item) => $item === 'grape'));
}

Expand All @@ -68,6 +75,7 @@ public function filter_returns_filtered_collection()
];

$collection = new TestCollection($this->connectorMock, $items);
$collection->setResponse($this->response);
$filtered = $collection->filter(fn ($item) => $item !== 'banana');

$this->assertCount(2, $filtered);
Expand All @@ -84,6 +92,7 @@ public function filter_returns_filtered_collection()
public function first_returns_first_item()
{
$collection = new TestCollection($this->connectorMock, ['item1', 'item2']);
$collection->setResponse($this->response);
$this->assertEquals('item1', $collection->first());
}

Expand All @@ -94,7 +103,7 @@ public function first_where_returns_first_item_where_condition_is_true()
['id' => 'item1'],
['id' => 'item2'],
]);

$collection->setResponse($this->response);
$this->assertEquals(['id' => 'item2'], $collection->firstWhere('id', 'item2'));
$this->assertEquals(['id' => 'item1'], $collection->firstWhere(fn ($item) => $item['id'] === 'item1'));
}
Expand Down
22 changes: 22 additions & 0 deletions tests/Resources/CursorCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@
use Mollie\Api\Fake\MockResponse;
use Mollie\Api\Fake\SequenceMockResponse;
use Mollie\Api\Http\Requests\DynamicGetRequest;
use Mollie\Api\Http\Response;
use Mollie\Api\Resources\LazyCollection;
use Mollie\Api\Resources\PaymentCollection;
use PHPUnit\Framework\TestCase;
use stdClass;

class CursorCollectionTest extends TestCase
{
private Response $response;

protected function setUp(): void
{
parent::setUp();

$this->response = $this->createMock(Response::class);
}

/** @test */
public function can_get_next_collection_result_when_next_link_is_available()
{
Expand All @@ -30,6 +40,8 @@ public function can_get_next_collection_result_when_next_link_is_available()
])
);

$collection->setResponse($this->response);

$this->assertTrue($collection->hasNext());

$nextPage = $collection->next();
Expand All @@ -47,6 +59,8 @@ public function test_will_return_null_if_no_next_result_is_available()
(object) []
);

$collection->setResponse($this->response);

$this->assertFalse($collection->hasNext());
$this->assertNull($collection->next());
}
Expand All @@ -67,6 +81,8 @@ public function test_can_get_previous_collection_result_when_previous_link_is_av
])
);

$collection->setResponse($this->response);

$this->assertTrue($collection->hasPrevious());

$previousPage = $collection->previous();
Expand All @@ -84,6 +100,8 @@ public function test_will_return_null_if_no_previous_result_is_available()
(object) []
);

$collection->setResponse($this->response);

$this->assertFalse($collection->hasPrevious());
$this->assertNull($collection->previous());
}
Expand All @@ -98,6 +116,8 @@ public function test_auto_paginator_returns_lazy_collection()
(object) []
);

$collection->setResponse($this->response);

$this->assertInstanceOf(LazyCollection::class, $collection->getAutoIterator());
}

Expand All @@ -121,6 +141,8 @@ public function test_auto_paginator_can_handle_consecutive_calls()
])
);

$collection->setResponse($this->response);

$paymentIds = [];
foreach ($collection->getAutoIterator() as $payment) {
$paymentIds[] = $payment->id;
Expand Down
5 changes: 5 additions & 0 deletions tests/Resources/LazyCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Tests\Resources;

use Mollie\Api\Http\Response;
use Mollie\Api\Resources\LazyCollection;
use PHPUnit\Framework\TestCase;

Expand All @@ -21,6 +22,10 @@ protected function setUp(): void
yield 2;
yield 3;
});

$response = $this->createMock(Response::class);

$this->collection->setResponse($response);
}

/** @test */
Expand Down
5 changes: 5 additions & 0 deletions tests/Resources/MandateCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Tests\Resources;

use Mollie\Api\Http\Response;
use Mollie\Api\MollieApiClient;
use Mollie\Api\Resources\Mandate;
use Mollie\Api\Resources\MandateCollection;
Expand Down Expand Up @@ -33,6 +34,10 @@ public function test_where_status()
$this->getMandateWithStatus(MandateStatus::PENDING),
]);

$response = $this->createMock(Response::class);

$collection->setResponse($response);

$valid = $collection->whereStatus(MandateStatus::VALID);
$invalid = $collection->whereStatus(MandateStatus::INVALID);
$pending = $collection->whereStatus(MandateStatus::PENDING);
Expand Down

0 comments on commit 3a8e0da

Please sign in to comment.