From 593a3080c4161bb3e192d99182a84f5ee9a9328b Mon Sep 17 00:00:00 2001 From: Krishan Koenig Date: Tue, 18 Feb 2025 14:46:50 +0100 Subject: [PATCH] fix: accessing related resource collections --- phpstan-baseline.neon | 12 +++++++-- src/Contracts/IsResponseAware.php | 5 +++- src/Fake/ResourceResponseBuilder.php | 24 +++++++---------- src/Resources/Client.php | 2 +- src/Resources/Payment.php | 10 ++++---- src/Resources/PaymentLink.php | 30 +++++++--------------- src/Resources/Profile.php | 8 +++--- src/Resources/ResourceCollection.php | 13 ++++++++++ src/Resources/Subscription.php | 2 +- src/Traits/HasResponse.php | 5 +++- tests/Fake/ResourceResponseBuilderTest.php | 1 + tests/Resources/ResourceFactoryTest.php | 4 +-- 12 files changed, 62 insertions(+), 54 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 8ccc12f5..5e62612d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7,12 +7,14 @@ parameters: path: examples/capabilities/get-capability.php - - message: "#^Variable \\$mollie might not be defined\\.$#" + message: '#^Variable \$mollie might not be defined\.$#' + identifier: variable.undefined count: 1 path: examples/capabilities/list-capabilities.php - - message: "#^Variable \\$mollie might not be defined\\.$#" + message: '#^Variable \$mollie might not be defined\.$#' + identifier: variable.undefined count: 1 path: examples/captures/create-capture.php @@ -292,6 +294,12 @@ parameters: count: 5 path: src/Http/Data/DataCollection.php + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 1 + path: src/Resources/ResourceCollection.php + - message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' identifier: method.alreadyNarrowedType diff --git a/src/Contracts/IsResponseAware.php b/src/Contracts/IsResponseAware.php index d77955a5..fe8c025d 100644 --- a/src/Contracts/IsResponseAware.php +++ b/src/Contracts/IsResponseAware.php @@ -8,5 +8,8 @@ interface IsResponseAware extends ViableResponse { public function getResponse(): Response; - public function setResponse(Response $response): self; + /** + * @return $this + */ + public function setResponse(Response $response); } diff --git a/src/Fake/ResourceResponseBuilder.php b/src/Fake/ResourceResponseBuilder.php index 2ae3e108..920c3189 100644 --- a/src/Fake/ResourceResponseBuilder.php +++ b/src/Fake/ResourceResponseBuilder.php @@ -5,11 +5,14 @@ use Mollie\Api\Exceptions\LogicException; use Mollie\Api\Resources\BaseResource; use Mollie\Api\Traits\ForwardsCalls; +use ReflectionClass; /** * Builder for creating mock responses for Mollie API resources. * * @method self embed(string $collectionClass) Embed a collection of resources into the response + * @method self add(array $data) Add a resource to the embedded response + * @method self addMany(array $data) Add multiple resources to the embedded response */ class ResourceResponseBuilder { @@ -49,7 +52,12 @@ public function with(array $data): self */ public function create(): MockResponse { - $data = $this->data; + $reflection = new ReflectionClass($this->resourceClass); + $baseName = strtolower($reflection->getShortName()); + + $sampleContents = json_decode(FakeResponseLoader::load($baseName), true); + + $data = array_merge(['_links' => $sampleContents['_links']], $this->data); $data['_embedded'] = []; foreach ($this->embeddedBuilders as $key => $builder) { @@ -63,20 +71,6 @@ public function create(): MockResponse unset($data['_embedded']); } - // add standard links - if (empty($data['_links'])) { - $data['_links'] = [ - 'self' => [ - 'href' => '...', - 'type' => 'application/hal+json', - ], - 'documentation' => [ - 'href' => '...', - 'type' => 'text/html', - ], - ]; - } - return new MockResponse($data); } diff --git a/src/Resources/Client.php b/src/Resources/Client.php index 958a03d3..08c43b4c 100644 --- a/src/Resources/Client.php +++ b/src/Resources/Client.php @@ -31,7 +31,7 @@ class Client extends BaseResource implements EmbeddedResourcesContract public $_links; /** - * @var \stdClass[] + * @var \stdClass */ public $_embedded; diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 92eab836..8ec6171d 100644 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -295,7 +295,7 @@ class Payment extends BaseResource implements EmbeddedResourcesContract public $_links; /** - * @var \stdClass[] + * @var \stdClass */ public $_embedded; @@ -594,7 +594,7 @@ public function hasSplitPayments(): bool public function refunds(): RefundCollection { if (! isset($this->_links->refunds->href)) { - return new RefundCollection($this->connector, $this->response); + return RefundCollection::withResponse($this->response, $this->connector); } return $this @@ -636,7 +636,7 @@ public function listRefunds(array $parameters = []): RefundCollection public function captures(): CaptureCollection { if (! isset($this->_links->captures->href)) { - return new CaptureCollection($this->connector, $this->response); + return CaptureCollection::withResponse($this->response, $this->connector); } return $this @@ -667,7 +667,7 @@ public function getCapture($captureId, array $parameters = []): Capture public function chargebacks(): ChargebackCollection { if (! isset($this->_links->chargebacks->href)) { - return new ChargebackCollection($this->connector, $this->response); + return ChargebackCollection::withResponse($this->response, $this->connector); } return $this @@ -720,7 +720,7 @@ public function update(): Payment $this->redirectUrl, $this->cancelUrl, $this->webhookUrl, - new Metadata($this->metadata), + new Metadata((array) $this->metadata), $this->method, $this->locale, $this->restrictPaymentMethodsToCountry, diff --git a/src/Resources/PaymentLink.php b/src/Resources/PaymentLink.php index 397de6c1..1dfe11e7 100644 --- a/src/Resources/PaymentLink.php +++ b/src/Resources/PaymentLink.php @@ -2,11 +2,15 @@ namespace Mollie\Api\Resources; +use Mollie\Api\Traits\HasMode; + /** * @property \Mollie\Api\MollieApiClient $connector */ class PaymentLink extends BaseResource { + use HasMode; + /** * Id of the payment link (on the Mollie platform). * @@ -136,12 +140,10 @@ public function getCheckoutUrl(): ?string */ public function update(): ?PaymentLink { - $body = $this->withTestmode([ + return $this->connector->paymentLinks->update($this->id, $this->withMode([ 'description' => $this->description, 'archived' => $this->archived, - ]); - - return $this->connector->paymentLinks->update($this->id, $body); + ])); } /** @@ -153,11 +155,9 @@ public function update(): ?PaymentLink */ public function archive() { - $data = $this->withTestmode([ + return $this->connector->paymentLinks->update($this->id, $this->withMode([ 'archived' => true, - ]); - - return $this->connector->paymentLinks->update($this->id, $data); + ])); } /** @@ -171,19 +171,7 @@ public function payments(?string $from = null, ?int $limit = null, array $filter $this, $from, $limit, - $this->withTestmode($filters) + $this->withMode($filters) ); } - - /** - * Apply the preset options. - * - * @return array - */ - private function withTestmode(array $options) - { - return array_merge([ - 'testmode' => $this->mode === 'test', - ], $options); - } } diff --git a/src/Resources/Profile.php b/src/Resources/Profile.php index e4ab49c5..33631df0 100644 --- a/src/Resources/Profile.php +++ b/src/Resources/Profile.php @@ -124,7 +124,7 @@ public function update(): ?Profile public function chargebacks(): ChargebackCollection { if (! isset($this->_links->chargebacks->href)) { - return new ChargebackCollection($this->connector, $this->response); + return ChargebackCollection::withResponse($this->response, $this->connector); } return $this @@ -140,7 +140,7 @@ public function chargebacks(): ChargebackCollection public function methods(): MethodCollection { if (! isset($this->_links->methods->href)) { - return new MethodCollection($this->connector, $this->response); + return MethodCollection::withResponse($this->response, $this->connector); } return $this @@ -178,7 +178,7 @@ public function disableMethod(string $methodId): void public function payments(): PaymentCollection { if (! isset($this->_links->payments->href)) { - return new PaymentCollection($this->connector, $this->response); + return PaymentCollection::withResponse($this->response, $this->connector); } return $this @@ -194,7 +194,7 @@ public function payments(): PaymentCollection public function refunds(): RefundCollection { if (! isset($this->_links->refunds->href)) { - return new RefundCollection($this->connector, $this->response); + return RefundCollection::withResponse($this->response, $this->connector); } return $this diff --git a/src/Resources/ResourceCollection.php b/src/Resources/ResourceCollection.php index d7dba9a5..d305abef 100644 --- a/src/Resources/ResourceCollection.php +++ b/src/Resources/ResourceCollection.php @@ -2,6 +2,9 @@ namespace Mollie\Api\Resources; +use Mollie\Api\Contracts\Connector; +use Mollie\Api\Http\Response; + abstract class ResourceCollection extends BaseCollection { /** @@ -17,4 +20,14 @@ public static function getResourceClass(): string return static::$resource; } + + /** + * @return $this + */ + public static function withResponse(Response $response, Connector $connector, $items = [], ?\stdClass $_links = null): self + { + $collection = new static($connector, $items, $_links); + + return $collection->setResponse($response); + } } diff --git a/src/Resources/Subscription.php b/src/Resources/Subscription.php index 1066f97d..98d8321b 100644 --- a/src/Resources/Subscription.php +++ b/src/Resources/Subscription.php @@ -199,7 +199,7 @@ public function cancel(): ?Subscription public function payments(): PaymentCollection { if (! isset($this->_links->payments->href)) { - return new PaymentCollection($this->connector, $this->response); + return PaymentCollection::withResponse($this->response, $this->connector); } return $this diff --git a/src/Traits/HasResponse.php b/src/Traits/HasResponse.php index bf867b30..773c0740 100644 --- a/src/Traits/HasResponse.php +++ b/src/Traits/HasResponse.php @@ -14,7 +14,10 @@ public function getResponse(): Response return $this->response; } - public function setResponse(Response $response): self + /** + * @return $this + */ + public function setResponse(Response $response) { $this->response = $response; diff --git a/tests/Fake/ResourceResponseBuilderTest.php b/tests/Fake/ResourceResponseBuilderTest.php index bc039164..5c411577 100644 --- a/tests/Fake/ResourceResponseBuilderTest.php +++ b/tests/Fake/ResourceResponseBuilderTest.php @@ -253,6 +253,7 @@ public function it_throws_an_exception_when_calling_undefined_methods() $this->expectException(\BadMethodCallException::class); $this->expectExceptionMessage('Method undefinedMethod does not exist'); + /** @phpstan-ignore-next-line */ $builder->undefinedMethod(); } diff --git a/tests/Resources/ResourceFactoryTest.php b/tests/Resources/ResourceFactoryTest.php index 060664f6..121adb51 100644 --- a/tests/Resources/ResourceFactoryTest.php +++ b/tests/Resources/ResourceFactoryTest.php @@ -81,8 +81,7 @@ public function embedded_collections_are_type_casted() ); $this->assertInstanceOf(Payment::class, $payment); - /** @phpstan-ignore-next-line */ - $this->assertInstanceOf(RefundCollection::class, $payment->_embedded->refunds); + $this->assertInstanceOf(RefundCollection::class, $payment->refunds()); } /** @test */ @@ -121,7 +120,6 @@ public function embedded_resources_are_type_casted() ); $this->assertInstanceOf(Client::class, $client); - /** @phpstan-ignore-next-line */ $this->assertInstanceOf(Onboarding::class, $client->_embedded->onboarding); }