diff --git a/lib/ApiOperations/NestedResource.php b/lib/ApiOperations/NestedResource.php index 180cacd2cc..26af8dc307 100644 --- a/lib/ApiOperations/NestedResource.php +++ b/lib/ApiOperations/NestedResource.php @@ -10,7 +10,7 @@ trait NestedResource { /** - * @param string $method + * @param 'delete'|'get'|'post' $method * @param string $url * @param null|array $params * @param null|array|string $options diff --git a/lib/ApiOperations/Request.php b/lib/ApiOperations/Request.php index a60ca796a0..12df3f2b7f 100644 --- a/lib/ApiOperations/Request.php +++ b/lib/ApiOperations/Request.php @@ -27,7 +27,7 @@ protected static function _validateParams($params = null) } /** - * @param string $method HTTP method ('get', 'post', etc.) + * @param 'delete'|'get'|'post' $method HTTP method ('get', 'post', etc.) * @param string $url URL for the request * @param array $params list of parameters for the request * @param null|array|string $options @@ -46,7 +46,7 @@ protected function _request($method, $url, $params = [], $options = null) } /** - * @param string $method HTTP method ('get', 'post', etc.) + * @param 'delete'|'get'|'post' $method HTTP method ('get', 'post', etc.) * @param string $url URL for the request * @param callable $readBodyChunk function that will receive chunks of data from a successful request body * @param array $params list of parameters for the request @@ -61,7 +61,7 @@ protected function _requestStream($method, $url, $readBodyChunk, $params = [], $ } /** - * @param string $method HTTP method ('get', 'post', etc.) + * @param 'delete'|'get'|'post' $method HTTP method ('get', 'post', etc.) * @param string $url URL for the request * @param array $params list of parameters for the request * @param null|array|string $options @@ -82,7 +82,7 @@ protected static function _staticRequest($method, $url, $params, $options) } /** - * @param string $method HTTP method ('get', 'post', etc.) + * @param 'delete'|'get'|'post' $method HTTP method ('get', 'post', etc.) * @param string $url URL for the request * @param callable $readBodyChunk function that will receive chunks of data from a successful request body * @param array $params list of parameters for the request diff --git a/lib/ApiRequestor.php b/lib/ApiRequestor.php index 7162e33b53..89b5bee85d 100644 --- a/lib/ApiRequestor.php +++ b/lib/ApiRequestor.php @@ -106,7 +106,7 @@ private static function _encodeObjects($d) } /** - * @param string $method + * @param 'delete'|'get'|'post' $method * @param string $url * @param null|array $params * @param null|array $headers @@ -128,7 +128,7 @@ public function request($method, $url, $params = null, $headers = null) } /** - * @param string $method + * @param 'delete'|'get'|'post' $method * @param string $url * @param callable $readBodyChunkCallable * @param null|array $params @@ -432,7 +432,7 @@ function ($key) use ($params) { } /** - * @param string $method + * @param 'delete'|'get'|'post' $method * @param string $url * @param array $params * @param array $headers @@ -469,7 +469,7 @@ private function _requestRaw($method, $url, $params, $headers) } /** - * @param string $method + * @param 'delete'|'get'|'post' $method * @param string $url * @param array $params * @param array $headers diff --git a/lib/BaseStripeClient.php b/lib/BaseStripeClient.php index b0b2e7e57b..a2c1d30d87 100644 --- a/lib/BaseStripeClient.php +++ b/lib/BaseStripeClient.php @@ -119,7 +119,7 @@ public function getFilesBase() /** * Sends a request to Stripe's API. * - * @param string $method the HTTP method + * @param 'delete'|'get'|'post' $method the HTTP method * @param string $path the path of the request * @param array $params the parameters of the request * @param array|\Stripe\Util\RequestOptions $opts the special modifiers of the request @@ -143,7 +143,7 @@ public function request($method, $path, $params, $opts) * Sends a request to Stripe's API, passing chunks of the streamed response * into a user-provided $readBodyChunkCallable callback. * - * @param string $method the HTTP method + * @param 'delete'|'get'|'post' $method the HTTP method * @param string $path the path of the request * @param callable $readBodyChunkCallable a function that will be called * @param array $params the parameters of the request @@ -161,7 +161,7 @@ public function requestStream($method, $path, $readBodyChunkCallable, $params, $ /** * Sends a request to Stripe's API. * - * @param string $method the HTTP method + * @param 'delete'|'get'|'post' $method the HTTP method * @param string $path the path of the request * @param array $params the parameters of the request * @param array|\Stripe\Util\RequestOptions $opts the special modifiers of the request @@ -185,7 +185,7 @@ public function requestCollection($method, $path, $params, $opts) /** * Sends a request to Stripe's API. * - * @param string $method the HTTP method + * @param 'delete'|'get'|'post' $method the HTTP method * @param string $path the path of the request * @param array $params the parameters of the request * @param array|\Stripe\Util\RequestOptions $opts the special modifiers of the request diff --git a/lib/HttpClient/ClientInterface.php b/lib/HttpClient/ClientInterface.php index 3c7861e597..6d17eb8ae3 100644 --- a/lib/HttpClient/ClientInterface.php +++ b/lib/HttpClient/ClientInterface.php @@ -5,7 +5,7 @@ interface ClientInterface { /** - * @param string $method The HTTP method being used + * @param 'delete'|'get'|'post' $method The HTTP method being used * @param string $absUrl The URL being requested, including domain and protocol * @param array $headers Headers to be used in the request (full strings, not KV pairs) * @param array $params KV pairs for parameters. Can be nested for arrays and hashes diff --git a/lib/HttpClient/StreamingClientInterface.php b/lib/HttpClient/StreamingClientInterface.php index 482f9a1199..7612c94a6c 100644 --- a/lib/HttpClient/StreamingClientInterface.php +++ b/lib/HttpClient/StreamingClientInterface.php @@ -5,7 +5,7 @@ interface StreamingClientInterface { /** - * @param string $method The HTTP method being used + * @param 'delete'|'get'|'post' $method The HTTP method being used * @param string $absUrl The URL being requested, including domain and protocol * @param array $headers Headers to be used in the request (full strings, not KV pairs) * @param array $params KV pairs for parameters. Can be nested for arrays and hashes diff --git a/lib/Service/OAuthService.php b/lib/Service/OAuthService.php index b745ad9876..3870cccd48 100644 --- a/lib/Service/OAuthService.php +++ b/lib/Service/OAuthService.php @@ -7,7 +7,7 @@ class OAuthService extends \Stripe\Service\AbstractService /** * Sends a request to Stripe's Connect API. * - * @param string $method the HTTP method + * @param 'delete'|'get'|'post' $method the HTTP method * @param string $path the path of the request * @param array $params the parameters of the request * @param array|\Stripe\Util\RequestOptions $opts the special modifiers of the request diff --git a/lib/StripeClientInterface.php b/lib/StripeClientInterface.php index d5a8806ff5..a18308d720 100644 --- a/lib/StripeClientInterface.php +++ b/lib/StripeClientInterface.php @@ -10,7 +10,7 @@ interface StripeClientInterface extends BaseStripeClientInterface /** * Sends a request to Stripe's API. * - * @param string $method the HTTP method + * @param 'delete'|'get'|'post' $method the HTTP method * @param string $path the path of the request * @param array $params the parameters of the request * @param array|\Stripe\Util\RequestOptions $opts the special modifiers of the request diff --git a/phpstan.neon.dist b/phpstan.neon.dist index fb066c682f..983b38e605 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,7 +2,7 @@ includes: - phpstan-baseline.neon parameters: - level: 1 + level: 2 bootstrapFiles: - tests/bootstrap.php diff --git a/tests/Stripe/BaseStripeClientTest.php b/tests/Stripe/BaseStripeClientTest.php index 561af37d0f..775d55b664 100644 --- a/tests/Stripe/BaseStripeClientTest.php +++ b/tests/Stripe/BaseStripeClientTest.php @@ -202,4 +202,133 @@ public function testRequestWithOptsInParamsWarns() static::assertNotNull($charge); static::assertSame('acct_456', $this->optsReflector->getValue($charge)->headers['Stripe-Account']); } + + public function testJsonRawRequestGetWithURLParams() + { + $curlClientStub = $this->getMockBuilder(\Stripe\HttpClient\CurlClient::class) + ->onlyMethods(['executeRequestWithRetries']) + ->getMock() + ; + $curlClientStub->method('executeRequestWithRetries') + ->willReturn(['{}', 200, []]) + ; + + $opts = null; + $curlClientStub->expects(static::once()) + ->method('executeRequestWithRetries') + ->with(static::callback(function ($opts_) use (&$opts) { + $opts = $opts_; + + return true; + }), MOCK_URL . '/v1/xyz?foo=bar') + ; + + ApiRequestor::setHttpClient($curlClientStub); + $client = new BaseStripeClient([ + 'api_key' => 'sk_test_client', + 'stripe_account' => 'acct_123', + 'api_base' => MOCK_URL, + ]); + $client->rawRequest('get', '/v1/xyz?foo=bar', null, []); + static::assertArrayNotHasKey(\CURLOPT_POST, $opts); + static::assertArrayNotHasKey(\CURLOPT_POSTFIELDS, $opts); + $content_type = null; + foreach ($opts[\CURLOPT_HTTPHEADER] as $header) { + if (\str_starts_with($header, 'Content-Type:')) { + $content_type = $header; + } + } + // The library sends Content-Type even with no body, so assert this + // But it would be more correct to not send Content-Type + static::assertStringStartsWith('Content-Type: application/x-www-form-urlencoded', $content_type); + } + + public function testJsonRawRequestPost() + { + $curlClientStub = $this->getMockBuilder(\Stripe\HttpClient\CurlClient::class) + ->onlyMethods(['executeRequestWithRetries']) + ->getMock() + ; + $curlClientStub->method('executeRequestWithRetries') + ->willReturn(['{"object": "xyz", "isPHPBestLanguage": true, "abc": {"object": "abc", "a": 2}}', 200, []]) + ; + + $curlClientStub->expects(static::once()) + ->method('executeRequestWithRetries') + ->with(static::callback(function ($opts) { + $this->assertSame(1, $opts[\CURLOPT_POST]); + $this->assertSame('{"foo":"bar","baz":{"qux":false}}', $opts[\CURLOPT_POSTFIELDS]); + $this->assertContains('Content-Type: application/json', $opts[\CURLOPT_HTTPHEADER]); + + return true; + }), MOCK_URL . '/v1/xyz') + ; + + ApiRequestor::setHttpClient($curlClientStub); + $client = new BaseStripeClient([ + 'api_key' => 'sk_test_client', + 'stripe_account' => 'acct_123', + 'api_base' => MOCK_URL, + ]); + $params = ['foo' => 'bar', 'baz' => ['qux' => false]]; + $resp = $client->rawRequest('post', '/v1/xyz', $params, [ + 'encoding' => 'json', + ]); + + $decoded = \json_decode($resp->body, true); + $xyz = \Stripe\StripeObject::constructFrom($decoded); + + static::assertSame('xyz', $xyz->object); + static::assertTrue($xyz->isPHPBestLanguage); + static::assertSame(2, $xyz->abc->a); + static::assertInstanceof(\Stripe\StripeObject::class, $xyz->abc); + } + + public function testFormRawRequestPost() + { + $curlClientStub = $this->getMockBuilder(\Stripe\HttpClient\CurlClient::class) + ->onlyMethods(['executeRequestWithRetries']) + ->getMock() + ; + $curlClientStub->method('executeRequestWithRetries') + ->willReturn(['{}', 200, []]) + ; + + $curlClientStub->expects(static::once()) + ->method('executeRequestWithRetries') + ->with(static::callback(function ($opts) { + $this->assertSame(1, $opts[\CURLOPT_POST]); + $this->assertSame('foo=bar&baz[qux]=false', $opts[\CURLOPT_POSTFIELDS]); + $this->assertContains('Content-Type: application/x-www-form-urlencoded', $opts[\CURLOPT_HTTPHEADER]); + + return true; + }), MOCK_URL . '/v1/xyz') + ; + + ApiRequestor::setHttpClient($curlClientStub); + $client = new BaseStripeClient([ + 'api_key' => 'sk_test_client', + 'stripe_account' => 'acct_123', + 'api_base' => MOCK_URL, + ]); + $params = ['foo' => 'bar', 'baz' => ['qux' => false]]; + $client->rawRequest('post', '/v1/xyz', $params, [ + 'encoding' => 'form', + ]); + } + + public function testJsonRawRequestGetWithNonNullParams() + { + $client = new BaseStripeClient([ + 'api_key' => 'sk_test_client', + 'stripe_account' => 'acct_123', + 'api_base' => MOCK_URL, + ]); + $params = []; + $this->expectException(\Stripe\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Error: rawRequest only supports $params on post requests. Please pass null and add your parameters to $path'); + $client->rawRequest('get', '/v1/xyz', $params, [ + 'encoding' => 'json', + ]); + } } diff --git a/tests/TestHelper.php b/tests/TestHelper.php index 350608f2d4..95e4ec64bc 100644 --- a/tests/TestHelper.php +++ b/tests/TestHelper.php @@ -71,7 +71,7 @@ protected function tearDownConfig() * Sets up a request expectation with the provided parameters. The request * will actually go through and be emitted. * - * @param string $method HTTP method (e.g. 'post', 'get', etc.) + * @param 'delete'|'get'|'post' $method HTTP method (e.g. 'post', 'get', etc.) * @param string $path relative path (e.g. '/v1/charges') * @param null|array $params array of parameters. If null, parameters will * not be checked. @@ -106,7 +106,7 @@ function ($method, $absUrl, $headers, $params, $hasFile) { * Sets up a request expectation with the provided parameters. The request * will actually go through and be emitted. * - * @param string $method HTTP method (e.g. 'post', 'get', etc.) + * @param 'delete'|'get'|'post' $method HTTP method (e.g. 'post', 'get', etc.) * @param string $path relative path (e.g. '/v1/charges') * @param null|array $params array of parameters. If null, parameters will * not be checked. @@ -142,7 +142,7 @@ function ($method, $absUrl, $readBodyChunkCallable, $headers, $params, $hasFile) * will not actually be emitted, instead the provided response parameters * will be returned. * - * @param string $method HTTP method (e.g. 'post', 'get', etc.) + * @param 'delete'|'get'|'post' $method HTTP method (e.g. 'post', 'get', etc.) * @param string $path relative path (e.g. '/v1/charges') * @param null|array $params array of parameters. If null, parameters will * not be checked. @@ -175,7 +175,7 @@ protected function stubRequest( * prepare the client mocker to expect an invocation of the `request` method * with the provided arguments. * - * @param string $method HTTP method (e.g. 'post', 'get', etc.) + * @param 'delete'|'get'|'post' $method HTTP method (e.g. 'post', 'get', etc.) * @param string $path relative path (e.g. '/v1/charges') * @param null|array $params array of parameters. If null, parameters will * not be checked. @@ -231,7 +231,7 @@ private function prepareRequestMock( * prepare the client mocker to expect an invocation of the `request` method * with the provided arguments. * - * @param string $method HTTP method (e.g. 'post', 'get', etc.) + * @param 'delete'|'get'|'post' $method HTTP method (e.g. 'post', 'get', etc.) * @param string $path relative path (e.g. '/v1/charges') * @param null|array $params array of parameters. If null, parameters will * not be checked.