From 61baaaa88232ba4296e6fff9c4395dc618132245 Mon Sep 17 00:00:00 2001 From: Masoud Amini Date: Sun, 9 Oct 2022 13:12:57 +0330 Subject: [PATCH 01/23] Create README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e968b96 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +[![Build Status](https://travis-ci.org/ZarinPal/zarinpal-php-sdk.svg?branch=master)](https://travis-ci.org/morilog/jalali) +morilog/jalali +====== +## Installation* +#### Requirements: +- `php >= 7.4` + +Run the Composer update command + + $ composer require zarinpal/zarinpal-php-sdk From 660c8e3bab72a49aa28bf361a950f9cf50e6e247 Mon Sep 17 00:00:00 2001 From: Masoud Amini Date: Sun, 9 Oct 2022 13:13:17 +0330 Subject: [PATCH 02/23] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e968b96..4842974 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://travis-ci.org/ZarinPal/zarinpal-php-sdk.svg?branch=master)](https://travis-ci.org/morilog/jalali) -morilog/jalali +[![Build Status](https://travis-ci.org/ZarinPal/zarinpal-php-sdk.svg?branch=master)](https://travis-ci.org/ZarinPal/zarinpal-php-sdk) +ZarinPal/zarinpal-php-sdk ====== ## Installation* #### Requirements: From 1c6a9e5c32c31272dd9f5189a374b4f125abb4b3 Mon Sep 17 00:00:00 2001 From: Masoud Amini Date: Sun, 9 Oct 2022 13:43:24 +0330 Subject: [PATCH 03/23] add sr/http-client-implementation --- composer.json | 3 +- composer.lock | 138 +++++++++++++++++++++++++------------------------- 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/composer.json b/composer.json index d4114ff..b9e0354 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "psr/http-client": "^1.0", "php-http/client-common": "^2.5", "php-http/discovery": "^1.14", - "ext-json": "*" + "ext-json": "*", + "psr/http-client-implementation": "*" }, "require-dev": { "php-http/curl-client": "^2.2", diff --git a/composer.lock b/composer.lock index fde0eaa..efca38c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ccb3b1cdf791a18a23c8efc7c650bb08", + "content-hash": "99e1b66ec6405ef7248535a7f99e2662", "packages": [ { "name": "clue/stream-filter", @@ -404,6 +404,74 @@ }, "time": "2015-12-19T14:08:53+00:00" }, + { + "name": "php-http/mock-client", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/mock-client.git", + "reference": "a797c2a9122cccafcce14773b8a24d2808a9ab44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/mock-client/zipball/a797c2a9122cccafcce14773b8a24d2808a9ab44", + "reference": "a797c2a9122cccafcce14773b8a24d2808a9ab44", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "php-http/client-common": "^2.0", + "php-http/discovery": "^1.0", + "php-http/httplug": "^2.0", + "php-http/message-factory": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "symfony/polyfill-php80": "^1.17" + }, + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0", + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "phpspec/phpspec": "^5.1 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Mock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David de Boer", + "email": "david@ddeboer.nl" + } + ], + "description": "Mock HTTP client", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "http", + "mock", + "psr7" + ], + "support": { + "issues": "https://github.com/php-http/mock-client/issues", + "source": "https://github.com/php-http/mock-client/tree/1.5.0" + }, + "time": "2021-08-25T07:01:14+00:00" + }, { "name": "php-http/promise", "version": "1.1.0", @@ -1302,74 +1370,6 @@ }, "time": "2021-12-10T18:02:07+00:00" }, - { - "name": "php-http/mock-client", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/mock-client.git", - "reference": "a797c2a9122cccafcce14773b8a24d2808a9ab44" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/mock-client/zipball/a797c2a9122cccafcce14773b8a24d2808a9ab44", - "reference": "a797c2a9122cccafcce14773b8a24d2808a9ab44", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "php-http/client-common": "^2.0", - "php-http/discovery": "^1.0", - "php-http/httplug": "^2.0", - "php-http/message-factory": "^1.0", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "symfony/polyfill-php80": "^1.17" - }, - "provide": { - "php-http/async-client-implementation": "1.0", - "php-http/client-implementation": "1.0", - "psr/http-client-implementation": "1.0" - }, - "require-dev": { - "phpspec/phpspec": "^5.1 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Http\\Mock\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "David de Boer", - "email": "david@ddeboer.nl" - } - ], - "description": "Mock HTTP client", - "homepage": "http://httplug.io", - "keywords": [ - "client", - "http", - "mock", - "psr7" - ], - "support": { - "issues": "https://github.com/php-http/mock-client/issues", - "source": "https://github.com/php-http/mock-client/tree/1.5.0" - }, - "time": "2021-08-25T07:01:14+00:00" - }, { "name": "phpstan/phpstan", "version": "1.8.6", From d8b191e00c1559d467b513e862999d66888da2c7 Mon Sep 17 00:00:00 2001 From: Masoud Amini Date: Sun, 9 Oct 2022 13:46:16 +0330 Subject: [PATCH 04/23] Update Options.php --- src/Options.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Options.php b/src/Options.php index 9f40201..f841379 100644 --- a/src/Options.php +++ b/src/Options.php @@ -28,7 +28,7 @@ private function configureOptions(OptionsResolver $resolver): void [ 'client_builder' => new ClientBuilder(), 'uri_factory' => Psr17FactoryDiscovery::findUriFactory(), - 'base_url' => $this->arrayGet(getenv(), 'ZARINPAL_MERCHANT_URL', 'https://api.zarinpal.com/'), + 'base_url' => $this->arrayGet(getenv(), 'ZARINPAL_MERCHANT_URL', 'https://api.zarinpal.com'), 'merchant_id' => $this->arrayGet(getenv(), 'ZARINPAL_MERCHANT_KEY', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') ] ); From ac7661a56e9539ddb82ecf5e9ae108b120b8d3b5 Mon Sep 17 00:00:00 2001 From: Masoud Amini Date: Sun, 9 Oct 2022 13:46:20 +0330 Subject: [PATCH 05/23] Update PaymentGateway.php --- src/Endpoint/PaymentGateway/PaymentGateway.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Endpoint/PaymentGateway/PaymentGateway.php b/src/Endpoint/PaymentGateway/PaymentGateway.php index 82bd6a2..3f56e01 100644 --- a/src/Endpoint/PaymentGateway/PaymentGateway.php +++ b/src/Endpoint/PaymentGateway/PaymentGateway.php @@ -17,7 +17,7 @@ final class PaymentGateway { - private const BASE_URL = 'pg/v4/payment/'; + private const BASE_URL = '/pg/v4/payment/'; private const REQUEST_URI = self::BASE_URL . 'request.json'; private const VERIFY_URI = self::BASE_URL . 'verify.json'; private const UNVERIFIED_URI = self::BASE_URL . 'unVerified.json'; @@ -68,6 +68,8 @@ private function httpHandler(string $uri, string $body): array throw new ResponseException($e->getMessage(), -99, $e); } + //die(print_r($response)); + return $this->checkPaymentGatewayError($response); } From d64b9b070066121277acce01cbc89ea955e69b2d Mon Sep 17 00:00:00 2001 From: Masoud Amini Date: Sun, 9 Oct 2022 13:46:34 +0330 Subject: [PATCH 06/23] Update PaymentGateway.php --- src/Endpoint/PaymentGateway/PaymentGateway.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Endpoint/PaymentGateway/PaymentGateway.php b/src/Endpoint/PaymentGateway/PaymentGateway.php index 3f56e01..dda6ba8 100644 --- a/src/Endpoint/PaymentGateway/PaymentGateway.php +++ b/src/Endpoint/PaymentGateway/PaymentGateway.php @@ -67,9 +67,7 @@ private function httpHandler(string $uri, string $body): array } catch (Exception $e) { throw new ResponseException($e->getMessage(), -99, $e); } - - //die(print_r($response)); - + return $this->checkPaymentGatewayError($response); } From fb60034e0244955b62c9ac9232a98946b98aef08 Mon Sep 17 00:00:00 2001 From: Masoud Amini Date: Mon, 10 Oct 2022 13:59:22 +0330 Subject: [PATCH 07/23] Create .gitattributes --- .gitattributes | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff64aa --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +docs/* export-ignore +examples/* export-ignore +composer.lock export-ignore +README.md export-ignore \ No newline at end of file From 443f9f5c7b783ba1c5a1d5ba439911190edfa7e8 Mon Sep 17 00:00:00 2001 From: Armin Zahedi <00001212aa@gmail.com> Date: Sat, 7 Sep 2024 11:01:00 +0330 Subject: [PATCH 08/23] V-2 --- .gitattributes => .gitattributes | 0 composer.json | 16 +- composer.lock | 1539 ++++++++++++----- examples/Inquiry.php | 26 + examples/Refund.php | 32 + examples/Request.php | 31 + examples/Reverse.php | 24 + examples/Transaction.php | 30 + examples/Verify.php | 27 + examples/basic-client.php | 37 +- examples/basic-client2.php | 28 + src/Endpoint/GraphQL/RefundService.php | 49 + .../GraphQL/RequestTypes/RefundRequest.php | 69 + .../RequestTypes/TransactionListRequest.php | 77 + .../GraphQL/ResponseTypes/RefundResponse.php | 23 + .../ResponseTypes/TransactionListResponse.php | 25 + src/Endpoint/GraphQL/TransactionService.php | 53 + .../PaymentGateway/PaymentGateway.php | 132 +- .../RequestTypes/InquiryRequest.php | 50 + .../RequestTypes/RequestRequest.php | 107 +- .../RequestTypes/ReverseRequest.php | 50 + .../RequestTypes/UnverifiedRequest.php | 20 +- .../RequestTypes/VerifyRequest.php | 34 +- .../ResponseTypes/RequestResponse.php | 2 + .../ResponseTypes/UnverifiedResponse.php | 1 + src/Options.php | 42 +- src/ZarinPal.php | 16 +- tests/BaseTestCase.php | 34 + tests/Graphql/GraphQLRefundTest.php | 44 + tests/Graphql/TransactionServiceTest.php | 62 + tests/PaymentGateway/PaymentGatewayTest.php | 140 ++ 31 files changed, 2283 insertions(+), 537 deletions(-) rename .gitattributes => .gitattributes (100%) create mode 100644 examples/Inquiry.php create mode 100644 examples/Refund.php create mode 100644 examples/Request.php create mode 100644 examples/Reverse.php create mode 100644 examples/Transaction.php create mode 100644 examples/Verify.php create mode 100644 examples/basic-client2.php create mode 100644 src/Endpoint/GraphQL/RefundService.php create mode 100644 src/Endpoint/GraphQL/RequestTypes/RefundRequest.php create mode 100644 src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php create mode 100644 src/Endpoint/GraphQL/ResponseTypes/RefundResponse.php create mode 100644 src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php create mode 100644 src/Endpoint/GraphQL/TransactionService.php create mode 100644 src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php create mode 100644 src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php create mode 100644 tests/BaseTestCase.php create mode 100644 tests/Graphql/GraphQLRefundTest.php create mode 100644 tests/Graphql/TransactionServiceTest.php create mode 100644 tests/PaymentGateway/PaymentGatewayTest.php diff --git a/.gitattributes b/.gitattributes similarity index 100% rename from .gitattributes rename to .gitattributes diff --git a/composer.json b/composer.json index b9e0354..b65427d 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,12 @@ "license": "MIT", "autoload": { "psr-4": { - "ZarinPal\\Sdk\\": "src" + "ZarinPal\\Sdk\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" } }, "authors": [ @@ -26,7 +31,9 @@ "php-http/client-common": "^2.5", "php-http/discovery": "^1.14", "ext-json": "*", - "psr/http-client-implementation": "*" + "psr/http-client-implementation": "*", + "symfony/http-client": "^7.1", + "guzzlehttp/guzzle": "^7.9" }, "require-dev": { "php-http/curl-client": "^2.2", @@ -34,5 +41,10 @@ "phpstan/phpstan": "^1.8", "phpunit/phpunit": "^9", "php-http/mock-client": "^1.5" + }, + "config": { + "allow-plugins": { + "php-http/discovery": true + } } } diff --git a/composer.lock b/composer.lock index efca38c..7692dba 100644 --- a/composer.lock +++ b/composer.lock @@ -4,27 +4,27 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "99e1b66ec6405ef7248535a7f99e2662", + "content-hash": "6fb28754c98b5675132beb8d0b401b05", "packages": [ { "name": "clue/stream-filter", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/clue/stream-filter.git", - "reference": "d6169430c7731d8509da7aecd0af756a5747b78e" + "reference": "049509fef80032cb3f051595029ab75b49a3c2f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/clue/stream-filter/zipball/d6169430c7731d8509da7aecd0af756a5747b78e", - "reference": "d6169430c7731d8509da7aecd0af756a5747b78e", + "url": "https://api.github.com/repos/clue/stream-filter/zipball/049509fef80032cb3f051595029ab75b49a3c2f7", + "reference": "049509fef80032cb3f051595029ab75b49a3c2f7", "shasum": "" }, "require": { "php": ">=5.3" }, "require-dev": { - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36" + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" }, "type": "library", "autoload": { @@ -46,7 +46,7 @@ } ], "description": "A simple and modern approach to stream filtering in PHP", - "homepage": "https://github.com/clue/php-stream-filter", + "homepage": "https://github.com/clue/stream-filter", "keywords": [ "bucket brigade", "callback", @@ -58,7 +58,7 @@ ], "support": { "issues": "https://github.com/clue/stream-filter/issues", - "source": "https://github.com/clue/stream-filter/tree/v1.6.0" + "source": "https://github.com/clue/stream-filter/tree/v1.7.0" }, "funding": [ { @@ -70,31 +70,355 @@ "type": "github" } ], - "time": "2022-02-21T13:15:14+00:00" + "time": "2023-12-20T15:40:13+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2024-07-18T10:29:17+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" }, { "name": "php-http/client-common", - "version": "2.6.0", + "version": "2.7.1", "source": { "type": "git", "url": "https://github.com/php-http/client-common.git", - "reference": "45db684cd4e186dcdc2b9c06b22970fe123796c0" + "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/client-common/zipball/45db684cd4e186dcdc2b9c06b22970fe123796c0", - "reference": "45db684cd4e186dcdc2b9c06b22970fe123796c0", + "url": "https://api.github.com/repos/php-http/client-common/zipball/1e19c059b0e4d5f717bf5d524d616165aeab0612", + "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", "php-http/httplug": "^2.0", "php-http/message": "^1.6", - "php-http/message-factory": "^1.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0", + "psr/http-message": "^1.0 || ^2.0", + "symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0 || ^7.0", "symfony/polyfill-php80": "^1.17" }, "require-dev": { @@ -103,7 +427,7 @@ "nyholm/psr7": "^1.2", "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", "phpspec/prophecy": "^1.10.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3" + "phpunit/phpunit": "^7.5.20 || ^8.5.33 || ^9.6.7" }, "suggest": { "ext-json": "To detect JSON responses with the ContentTypePlugin", @@ -113,11 +437,6 @@ "php-http/stopwatch-plugin": "Symfony Stopwatch plugin" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3.x-dev" - } - }, "autoload": { "psr-4": { "Http\\Client\\Common\\": "src/" @@ -143,49 +462,60 @@ ], "support": { "issues": "https://github.com/php-http/client-common/issues", - "source": "https://github.com/php-http/client-common/tree/2.6.0" + "source": "https://github.com/php-http/client-common/tree/2.7.1" }, - "time": "2022-09-29T09:59:43+00:00" + "time": "2023-11-30T10:31:25+00:00" }, { "name": "php-http/discovery", - "version": "1.14.3", + "version": "1.19.4", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735" + "reference": "0700efda8d7526335132360167315fdab3aeb599" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/31d8ee46d0215108df16a8527c7438e96a4d7735", - "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735", + "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599", + "reference": "0700efda8d7526335132360167315fdab3aeb599", "shasum": "" }, "require": { + "composer-plugin-api": "^1.0|^2.0", "php": "^7.1 || ^8.0" }, "conflict": { - "nyholm/psr7": "<1.0" + "nyholm/psr7": "<1.0", + "zendframework/zend-diactoros": "*" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "*", + "psr/http-factory-implementation": "*", + "psr/http-message-implementation": "*" }, "require-dev": { + "composer/composer": "^1.0.2|^2.0", "graham-campbell/phpspec-skip-example-extension": "^5.0", "php-http/httplug": "^1.0 || ^2.0", "php-http/message-factory": "^1.0", - "phpspec/phpspec": "^5.1 || ^6.1" + "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", + "sebastian/comparator": "^3.0.5 || ^4.0.8", + "symfony/phpunit-bridge": "^6.4.4 || ^7.0.1" }, - "suggest": { - "php-http/message": "Allow to use Guzzle, Diactoros or Slim Framework factories" - }, - "type": "library", + "type": "composer-plugin", "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } + "class": "Http\\Discovery\\Composer\\Plugin", + "plugin-optional": true }, "autoload": { "psr-4": { "Http\\Discovery\\": "src/" - } + }, + "exclude-from-classmap": [ + "src/Composer/Plugin.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -197,7 +527,7 @@ "email": "mark.sagikazar@gmail.com" } ], - "description": "Finds installed HTTPlug implementations and PSR-7 message factories", + "description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations", "homepage": "http://php-http.org", "keywords": [ "adapter", @@ -206,44 +536,40 @@ "factory", "http", "message", + "psr17", "psr7" ], "support": { "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.14.3" + "source": "https://github.com/php-http/discovery/tree/1.19.4" }, - "time": "2022-07-11T14:04:40+00:00" + "time": "2024-03-29T13:00:05+00:00" }, { "name": "php-http/httplug", - "version": "2.3.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/php-http/httplug.git", - "reference": "f640739f80dfa1152533976e3c112477f69274eb" + "reference": "625ad742c360c8ac580fcc647a1541d29e257f67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/httplug/zipball/f640739f80dfa1152533976e3c112477f69274eb", - "reference": "f640739f80dfa1152533976e3c112477f69274eb", + "url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67", + "reference": "625ad742c360c8ac580fcc647a1541d29e257f67", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", "php-http/promise": "^1.1", "psr/http-client": "^1.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.1", - "phpspec/phpspec": "^5.1 || ^6.0" + "friends-of-phpspec/phpspec-code-coverage": "^4.1 || ^5.0 || ^6.0", + "phpspec/phpspec": "^5.1 || ^6.0 || ^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, "autoload": { "psr-4": { "Http\\Client\\": "src/" @@ -272,29 +598,28 @@ ], "support": { "issues": "https://github.com/php-http/httplug/issues", - "source": "https://github.com/php-http/httplug/tree/2.3.0" + "source": "https://github.com/php-http/httplug/tree/2.4.0" }, - "time": "2022-02-21T09:52:22+00:00" + "time": "2023-04-14T15:10:03+00:00" }, { "name": "php-http/message", - "version": "1.13.0", + "version": "1.16.1", "source": { "type": "git", "url": "https://github.com/php-http/message.git", - "reference": "7886e647a30a966a1a8d1dad1845b71ca8678361" + "reference": "5997f3289332c699fa2545c427826272498a2088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/message/zipball/7886e647a30a966a1a8d1dad1845b71ca8678361", - "reference": "7886e647a30a966a1a8d1dad1845b71ca8678361", + "url": "https://api.github.com/repos/php-http/message/zipball/5997f3289332c699fa2545c427826272498a2088", + "reference": "5997f3289332c699fa2545c427826272498a2088", "shasum": "" }, "require": { "clue/stream-filter": "^1.5", - "php": "^7.1 || ^8.0", - "php-http/message-factory": "^1.0.2", - "psr/http-message": "^1.0" + "php": "^7.2 || ^8.0", + "psr/http-message": "^1.1 || ^2.0" }, "provide": { "php-http/message-factory-implementation": "1.0" @@ -302,8 +627,9 @@ "require-dev": { "ergebnis/composer-normalize": "^2.6", "ext-zlib": "*", - "guzzlehttp/psr7": "^1.0", - "laminas/laminas-diactoros": "^2.0", + "guzzlehttp/psr7": "^1.0 || ^2.0", + "laminas/laminas-diactoros": "^2.0 || ^3.0", + "php-http/message-factory": "^1.0.2", "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", "slim/slim": "^3.0" }, @@ -314,11 +640,6 @@ "slim/slim": "Used with Slim Framework PSR-7 implementation" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, "autoload": { "files": [ "src/filters.php" @@ -346,37 +667,35 @@ ], "support": { "issues": "https://github.com/php-http/message/issues", - "source": "https://github.com/php-http/message/tree/1.13.0" + "source": "https://github.com/php-http/message/tree/1.16.1" }, - "time": "2022-02-11T13:41:14+00:00" + "time": "2024-03-07T13:22:09+00:00" }, { - "name": "php-http/message-factory", - "version": "v1.0.2", + "name": "php-http/promise", + "version": "1.3.1", "source": { "type": "git", - "url": "https://github.com/php-http/message-factory.git", - "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + "url": "https://github.com/php-http/promise.git", + "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", - "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83", + "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83", "shasum": "" }, "require": { - "php": ">=5.4", - "psr/http-message": "^1.0" + "php": "^7.1 || ^8.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } + "require-dev": { + "friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3", + "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4" }, + "type": "library", "autoload": { "psr-4": { - "Http\\Message\\": "src/" + "Http\\Promise\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -384,68 +703,106 @@ "MIT" ], "authors": [ + { + "name": "Joel Wurtz", + "email": "joel.wurtz@gmail.com" + }, { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com" } ], - "description": "Factory interfaces for PSR-7 HTTP Message", - "homepage": "http://php-http.org", + "description": "Promise used for asynchronous HTTP requests", + "homepage": "http://httplug.io", "keywords": [ - "factory", - "http", - "message", - "stream", - "uri" + "promise" ], "support": { - "issues": "https://github.com/php-http/message-factory/issues", - "source": "https://github.com/php-http/message-factory/tree/master" + "issues": "https://github.com/php-http/promise/issues", + "source": "https://github.com/php-http/promise/tree/1.3.1" }, - "time": "2015-12-19T14:08:53+00:00" + "time": "2024-03-15T13:55:21+00:00" }, { - "name": "php-http/mock-client", - "version": "1.5.0", + "name": "psr/container", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/php-http/mock-client.git", - "reference": "a797c2a9122cccafcce14773b8a24d2808a9ab44" + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/mock-client/zipball/a797c2a9122cccafcce14773b8a24d2808a9ab44", - "reference": "a797c2a9122cccafcce14773b8a24d2808a9ab44", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0", - "php-http/client-common": "^2.0", - "php-http/discovery": "^1.0", - "php-http/httplug": "^2.0", - "php-http/message-factory": "^1.0", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "symfony/polyfill-php80": "^1.17" + "php": ">=7.4.0" }, - "provide": { - "php-http/async-client-implementation": "1.0", - "php-http/client-implementation": "1.0", - "psr/http-client-implementation": "1.0" + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } }, - "require-dev": { - "phpspec/phpspec": "^5.1 || ^6.0" + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Http\\Mock\\": "src/" + "Psr\\Http\\Client\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -454,54 +811,50 @@ ], "authors": [ { - "name": "David de Boer", - "email": "david@ddeboer.nl" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Mock HTTP client", - "homepage": "http://httplug.io", + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", "keywords": [ - "client", "http", - "mock", - "psr7" + "http-client", + "psr", + "psr-18" ], "support": { - "issues": "https://github.com/php-http/mock-client/issues", - "source": "https://github.com/php-http/mock-client/tree/1.5.0" + "source": "https://github.com/php-fig/http-client" }, - "time": "2021-08-25T07:01:14+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { - "name": "php-http/promise", + "name": "psr/http-factory", "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/php-http/promise.git", - "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88" + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", - "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.3.2", - "phpspec/phpspec": "^5.1.2 || ^6.2" + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Http\\Promise\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -510,52 +863,52 @@ ], "authors": [ { - "name": "Joel Wurtz", - "email": "joel.wurtz@gmail.com" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Promise used for asynchronous HTTP requests", - "homepage": "http://httplug.io", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ - "promise" + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/php-http/promise/issues", - "source": "https://github.com/php-http/promise/tree/1.1.0" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2020-07-07T09:29:14+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { - "name": "psr/http-client", - "version": "1.0.1", + "name": "psr/http-message", + "version": "1.1", "source": { "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Http\\Client\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -568,47 +921,146 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ "http", - "http-client", + "http-message", "psr", - "psr-18" + "psr-7", + "request", + "response" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/master" + "source": "https://github.com/php-fig/http-message/tree/1.1" }, - "time": "2020-06-29T06:28:15+00:00" + "time": "2023-04-04T09:50:52+00:00" }, { - "name": "psr/http-factory", - "version": "1.0.1", + "name": "psr/log", + "version": "3.0.1", "source": { "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + "url": "https://github.com/php-fig/log.git", + "reference": "79dff0b268932c640297f5208d6298f71855c03e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "url": "https://api.github.com/repos/php-fig/log/zipball/79dff0b268932c640297f5208d6298f71855c03e", + "reference": "79dff0b268932c640297f5208d6298f71855c03e", "shasum": "" }, "require": { - "php": ">=7.0.0", - "psr/http-message": "^1.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.1" + }, + "time": "2024-08-21T13:31:24+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } + "files": [ + "function.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -616,53 +1068,90 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, - "time": "2019-04-30T12:38:16+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" }, { - "name": "psr/http-message", - "version": "1.0.1", + "name": "symfony/http-client", + "version": "v7.1.3", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "url": "https://github.com/symfony/http-client.git", + "reference": "b79858aa7a051ea791b0d50269a234a0b50cb231" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/symfony/http-client/zipball/b79858aa7a051ea791b0d50269a234a0b50cb231", + "reference": "b79858aa7a051ea791b0d50269a234a0b50cb231", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "^3.4.1", + "symfony/service-contracts": "^2.5|^3" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" }, + "type": "library", "autoload": { "psr-4": { - "Psr\\Http\\Message\\": "src/" - } + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -670,37 +1159,50 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" + "http" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/symfony/http-client/tree/v7.1.3" }, - "time": "2016-08-06T14:39:51+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-07-17T06:10:24+00:00" }, { - "name": "symfony/deprecation-contracts", - "version": "v3.1.1", + "name": "symfony/http-client-contracts", + "version": "v3.5.0", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "20414d96f391677bf80078aa55baece78b82647d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", - "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", + "reference": "20414d96f391677bf80078aa55baece78b82647d", "shasum": "" }, "require": { @@ -709,7 +1211,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -717,8 +1219,11 @@ } }, "autoload": { - "files": [ - "function.php" + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -735,10 +1240,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "A generic function and convention to trigger deprecation notices", + "description": "Generic abstractions related to HTTP clients", "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" }, "funding": [ { @@ -754,25 +1267,25 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.1.0", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4" + "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a3016f5442e28386ded73c43a32a5b68586dd1c4", - "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55", + "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -805,7 +1318,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.1.0" + "source": "https://github.com/symfony/options-resolver/tree/v7.1.1" }, "funding": [ { @@ -821,20 +1334,20 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.26.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", "shasum": "" }, "require": { @@ -842,9 +1355,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.26-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -888,7 +1398,90 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" }, "funding": [ { @@ -904,36 +1497,36 @@ "type": "tidelift" } ], - "time": "2022-05-10T07:21:04+00:00" + "time": "2024-04-18T09:32:20+00:00" } ], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.4.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.22" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { @@ -960,7 +1553,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -976,26 +1569,26 @@ "type": "tidelift" } ], - "time": "2022-03-03T08:28:38+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "laminas/laminas-diactoros", - "version": "2.17.0", + "version": "2.26.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-diactoros.git", - "reference": "5b32597aa46b83c8b85bb1cf9a6ed4fe7dd980c5" + "reference": "6584d44eb8e477e89d453313b858daac6183cddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/5b32597aa46b83c8b85bb1cf9a6ed4fe7dd980c5", - "reference": "5b32597aa46b83c8b85bb1cf9a6ed4fe7dd980c5", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/6584d44eb8e477e89d453313b858daac6183cddc", + "reference": "6584d44eb8e477e89d453313b858daac6183cddc", "shasum": "" }, "require": { - "php": "^7.4 || ~8.0.0 || ~8.1.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.1" }, "conflict": { "zendframework/zend-diactoros": "*" @@ -1010,11 +1603,11 @@ "ext-gd": "*", "ext-libxml": "*", "http-interop/http-factory-tests": "^0.9.0", - "laminas/laminas-coding-standard": "^2.4.0", - "php-http/psr7-integration-tests": "^1.1.1", - "phpunit/phpunit": "^9.5.23", - "psalm/plugin-phpunit": "^0.17.0", - "vimeo/psalm": "^4.24.0" + "laminas/laminas-coding-standard": "^2.5", + "php-http/psr7-integration-tests": "^1.2", + "phpunit/phpunit": "^9.5.28", + "psalm/plugin-phpunit": "^0.18.4", + "vimeo/psalm": "^5.6" }, "type": "library", "extra": { @@ -1073,20 +1666,20 @@ "type": "community_bridge" } ], - "time": "2022-08-30T17:01:46+00:00" + "time": "2023-10-29T16:17:44+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", "shasum": "" }, "require": { @@ -1094,11 +1687,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -1124,7 +1718,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" }, "funding": [ { @@ -1132,29 +1726,31 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2024-06-12T14:39:25+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.1", + "version": "v5.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900" + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", - "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -1162,7 +1758,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1186,26 +1782,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" }, - "time": "2022-09-04T07:30:47+00:00" + "time": "2024-07-01T20:03:41+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -1246,9 +1843,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -1303,27 +1906,27 @@ }, { "name": "php-http/curl-client", - "version": "2.2.1", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/php-http/curl-client.git", - "reference": "2ed4245a817d859dd0c1d51c7078cdb343cf5233" + "reference": "0b869922458b1cde9137374545ed4fff7ac83623" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/curl-client/zipball/2ed4245a817d859dd0c1d51c7078cdb343cf5233", - "reference": "2ed4245a817d859dd0c1d51c7078cdb343cf5233", + "url": "https://api.github.com/repos/php-http/curl-client/zipball/0b869922458b1cde9137374545ed4fff7ac83623", + "reference": "0b869922458b1cde9137374545ed4fff7ac83623", "shasum": "" }, "require": { "ext-curl": "*", - "php": "^7.1 || ^8.0", + "php": "^7.4 || ^8.0", "php-http/discovery": "^1.6", "php-http/httplug": "^2.0", "php-http/message": "^1.2", "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0" + "psr/http-factory-implementation": "^1.0", + "symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" }, "provide": { "php-http/async-client-implementation": "1.0", @@ -1331,17 +1934,13 @@ "psr/http-client-implementation": "1.0" }, "require-dev": { - "guzzlehttp/psr7": "^1.0", + "guzzlehttp/psr7": "^2.0", "laminas/laminas-diactoros": "^2.0", "php-http/client-integration-tests": "^3.0", + "php-http/message-factory": "^1.1", "phpunit/phpunit": "^7.5 || ^9.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, "autoload": { "psr-4": { "Http\\Client\\Curl\\": "src/" @@ -1366,22 +1965,84 @@ ], "support": { "issues": "https://github.com/php-http/curl-client/issues", - "source": "https://github.com/php-http/curl-client/tree/2.2.1" + "source": "https://github.com/php-http/curl-client/tree/2.3.2" + }, + "time": "2024-03-03T08:21:07+00:00" + }, + { + "name": "php-http/mock-client", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/mock-client.git", + "reference": "ae5d717334ecd68199667bea6e9db07276e69a2b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/mock-client/zipball/ae5d717334ecd68199667bea6e9db07276e69a2b", + "reference": "ae5d717334ecd68199667bea6e9db07276e69a2b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "php-http/client-common": "^2.0", + "php-http/discovery": "^1.16", + "php-http/httplug": "^2.0", + "psr/http-client": "^1.0", + "psr/http-factory-implementation": "^1.0", + "psr/http-message": "^1.0 || ^2.0", + "symfony/polyfill-php80": "^1.17" + }, + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0", + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Http\\Mock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David de Boer", + "email": "david@ddeboer.nl" + } + ], + "description": "Mock HTTP client", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "http", + "mock", + "psr7" + ], + "support": { + "issues": "https://github.com/php-http/mock-client/issues", + "source": "https://github.com/php-http/mock-client/tree/1.6.0" }, - "time": "2021-12-10T18:02:07+00:00" + "time": "2023-05-21T08:31:38+00:00" }, { "name": "phpstan/phpstan", - "version": "1.8.6", + "version": "1.11.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "c386ab2741e64cc9e21729f891b28b2b10fe6618" + "reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c386ab2741e64cc9e21729f891b28b2b10fe6618", - "reference": "c386ab2741e64cc9e21729f891b28b2b10fe6618", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/707c2aed5d8d0075666e673a5e71440c1d01a5a3", + "reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3", "shasum": "" }, "require": { @@ -1410,8 +2071,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.8.6" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -1421,54 +2085,50 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2022-09-23T09:54:39+00:00" + "time": "2024-08-19T14:37:29+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.17", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa94dc41e8661fe90c7316849907cba3007b10d8", - "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -1496,7 +2156,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.17" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -1504,7 +2165,7 @@ "type": "github" } ], - "time": "2022-08-30T12:24:04+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1749,50 +2410,50 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.25", + "version": "9.6.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d" + "reference": "49d7820565836236411f5dc002d16dd689cde42f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d", - "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", + "reference": "49d7820565836236411f5dc002d16dd689cde42f", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.13", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -1800,7 +2461,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { @@ -1831,7 +2492,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.25" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" }, "funding": [ { @@ -1847,20 +2509,20 @@ "type": "tidelift" } ], - "time": "2022-09-25T03:44:45+00:00" + "time": "2024-07-10T11:45:39+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -1895,7 +2557,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -1903,7 +2565,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -2092,20 +2754,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -2137,7 +2799,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -2145,20 +2807,20 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -2203,7 +2865,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -2211,20 +2873,20 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", - "version": "5.1.4", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { @@ -2266,7 +2928,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -2274,20 +2936,20 @@ "type": "github" } ], - "time": "2022-04-03T09:37:03+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -2343,7 +3005,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -2351,20 +3013,20 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -2407,7 +3069,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -2415,24 +3077,24 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -2464,7 +3126,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -2472,7 +3134,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -2588,16 +3250,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { @@ -2636,10 +3298,10 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { @@ -2647,20 +3309,20 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -2672,7 +3334,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -2693,8 +3355,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -2702,20 +3363,20 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { @@ -2750,7 +3411,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { @@ -2758,7 +3419,7 @@ "type": "github" } ], - "time": "2022-09-12T14:47:03+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -2815,16 +3476,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -2853,7 +3514,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -2861,7 +3522,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], @@ -2874,5 +3535,5 @@ "ext-json": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/examples/Inquiry.php b/examples/Inquiry.php new file mode 100644 index 0000000..f2c42f8 --- /dev/null +++ b/examples/Inquiry.php @@ -0,0 +1,26 @@ + 'your_merchant_id_here', +]); + +$zarinpal = new ZarinPal($options); +$paymentGateway = $zarinpal->paymentGateway(); + +$inquiryRequest = new InquiryRequest(); +$inquiryRequest->authority = 'A00000000000000000000000000123456'; // Authority from the original transaction + +try { + $response = $paymentGateway->inquiry($inquiryRequest); + echo "Transaction Inquiry: \n"; + echo "Amount: " . $response->amount . "\n"; + echo "Status: " . $response->status . "\n"; +} catch (\Exception $e) { + echo 'Transaction inquiry failed: ' . $e->getMessage(); +} diff --git a/examples/Refund.php b/examples/Refund.php new file mode 100644 index 0000000..19f4aab --- /dev/null +++ b/examples/Refund.php @@ -0,0 +1,32 @@ + 'your_access_token_here', +]); + +$refundService = new RefundService($options); + +$refundRequest = new RefundRequest(); +$refundRequest->sessionId = '385404539'; +$refundRequest->amount = 20000; // Amount in IRR +$refundRequest->description = 'Refund for order 12345'; +$refundRequest->method = 'CARD'; // Method: CARD for instant, PAYA for regular +$refundRequest->reason = 'CUSTOMER_REQUEST'; // Reason for refund + +try { + $response = $refundService->refund($refundRequest); + echo "Refund Processed: \n"; + echo "Transaction ID: " . $response->id . "\n"; + echo "Terminal ID: " . $response->terminal_id . "\n"; + echo "Refund Amount: " . $response->timeline['refund_amount'] . "\n"; + echo "Refund Time: " . $response->timeline['refund_time'] . "\n"; + echo "Refund Status: " . $response->timeline['refund_status'] . "\n"; +} catch (\Exception $e) { + echo 'Refund failed: ' . $e->getMessage(); +} diff --git a/examples/Request.php b/examples/Request.php new file mode 100644 index 0000000..65abf8e --- /dev/null +++ b/examples/Request.php @@ -0,0 +1,31 @@ + false, // Enable sandbox mode + 'merchant_id' => 'your_merchant_id_here', +]); + +$zarinpal = new ZarinPal($options); +$paymentGateway = $zarinpal->paymentGateway(); + +$request = new RequestRequest(); +$request->amount = 10000; // Amount in IRR +$request->description = 'Payment for order 12345'; +$request->callback_url = 'https://yourcallbackurl.com'; +$request->mobile = '09121234567'; // Optional +$request->email = 'test@example.com'; // Optional + +try { + $response = $paymentGateway->request($request); + echo "Payment Request Successful: \n"; + echo "Authority: " . $response->authority . "\n"; + echo "Payment URL: " . $paymentGateway->getRedirectUrl($response->authority) . "\n"; +} catch (\Exception $e) { + echo 'Payment request failed: ' . $e->getMessage(); +} diff --git a/examples/Reverse.php b/examples/Reverse.php new file mode 100644 index 0000000..912524b --- /dev/null +++ b/examples/Reverse.php @@ -0,0 +1,24 @@ + 'your_merchant_id_here', +]); + +$zarinpal = new ZarinPal($options); +$paymentGateway = $zarinpal->paymentGateway(); + +$reverseRequest = new ReverseRequest(); +$reverseRequest->authority = 'A00000000000000000000000000123456'; // Authority from the original transaction + +try { + $response = $paymentGateway->reverse($reverseRequest); + echo "Transaction Reversed: " . $response->status . "\n"; +} catch (\Exception $e) { + echo 'Transaction reversal failed: ' . $e->getMessage(); +} diff --git a/examples/Transaction.php b/examples/Transaction.php new file mode 100644 index 0000000..987bf71 --- /dev/null +++ b/examples/Transaction.php @@ -0,0 +1,30 @@ + 'your_access_token_here', +]); + +$transactionService = new TransactionService($options); + +$transactionRequest = new TransactionListRequest(); +$transactionRequest->terminalId = '238'; +$transactionRequest->filter = 'PAID'; // Optional filter: PAID, VERIFIED, TRASH, ACTIVE, REFUNDED + +try { + $transactions = $transactionService->getTransactions($transactionRequest); + foreach ($transactions as $transaction) { + echo "Transaction ID: " . $transaction->id . "\n"; + echo "Status: " . $transaction->status . "\n"; + echo "Amount: " . $transaction->amount . "\n"; + echo "Description: " . $transaction->description . "\n"; + echo "Created At: " . $transaction->created_at . "\n\n"; + } +} catch (\Exception $e) { + echo 'Failed to retrieve transactions: ' . $e->getMessage(); +} diff --git a/examples/Verify.php b/examples/Verify.php new file mode 100644 index 0000000..4ef44cf --- /dev/null +++ b/examples/Verify.php @@ -0,0 +1,27 @@ + 'your_merchant_id_here', +]); + +$zarinpal = new ZarinPal($options); +$paymentGateway = $zarinpal->paymentGateway(); + +$verifyRequest = new VerifyRequest(); +$verifyRequest->authority = 'A00000000000000000000000000123456'; // The authority code returned by the initial payment request +$verifyRequest->amount = 15000; // Amount in IRR + +try { + $response = $paymentGateway->verify($verifyRequest); + echo "Payment Verified: \n"; + echo "Reference ID: " . $response->ref_id . "\n"; + echo "Code: " . $response->code . "\n"; +} catch (\Exception $e) { + echo 'Payment verification failed: ' . $e->getMessage(); +} diff --git a/examples/basic-client.php b/examples/basic-client.php index 4589f8b..aa2f9f2 100644 --- a/examples/basic-client.php +++ b/examples/basic-client.php @@ -2,38 +2,49 @@ require_once __DIR__ . '/../vendor/autoload.php'; - use Http\Client\Common\Plugin\HeaderDefaultsPlugin; use ZarinPal\Sdk\ClientBuilder; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\RequestRequest; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\UnverifiedRequest; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\VerifyRequest; +use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\ReverseRequest; +use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\InquiryRequest; use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; - $clientBuilder = new ClientBuilder(); $clientBuilder->addPlugin(new HeaderDefaultsPlugin([ 'Accept' => 'application/json', ])); - // usage $options = new Options([ 'client_builder' => $clientBuilder, - 'merchant_id' => 'a738fc08-1e83-4928-bf90-08936ea6e1e2', + 'merchant_id' => '25fe4c36-66e4-11e9-a9e4-000c29344814', ]); $sdk = new ZarinPal($options); - $request = new RequestRequest(); -$request->amount = 2000; -//$request->merchantId = 'a738fc08-1e83-4928-bf90-08936ea6e1e2'; -$request->description = 'test'; +$request->amount = 10000; +$request->description = 'پرداخت تست'; $request->callback_url = 'https://tehran.ir'; $request->mobile = '09370000000'; $request->email = 'a@b.c'; +$request->currency = 'IRT'; +$request->cardPan = '5022291083818920'; +//$request->wages = [ +// [ +// 'iban' => 'IR130570028780010957775103', +// 'amount' =>, +// 'description' => 'تسهیم سود فروش' +// ], +// [ +// 'iban' => 'IR670170000000352965862009', +// 'amount' => 5000, +// 'description' => 'تسهیم سود فروش به شخص دوم' +// ] +//]; $verify = new VerifyRequest(); $verify->amount = 15000; @@ -41,9 +52,17 @@ $unverified = new UnverifiedRequest(); +$reverseRequest = new ReverseRequest($options); +$reverseRequest->authority = 'A00000000000000000000000000123456'; + +$inquiryRequest = new InquiryRequest($options); +$inquiryRequest->authority = 'A00000000000000000000000000123456'; $response = $sdk->paymentGateway()->request($request); +die(var_dump($response)); $response2 = $sdk->paymentGateway()->verify($verify); $response3 = $sdk->paymentGateway()->unverified($unverified); +$response4 = $sdk->paymentGateway()->reverse($reverseRequest); +$response5 = $sdk->paymentGateway()->inquiry($inquiryRequest); -die(print_r($response) . print_r($response2) . print_r($response3)); \ No newline at end of file +die(print_r($response) . print_r($response2) . print_r($response3) . print_r($response4) . print_r($response5)); diff --git a/examples/basic-client2.php b/examples/basic-client2.php new file mode 100644 index 0000000..be71eda --- /dev/null +++ b/examples/basic-client2.php @@ -0,0 +1,28 @@ + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiZWU3MjgzZDQ0MzI1ZTJlMDdkODdhM2MzMDc2MzUzMWExZTYyZDI4OWMzOGMxZWY2ODI0NmRkZWZkYTRjZmNlMzY5NjVkMDQ0YjA1ZTMwNGMiLCJpYXQiOjE3MjQ2MTY3MjcuMTU5NTU5LCJuYmYiOjE3MjQ2MTY3MjcuMTU5NTYyLCJleHAiOjE4ODIzODMxMjcuMTIwOTkzLCJzdWIiOiIxMjE3NDYiLCJzY29wZXMiOltdfQ.L7CXjwVQQ0Pm0Ou4-7ALmKXZNHxUvrEvtvwe8i2H_zbcHTUZE51Gzd-wuO5gci09RalsshrOOwZ0UUZfCczuY8P8PfZTvvo5P6pzu6uhiU5FsEgyb8LNyyRakDXDkIekmyfDC-l3Y2dveBG2uAEfg4TflqjSJ-XIgeu4e9l8rnhWC91FS7d854aEqc7anpEbtetQG2gRSbAGgIWq6PA8laanX1Cj0eImUhsdG2B6raX4jTLfmn8bZ4bSmVNbTmgp7ltNGTLlU4ESbYCk79XhcUnGfYt59aeV0P_U82OVIXG0FBhKqrI4p8yJHbcObJgmSymLiZesZXlGfUST6I9u3fsaFCxd3BBFelrI84t6mTyabAEq7eGPJOlIu7pZbHtu3xCoNJoUKjPvltel1Ua25ENuY9GZa2rMFKl1hvSpkZYpJf9ZrYO7lQhxAoOufW-z9YehPD4axRQybVCFRYQ-Co1FczDU7RQPQ91-QBy34Z98Nj8qtl3pg00QieXLLHJHq2l5_ePzXb6-uLnQqIcpu2Sjrm9zObJkwcZ6pqASd4PVHDd76O27hDQ46q_Au3bQ5lm1MphSQ1yST5kpFNaTp8e0TvmkV8URsv8O0Ll9fT16Mf0faCgydtSv6K7saySnB6egs8MaB5qlMZf6oO1FcoJ3Cv9DJm56AxmYFYdYEgU', +]); + +$transactionService = new TransactionService($options); + +$transactionRequest = new TransactionListRequest(); +$transactionRequest->terminalId = '238'; +$transactionRequest->filter = 'PAID'; + +try { + $transactions = $transactionService->getTransactions($transactionRequest); + foreach ($transactions as $transaction) { + // Convert object to array and print it + print_r(json_decode(json_encode($transaction), true)); + } +} catch (Exception $e) { + echo 'Transaction fetch failed: ' . $e->getMessage(); +} + diff --git a/src/Endpoint/GraphQL/RefundService.php b/src/Endpoint/GraphQL/RefundService.php new file mode 100644 index 0000000..3458019 --- /dev/null +++ b/src/Endpoint/GraphQL/RefundService.php @@ -0,0 +1,49 @@ +client = new Client(); // Instantiate Guzzle client + $this->options = $options; + $this->graphqlUrl = $options->getGraphqlUrl(); + } + + public function refund(RefundRequest $request): array + { + $query = $request->toGraphQL(); + try { + $response = $this->client->request('POST', $this->graphqlUrl, [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), + 'Content-Type' => 'application/json', + ], + 'body' => $query, + ]); + + $responseData = $response->toArray(); + if (isset($responseData['errors'])) { + throw new ResponseException('GraphQL query error: ' . json_encode($responseData['errors'])); + } + + return new RefundResponse($responseData['data']['resource']); + } catch (RequestException $e) { + throw new ResponseException('Request failed: ' . $e->getMessage(), 0, $e); + } + } +} + + diff --git a/src/Endpoint/GraphQL/RequestTypes/RefundRequest.php b/src/Endpoint/GraphQL/RequestTypes/RefundRequest.php new file mode 100644 index 0000000..7481453 --- /dev/null +++ b/src/Endpoint/GraphQL/RequestTypes/RefundRequest.php @@ -0,0 +1,69 @@ +sessionId)) { + throw new \InvalidArgumentException('Session ID is required.'); + } + if ($this->amount < 20000) { + throw new \InvalidArgumentException('Amount must be at least 20000 IRR.'); + } + } + + public function toGraphQL(): string + { + $this->validate(); + + return json_encode([ + 'query' => ' + mutation AddRefund($session_id: ID!, $amount: BigInteger!, $description: String, $method: InstantPayoutActionTypeEnum, $reason: RefundReasonEnum) { + resource: AddRefund( + session_id: $session_id, + amount: $amount, + description: $description, + method: $method, + reason: $reason + ) { + terminal_id, + id, + amount, + timeline { + refund_amount, + refund_time, + refund_status + } + } + } + ', + 'variables' => [ + 'session_id' => $this->sessionId, + 'amount' => $this->amount, + 'description' => $this->description, + 'method' => $this->method, + 'reason' => $this->reason, + ] + ], JSON_THROW_ON_ERROR); + } +} diff --git a/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php b/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php new file mode 100644 index 0000000..c187d0b --- /dev/null +++ b/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php @@ -0,0 +1,77 @@ +terminalId)) { + throw new \InvalidArgumentException('Terminal ID is required.'); + } + } + + public function toGraphQL(): string + { + $this->validate(); + + return json_encode([ + 'query' => ' + query Sessions( + $terminal_id: ID!, + $filter: FilterEnum, + $id: ID, + $reference_id: String, + $rrn: String, + $card_pan: String, + $email: String, + $mobile: CellNumber, + $description: String + ) { + Session( + terminal_id: $terminal_id, + filter: $filter, + id: $id, + reference_id: $reference_id, + rrn: $rrn, + card_pan: $card_pan, + email: $email, + mobile: $mobile, + description: $description + ) { + id, + status, + amount, + description, + created_at + } + } + ', + 'variables' => [ + 'terminal_id' => $this->terminalId, + 'filter' => $this->filter, + 'id' => $this->id, + 'reference_id' => $this->referenceId, + 'rrn' => $this->rrn, + 'card_pan' => $this->cardPan, + 'email' => $this->email, + 'mobile' => $this->mobile, + 'description' => $this->description, + ] + ], JSON_THROW_ON_ERROR); + } +} diff --git a/src/Endpoint/GraphQL/ResponseTypes/RefundResponse.php b/src/Endpoint/GraphQL/ResponseTypes/RefundResponse.php new file mode 100644 index 0000000..6708ddd --- /dev/null +++ b/src/Endpoint/GraphQL/ResponseTypes/RefundResponse.php @@ -0,0 +1,23 @@ +terminalId = $data['terminal_id']; + $this->id = $data['id']; + $this->amount = $data['amount']; + $this->timeline = $data['timeline']; + } +} diff --git a/src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php b/src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php new file mode 100644 index 0000000..91c08c4 --- /dev/null +++ b/src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php @@ -0,0 +1,25 @@ +id = $data['id']; + $this->status = $data['status']; + $this->amount = $data['amount']; + $this->description = $data['description']; + $this->createdAt = $data['created_at']; + } +} diff --git a/src/Endpoint/GraphQL/TransactionService.php b/src/Endpoint/GraphQL/TransactionService.php new file mode 100644 index 0000000..3b95a2b --- /dev/null +++ b/src/Endpoint/GraphQL/TransactionService.php @@ -0,0 +1,53 @@ +client = new Client(); // Instantiate Guzzle client + $this->options = $options; + $this->graphqlUrl = $options->getGraphqlUrl(); + } + + public function getTransactions(TransactionListRequest $request): array + { + $query = $request->toGraphQL(); + try { + $response = $this->client->post($this->graphqlUrl, [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), + 'Content-Type' => 'application/json', + ], + 'body' => $query, + ]); + + $responseData = json_decode($response->getBody()->getContents(), true); + if (isset($responseData['errors'])) { + throw new ResponseException('GraphQL query error: ' . json_encode($responseData['errors'])); + } + + $transactions = []; + foreach ($responseData['data']['Session'] as $data) { + $transactions[] = new TransactionListResponse($data); + } + + return $transactions; + } catch (RequestException $e) { + throw new ResponseException('Request failed: ' . $e->getMessage(), 0, $e); + } + } +} + diff --git a/src/Endpoint/PaymentGateway/PaymentGateway.php b/src/Endpoint/PaymentGateway/PaymentGateway.php index dda6ba8..4416ca2 100644 --- a/src/Endpoint/PaymentGateway/PaymentGateway.php +++ b/src/Endpoint/PaymentGateway/PaymentGateway.php @@ -1,6 +1,5 @@ sdk = $sdk; } - - /** - * @param RequestTypes\RequestRequest $request - * @return RequestResponse - * @throws JsonException - * @throws PaymentGatewayException - * @throws ResponseException - * @throws \Http\Client\Exception - */ public function request(RequestTypes\RequestRequest $request): RequestResponse { $this->fillMerchantId($request); $response = $this->httpHandler(self::REQUEST_URI, $request->toString()); return new RequestResponse($response['data']); + } + + public function getRedirectUrl(string $authority): string + { + $baseUrl = (string) $this->sdk->getOptions()->getBaseUrl(); + return rtrim($baseUrl, '/') . self::START_PAY . $authority; + } + + public function verify(RequestTypes\VerifyRequest $request): VerifyResponse + { + $this->fillMerchantId($request); + $response = $this->httpHandler(self::VERIFY_URI, $request->toString()); + + return new VerifyResponse($response['data']); + } + + public function unverified(RequestTypes\UnverifiedRequest $request): UnverifiedResponse + { + $this->fillMerchantId($request); + $response = $this->httpHandler(self::UNVERIFIED_URI, $request->toString()); + + return new UnverifiedResponse($response['data']); + } + + public function reverse(RequestTypes\ReverseRequest $request): RequestResponse + { + $this->fillMerchantId($request); + $response = $this->httpHandler(self::REVERSE_URI, $request->toString()); + + return new RequestResponse($response['data']); + } + + public function inquiry(RequestTypes\InquiryRequest $request): RequestResponse + { + $this->fillMerchantId($request); + $response = $this->httpHandler(self::INQUIRY_URI, $request->toString()); + return new RequestResponse($response['data']); } private function fillMerchantId($request): void @@ -53,74 +84,53 @@ private function fillMerchantId($request): void } } - /** - * @throws PaymentGatewayException - * @throws ResponseException|\Http\Client\Exception - */ private function httpHandler(string $uri, string $body): array { try { - $response = $this->sdk->getHttpClient() - ->post($uri, [], $body); + $fullUri = $this->sdk->getOptions()->getBaseUrl() . $uri; // Use the correct base URL (sandbox or production) + $response = $this->sdk->getHttpClient()->post($fullUri, [], $body); $this->checkHttpError($response); $response = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); + } catch (JsonException $e) { + throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, $e); + } catch (ResponseException $e) { + throw $e; // Re-throw the original ResponseException to show exact status and message } catch (Exception $e) { - throw new ResponseException($e->getMessage(), -99, $e); + throw new ResponseException('Request failed: ' . $e->getMessage(), -99, $e); } - + return $this->checkPaymentGatewayError($response); } - /** - * @throws ResponseException - */ private function checkHttpError(ResponseInterface $response): void { - if (!in_array($response->getStatusCode(), [200, 400])) { - throw new ResponseException('Http Error', -99, null); + $statusCode = $response->getStatusCode(); + if ($statusCode !== 200) { + $body = $response->getBody()->getContents(); + $parsedBody = json_decode($body, true); + + if (isset($parsedBody['errors']['message'], $parsedBody['errors']['code'])) { + $message = $parsedBody['errors']['message']; + $code = $parsedBody['errors']['code']; + } else { + $message = 'HTTP Error: ' . $response->getReasonPhrase(); + $code = $statusCode; + } + + echo "HTTP Status Code: $statusCode\n"; + echo "Error Code: $code\n"; + echo "Error Message: $message\n"; + + throw new ResponseException($message, $code); } } - /** - * @throws PaymentGatewayException - */ - private function checkPaymentGatewayError($response) + private function checkPaymentGatewayError(array $response): array { if (!empty($response['errors']) || empty($response['data'])) { - throw new PaymentGatewayException($response['errors']); + $errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1]; + throw new PaymentGatewayException($errorDetails); } return $response; } - - /** - * @param RequestTypes\VerifyRequest $request - * @return VerifyResponse - * @throws JsonException - * @throws PaymentGatewayException - * @throws ResponseException - * @throws \Http\Client\Exception - */ - public function verify(RequestTypes\VerifyRequest $request): VerifyResponse - { - $this->fillMerchantId($request); - $response = $this->httpHandler(self::VERIFY_URI, $request->toString()); - - return new VerifyResponse($response['data']); - } - - /** - * @param RequestTypes\UnverifiedRequest $request - * @return UnverifiedResponse - * @throws JsonException - * @throws PaymentGatewayException - * @throws ResponseException - * @throws \Http\Client\Exception - */ - public function unverified(RequestTypes\UnverifiedRequest $request): UnverifiedResponse - { - $this->fillMerchantId($request); - $response = $this->httpHandler(self::UNVERIFIED_URI, $request->toString()); - - return new UnverifiedResponse($response['data']); - } -} \ No newline at end of file +} diff --git a/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php new file mode 100644 index 0000000..0b628e2 --- /dev/null +++ b/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php @@ -0,0 +1,50 @@ +merchantId = $options->getMerchantId(); + } + + public function validate(): void + { + $this->validateMerchantId(); + $this->validateAuthority(); + } + + private function validateMerchantId(): void + { + if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { + throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); + } + } + + private function validateAuthority(): void + { + if ($this->authority === null || !preg_match('/^A[0-9a-zA-Z]{32}$/', $this->authority)) { + throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); + } + } + + final public function toString(): string + { + $this->validate(); + + return json_encode([ + "merchant_id" => $this->merchantId, + "authority" => $this->authority, + ], JSON_THROW_ON_ERROR); + } +} diff --git a/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php index 0d93626..060b00b 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php @@ -1,8 +1,8 @@ validateMerchantId(); + $this->validateAmount(); + $this->validateCallbackUrl(); + $this->validateMobile(); + $this->validateEmail(); + $this->validateCurrency(); + $this->validateWages(); + $this->validateCardPan(); + } + + private function validateMerchantId(): void + { + if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { + throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); + } + } + + private function validateAmount(): void + { + if ($this->amount <= 0) { + throw new InvalidArgumentException('Amount must be greater than zero.'); + } + } + + private function validateCallbackUrl(): void + { + if (!preg_match('/^https?:\/\/.*/', $this->callback_url)) { + throw new InvalidArgumentException('Invalid callback URL format. It should start with http:// or https://.'); + } + } + + private function validateMobile(): void + { + if ($this->mobile !== null && !preg_match('/^09[0-9]{9}$/', $this->mobile)) { + throw new InvalidArgumentException('Invalid mobile number format.'); + } + } + + private function validateEmail(): void + { + if ($this->email !== null && !filter_var($this->email, FILTER_VALIDATE_EMAIL)) { + throw new InvalidArgumentException('Invalid email format.'); + } + } + + private function validateCurrency(): void + { + $validCurrencies = ['IRR', 'IRT']; + if ($this->currency !== null && !in_array($this->currency, $validCurrencies)) { + throw new InvalidArgumentException('Invalid currency format. Allowed values are "IRR" or "IRT".'); + } + } + + private function validateWages(): void + { + if ($this->wages !== null) { + foreach ($this->wages as $wage) { + if (!isset($wage['iban']) || !preg_match('/^IR[0-9]{2}[0-9A-Z]{1,24}$/', $wage['iban'])) { + throw new InvalidArgumentException('Invalid IBAN format in wages.'); + } + if (!isset($wage['amount']) || $wage['amount'] <= 0) { + throw new InvalidArgumentException('Wage amount must be greater than zero.'); + } + if (!isset($wage['description']) || strlen($wage['description']) > 255) { + throw new InvalidArgumentException('Wage description must be provided and less than 255 characters.'); + } + } + } + } + + private function validateCardPan(): void + { + if ($this->cardPan !== null && !preg_match('/^[0-9]{16}$/', $this->cardPan)) { + throw new InvalidArgumentException('Invalid card PAN format. It should be a 16-digit number.'); + } + } final public function toString(): string { - return json_encode([ + $this->validate(); + + $data = [ "merchant_id" => $this->merchantId, "amount" => $this->amount, "callback_url" => $this->callback_url, @@ -27,7 +111,20 @@ final public function toString(): string "mobile" => $this->mobile, "email" => $this->email, ] - ], JSON_THROW_ON_ERROR); - } + ]; -} \ No newline at end of file + if ($this->currency) { + $data['currency'] = $this->currency; + } + + if ($this->wages) { + $data['wages'] = $this->wages; + } + + if ($this->cardPan) { + $data['metadata']['card_pan'] = $this->cardPan; + } + + return json_encode($data, JSON_THROW_ON_ERROR); + } +} diff --git a/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php new file mode 100644 index 0000000..22f6f21 --- /dev/null +++ b/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php @@ -0,0 +1,50 @@ +merchantId = $options->getMerchantId(); + } + + public function validate(): void + { + $this->validateMerchantId(); + $this->validateAuthority(); + } + + private function validateMerchantId(): void + { + if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { + throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); + } + } + + private function validateAuthority(): void + { + if ($this->authority === null || !preg_match('/^A[0-9a-zA-Z]{32}$/', $this->authority)) { + throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); + } + } + + final public function toString(): string + { + $this->validate(); + + return json_encode([ + "merchant_id" => $this->merchantId, + "authority" => $this->authority, + ], JSON_THROW_ON_ERROR); + } +} diff --git a/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php index 257262b..b520001 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php @@ -1,8 +1,8 @@ validateMerchantId(); + } + + private function validateMerchantId(): void + { + if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { + throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); + } + } /** * @throws JsonException */ final public function toString(): string { + $this->validate(); + return json_encode([ "merchant_id" => $this->merchantId, ], JSON_THROW_ON_ERROR); } - -} \ No newline at end of file +} diff --git a/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php index b6e2305..14063a8 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php @@ -1,8 +1,8 @@ validateMerchantId(); + $this->validateAmount(); + $this->validateAuthority(); + } + + private function validateMerchantId(): void + { + if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { + throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); + } + } + + private function validateAmount(): void + { + if ($this->amount <= 0) { + throw new InvalidArgumentException('Amount must be greater than zero.'); + } + } + + private function validateAuthority(): void + { + if ($this->authority === null || !preg_match('/^A[0-9a-zA-Z]{32}$/', $this->authority)) { + throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); + } + } /** * @throws JsonException */ final public function toString(): string { + $this->validate(); + return json_encode([ "merchant_id" => $this->merchantId, "amount" => $this->amount, "authority" => $this->authority, ], JSON_THROW_ON_ERROR); } - -} \ No newline at end of file +} diff --git a/src/Endpoint/PaymentGateway/ResponseTypes/RequestResponse.php b/src/Endpoint/PaymentGateway/ResponseTypes/RequestResponse.php index d95799d..5cd6f9f 100644 --- a/src/Endpoint/PaymentGateway/ResponseTypes/RequestResponse.php +++ b/src/Endpoint/PaymentGateway/ResponseTypes/RequestResponse.php @@ -14,5 +14,7 @@ class RequestResponse public string $message; public string $fee_type; public int $fee; + public int $amount; + public string $status; } \ No newline at end of file diff --git a/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php b/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php index a7ebe0d..0fbbc98 100644 --- a/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php +++ b/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php @@ -10,6 +10,7 @@ class UnverifiedResponse use Fillable; public array $authorities; + public array $list; } \ No newline at end of file diff --git a/src/Options.php b/src/Options.php index f841379..f2017ba 100644 --- a/src/Options.php +++ b/src/Options.php @@ -4,7 +4,6 @@ namespace ZarinPal\Sdk; - use Http\Discovery\Psr17FactoryDiscovery; use Psr\Http\Message\UriFactoryInterface; use Psr\Http\Message\UriInterface; @@ -24,19 +23,25 @@ public function __construct(array $options = []) private function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults( - [ - 'client_builder' => new ClientBuilder(), - 'uri_factory' => Psr17FactoryDiscovery::findUriFactory(), - 'base_url' => $this->arrayGet(getenv(), 'ZARINPAL_MERCHANT_URL', 'https://api.zarinpal.com'), - 'merchant_id' => $this->arrayGet(getenv(), 'ZARINPAL_MERCHANT_KEY', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') - ] - ); + $resolver->setDefaults([ + 'client_builder' => new ClientBuilder(), + 'uri_factory' => Psr17FactoryDiscovery::findUriFactory(), + 'base_url' => 'https://payment.zarinpal.com', + 'sandbox_base_url' => 'https://sandbox.zarinpal.com', + 'merchant_id' => $this->arrayGet(getenv(), 'ZARINPAL_MERCHANT_KEY', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'), + 'graphql_url' => 'https://next.zarinpal.com/api/v4/graphql/', // Fixed GraphQL URL + 'access_token' => $this->arrayGet(getenv(), 'ZARINPAL_ACCESS_TOKEN', ''), + 'sandbox' => false, // Default is production mode + ]); $resolver->setAllowedTypes('client_builder', ClientBuilder::class); $resolver->setAllowedTypes('uri_factory', UriFactoryInterface::class); $resolver->setAllowedTypes('base_url', 'string'); + $resolver->setAllowedTypes('sandbox_base_url', 'string'); $resolver->setAllowedTypes('merchant_id', 'string'); + $resolver->setAllowedTypes('graphql_url', 'string'); + $resolver->setAllowedTypes('access_token', 'string'); + $resolver->setAllowedTypes('sandbox', 'bool'); } private function arrayGet(array $array, string $key, ?string $default = null): ?string @@ -55,7 +60,8 @@ public function getClientBuilder(): ClientBuilder public function getBaseUrl(): UriInterface { - return $this->getUriFactory()->createUri($this->options['base_url']); + $url = $this->options['sandbox'] ? $this->options['sandbox_base_url'] : $this->options['base_url']; + return $this->getUriFactory()->createUri($url); } public function getUriFactory(): UriFactoryInterface @@ -67,5 +73,19 @@ public function getMerchantId(): string { return $this->options['merchant_id']; } -} + public function getGraphqlUrl(): string + { + return $this->options['graphql_url']; + } + + public function getAccessToken(): string + { + return $this->options['access_token']; + } + + public function isSandbox(): bool + { + return $this->options['sandbox']; + } +} diff --git a/src/ZarinPal.php b/src/ZarinPal.php index 32434d1..c8dc378 100644 --- a/src/ZarinPal.php +++ b/src/ZarinPal.php @@ -13,6 +13,7 @@ final class ZarinPal { private ClientBuilder $clientBuilder; private Options $options; + private HttpMethodsClientInterface $httpClient; public function __construct(Options $options = null) { @@ -28,6 +29,7 @@ public function __construct(Options $options = null) ] ) ); + $this->httpClient = $this->clientBuilder->getHttpClient(); } private function getClassName(): string @@ -35,6 +37,11 @@ private function getClassName(): string return basename(str_replace('\\', '/', __CLASS__)); } + public function getOptions(): Options + { + return $this->options; + } + public function paymentGateway(): PaymentGateway { return new PaymentGateway($this); @@ -47,6 +54,11 @@ public function getMerchantId(): string public function getHttpClient(): HttpMethodsClientInterface { - return $this->clientBuilder->getHttpClient(); + return $this->httpClient; + } + + public function setHttpClient(HttpMethodsClientInterface $client): void + { + $this->httpClient = $client; } -} \ No newline at end of file +} diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php new file mode 100644 index 0000000..6a18977 --- /dev/null +++ b/tests/BaseTestCase.php @@ -0,0 +1,34 @@ +mockClient = new MockClient(); + $this->options = new Options([ + 'access_token' => 'mock-access-token', + 'merchant_id' => '25fe4c36-66e4-11e9-a9e4-000c29344814', + ]); + } + + protected function getMockClient(): MockClient + { + return $this->mockClient; + } + + protected function getOptions(): Options + { + return $this->options; + } +} diff --git a/tests/Graphql/GraphQLRefundTest.php b/tests/Graphql/GraphQLRefundTest.php new file mode 100644 index 0000000..7ec23ea --- /dev/null +++ b/tests/Graphql/GraphQLRefundTest.php @@ -0,0 +1,44 @@ +refundService = $this->createMock(RefundService::class); + } + + public function testRefund() + { + $refundRequest = new RefundRequest(); + $refundRequest->sessionId = '385404539'; + $refundRequest->amount = 20000; + $refundRequest->description = 'Test Refund'; + + $mockResponse = [ + 'id' => '1234567890', + 'terminal_id' => '238', + 'amount' => 20000, + 'timeline' => [ + 'refund_amount' => 20000, + 'refund_time' => '2024-08-25T15:00:00+03:30', + 'refund_status' => 'PENDING' + ] + ]; + + $this->refundService->method('refund')->willReturn($mockResponse); + + $response = $this->refundService->refund($refundRequest); + + $this->assertArrayHasKey('id', $response); + $this->assertEquals('1234567890', $response['id']); + } +} diff --git a/tests/Graphql/TransactionServiceTest.php b/tests/Graphql/TransactionServiceTest.php new file mode 100644 index 0000000..061eaf5 --- /dev/null +++ b/tests/Graphql/TransactionServiceTest.php @@ -0,0 +1,62 @@ + [ + 'Session' => [ + [ + 'id' => '1234567890', + 'status' => 'PAID', + 'amount' => 10000, + 'description' => 'Test transaction', + 'created_at' => '2024-08-25T15:00:00+03:30' + ] + ] + ] + ])), + ]); + + $handlerStack = HandlerStack::create($mock); + $mockClient = new Client(['handler' => $handlerStack]); + + // Inject mock client into the TransactionService + $this->transactionService = new TransactionService($this->getOptions()); + $reflection = new \ReflectionClass($this->transactionService); + $clientProperty = $reflection->getProperty('client'); + $clientProperty->setAccessible(true); + $clientProperty->setValue($this->transactionService, $mockClient); + } + + public function testGetTransactions() + { + $transactionRequest = new TransactionListRequest(); + $transactionRequest->terminalId = '238'; + + $transactions = $this->transactionService->getTransactions($transactionRequest); + + $this->assertCount(1, $transactions); + $this->assertEquals('1234567890', $transactions[0]->id); + $this->assertEquals('PAID', $transactions[0]->status); + $this->assertEquals(10000, $transactions[0]->amount); + $this->assertEquals('Test transaction', $transactions[0]->description); + } +} diff --git a/tests/PaymentGateway/PaymentGatewayTest.php b/tests/PaymentGateway/PaymentGatewayTest.php new file mode 100644 index 0000000..a21e8b8 --- /dev/null +++ b/tests/PaymentGateway/PaymentGatewayTest.php @@ -0,0 +1,140 @@ +clientMock = $this->createMock(HttpMethodsClientInterface::class); + + $zarinpal = new ZarinPal($this->getOptions()); + $zarinpal->setHttpClient($this->clientMock); + + $this->gateway = new PaymentGateway($zarinpal); + } + + public function testRequest() + { + $responseBody = [ + 'data' => [ + 'authority' => 'A00000000000000000000000000123456', + ], + 'errors' => [] + ]; + + $this->clientMock->expects($this->once()) + ->method('post') + ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + + $request = new RequestRequest(); + $request->amount = 10000; + $request->description = 'Test Payment'; + $request->callback_url = 'https://callback.url'; + $request->mobile = '09370000000'; + $request->email = 'test@example.com'; + + $response = $this->gateway->request($request); + $this->assertEquals('A00000000000000000000000000123456', $response->authority); + } + + public function testVerify() + { + $responseBody = [ + 'data' => [ + 'code' => 100, + 'ref_id' => '1234567890', + ], + 'errors' => [] + ]; + + $this->clientMock->expects($this->once()) + ->method('post') + ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + + $verify = new VerifyRequest(); + $verify->amount = 15000; + $verify->authority = 'A00000000000000000000000000123456'; + + $response = $this->gateway->verify($verify); + $this->assertEquals(100, $response->code); + } + + public function testUnverified() + { + $responseBody = [ + 'data' => [ + 'list' => [ + ['authority' => 'A00000000000000000000000000123456'], + ['authority' => 'B00000000000000000000000000123457'], + ] + ], + 'errors' => [] + ]; + + $this->clientMock->expects($this->once()) + ->method('post') + ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + + $unverified = new UnverifiedRequest(); + + $response = $this->gateway->unverified($unverified); + $this->assertCount(2, $response->list); + $this->assertEquals('A00000000000000000000000000123456', $response->list[0]['authority']); + } + + public function testReverse() + { + $responseBody = [ + 'data' => [ + 'status' => 'Success', + ], + 'errors' => [] + ]; + + $this->clientMock->expects($this->once()) + ->method('post') + ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + + $reverseRequest = new ReverseRequest($this->getOptions()); + $reverseRequest->authority = 'A00000000000000000000000000123456'; + + $response = $this->gateway->reverse($reverseRequest); + $this->assertEquals('Success', $response->status); + } + + public function testInquiry() + { + $responseBody = [ + 'data' => [ + 'amount' => 15000, + ], + 'errors' => [] + ]; + + $this->clientMock->expects($this->once()) + ->method('post') + ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + + $inquiryRequest = new InquiryRequest($this->getOptions()); + $inquiryRequest->authority = 'A00000000000000000000000000123456'; + + $response = $this->gateway->inquiry($inquiryRequest); + $this->assertEquals(15000, $response->amount); + } +} From 4ee45750a718c7a7d97ffd5d7419a03d1eb07a67 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Wed, 11 Sep 2024 19:20:44 +0330 Subject: [PATCH 09/23] chnage --- examples/basic-client.php | 17 ++++++++++++++--- src/Endpoint/PaymentGateway/PaymentGateway.php | 18 +++++++++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/examples/basic-client.php b/examples/basic-client.php index aa2f9f2..ffe0751 100644 --- a/examples/basic-client.php +++ b/examples/basic-client.php @@ -9,6 +9,7 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\VerifyRequest; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\ReverseRequest; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\InquiryRequest; +use ZarinPal\Sdk\HttpClient\Exception\ResponseException; use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; @@ -36,7 +37,7 @@ //$request->wages = [ // [ // 'iban' => 'IR130570028780010957775103', -// 'amount' =>, +// 'amount' =>5000, // 'description' => 'تسهیم سود فروش' // ], // [ @@ -58,8 +59,18 @@ $inquiryRequest = new InquiryRequest($options); $inquiryRequest->authority = 'A00000000000000000000000000123456'; -$response = $sdk->paymentGateway()->request($request); -die(var_dump($response)); +try { + $response = $sdk->paymentGateway()->request($request); + // نمایش نتیجه در صورت موفقیت + echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); +} catch (ResponseException $e) { + // خطا به صورت JSON برمی‌گردد، بدون اینکه برنامه قطع شود + echo "Error: " . $e->getMessage(); +} catch (Exception $e) { + // هندل کردن دیگر خطاهای غیرمنتظره + echo "Unexpected Error: " . $e->getMessage(); +} +die(); $response2 = $sdk->paymentGateway()->verify($verify); $response3 = $sdk->paymentGateway()->unverified($unverified); $response4 = $sdk->paymentGateway()->reverse($reverseRequest); diff --git a/src/Endpoint/PaymentGateway/PaymentGateway.php b/src/Endpoint/PaymentGateway/PaymentGateway.php index 4416ca2..b6c66b5 100644 --- a/src/Endpoint/PaymentGateway/PaymentGateway.php +++ b/src/Endpoint/PaymentGateway/PaymentGateway.php @@ -117,14 +117,22 @@ private function checkHttpError(ResponseInterface $response): void $code = $statusCode; } - echo "HTTP Status Code: $statusCode\n"; - echo "Error Code: $code\n"; - echo "Error Message: $message\n"; - - throw new ResponseException($message, $code); + // Create the error response as an array + $errorResponse = [ + 'http_status_code' => $statusCode, + 'error_code' => $code, + 'error_message' => $message, + ]; + + // Convert the error response to JSON + $errorJson = json_encode($errorResponse, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + + // Instead of displaying the error, throw it as JSON + throw new ResponseException($errorJson, $code); } } + private function checkPaymentGatewayError(array $response): array { if (!empty($response['errors']) || empty($response['data'])) { From 8bf4152be99ae6b0abcfdd97812ee11e730d1133 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Sat, 14 Sep 2024 21:28:01 +0330 Subject: [PATCH 10/23] update --- examples/Inquiry.php | 9 +++--- examples/Refund.php | 2 +- examples/Request.php | 26 ++++++++++++----- examples/Reverse.php | 9 +++--- examples/Transaction.php | 29 ++++++++++++------- examples/Verify.php | 8 ++--- examples/basic-client.php | 24 +++++++-------- .../ResponseTypes/TransactionListResponse.php | 4 +-- .../RequestTypes/InquiryRequest.php | 9 ++---- .../RequestTypes/ReverseRequest.php | 9 ++---- .../RequestTypes/VerifyRequest.php | 2 +- tests/PaymentGateway/PaymentGatewayTest.php | 16 +++++----- 12 files changed, 80 insertions(+), 67 deletions(-) diff --git a/examples/Inquiry.php b/examples/Inquiry.php index f2c42f8..700978a 100644 --- a/examples/Inquiry.php +++ b/examples/Inquiry.php @@ -1,25 +1,26 @@ 'your_merchant_id_here', + 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); $inquiryRequest = new InquiryRequest(); -$inquiryRequest->authority = 'A00000000000000000000000000123456'; // Authority from the original transaction +$inquiryRequest->authority = 'A000000000000000000000000000ydq5y838'; // Authority from the original transaction try { $response = $paymentGateway->inquiry($inquiryRequest); echo "Transaction Inquiry: \n"; - echo "Amount: " . $response->amount . "\n"; + echo "Amount: " . $response->code . "\n"; + echo "Status: " . $response->message . "\n"; echo "Status: " . $response->status . "\n"; } catch (\Exception $e) { echo 'Transaction inquiry failed: ' . $e->getMessage(); diff --git a/examples/Refund.php b/examples/Refund.php index 19f4aab..b121533 100644 --- a/examples/Refund.php +++ b/examples/Refund.php @@ -1,6 +1,6 @@ false, // Enable sandbox mode - 'merchant_id' => 'your_merchant_id_here', + 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); $request = new RequestRequest(); -$request->amount = 10000; // Amount in IRR +$request->amount = 1000; // Amount in IRR $request->description = 'Payment for order 12345'; -$request->callback_url = 'https://yourcallbackurl.com'; +$request->callback_url = 'http://localhost:8000/examples/verify.php'; $request->mobile = '09121234567'; // Optional $request->email = 'test@example.com'; // Optional +//$request->wages = [ +// [ +// 'iban' => 'IR130570028780010957775103', +// 'amount' =>5000, +// 'description' => 'تسهیم سود فروش' +// ], +// [ +// 'iban' => 'IR670170000000352965862009', +// 'amount' => 5000, +// 'description' => 'تسهیم سود فروش به شخص دوم' +// ] +//]; try { $response = $paymentGateway->request($request); - echo "Payment Request Successful: \n"; - echo "Authority: " . $response->authority . "\n"; - echo "Payment URL: " . $paymentGateway->getRedirectUrl($response->authority) . "\n"; + $url = $paymentGateway->getRedirectUrl($response->authority); + header('Location:'. $url); + } catch (\Exception $e) { echo 'Payment request failed: ' . $e->getMessage(); } diff --git a/examples/Reverse.php b/examples/Reverse.php index 912524b..87c826b 100644 --- a/examples/Reverse.php +++ b/examples/Reverse.php @@ -1,24 +1,25 @@ 'your_merchant_id_here', + 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); $reverseRequest = new ReverseRequest(); -$reverseRequest->authority = 'A00000000000000000000000000123456'; // Authority from the original transaction +$reverseRequest->authority = 'A000000000000000000000000000ydq5y838'; // Authority from the original transaction try { $response = $paymentGateway->reverse($reverseRequest); - echo "Transaction Reversed: " . $response->status . "\n"; + echo "Transaction Reversed: " . $response->code . "\n"; + echo "Transaction Reversed: " . $response->message . "\n"; } catch (\Exception $e) { echo 'Transaction reversal failed: ' . $e->getMessage(); } diff --git a/examples/Transaction.php b/examples/Transaction.php index 987bf71..7779985 100644 --- a/examples/Transaction.php +++ b/examples/Transaction.php @@ -1,30 +1,39 @@ 'your_access_token_here', + 'access_token' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiZWU3MjgzZDQ0MzI1ZTJlMDdkODdhM2MzMDc2MzUzMWExZTYyZDI4OWMzOGMxZWY2ODI0NmRkZWZkYTRjZmNlMzY5NjVkMDQ0YjA1ZTMwNGMiLCJpYXQiOjE3MjQ2MTY3MjcuMTU5NTU5LCJuYmYiOjE3MjQ2MTY3MjcuMTU5NTYyLCJleHAiOjE4ODIzODMxMjcuMTIwOTkzLCJzdWIiOiIxMjE3NDYiLCJzY29wZXMiOltdfQ.L7CXjwVQQ0Pm0Ou4-7ALmKXZNHxUvrEvtvwe8i2H_zbcHTUZE51Gzd-wuO5gci09RalsshrOOwZ0UUZfCczuY8P8PfZTvvo5P6pzu6uhiU5FsEgyb8LNyyRakDXDkIekmyfDC-l3Y2dveBG2uAEfg4TflqjSJ-XIgeu4e9l8rnhWC91FS7d854aEqc7anpEbtetQG2gRSbAGgIWq6PA8laanX1Cj0eImUhsdG2B6raX4jTLfmn8bZ4bSmVNbTmgp7ltNGTLlU4ESbYCk79XhcUnGfYt59aeV0P_U82OVIXG0FBhKqrI4p8yJHbcObJgmSymLiZesZXlGfUST6I9u3fsaFCxd3BBFelrI84t6mTyabAEq7eGPJOlIu7pZbHtu3xCoNJoUKjPvltel1Ua25ENuY9GZa2rMFKl1hvSpkZYpJf9ZrYO7lQhxAoOufW-z9YehPD4axRQybVCFRYQ-Co1FczDU7RQPQ91-QBy34Z98Nj8qtl3pg00QieXLLHJHq2l5_ePzXb6-uLnQqIcpu2Sjrm9zObJkwcZ6pqASd4PVHDd76O27hDQ46q_Au3bQ5lm1MphSQ1yST5kpFNaTp8e0TvmkV8URsv8O0Ll9fT16Mf0faCgydtSv6K7saySnB6egs8MaB5qlMZf6oO1FcoJ3Cv9DJm56AxmYFYdYEgU', ]); $transactionService = new TransactionService($options); $transactionRequest = new TransactionListRequest(); -$transactionRequest->terminalId = '238'; +$transactionRequest->terminalId = '250'; $transactionRequest->filter = 'PAID'; // Optional filter: PAID, VERIFIED, TRASH, ACTIVE, REFUNDED try { $transactions = $transactionService->getTransactions($transactionRequest); + + $transactionArray = []; foreach ($transactions as $transaction) { - echo "Transaction ID: " . $transaction->id . "\n"; - echo "Status: " . $transaction->status . "\n"; - echo "Amount: " . $transaction->amount . "\n"; - echo "Description: " . $transaction->description . "\n"; - echo "Created At: " . $transaction->created_at . "\n\n"; + $transactionArray[] = [ + 'Transaction ID' => $transaction->id, + 'Status' => $transaction->status, + 'Amount' => $transaction->amount, + 'Description' => $transaction->description, + 'Created At' => $transaction->created_at, + ]; } -} catch (\Exception $e) { - echo 'Failed to retrieve transactions: ' . $e->getMessage(); + + echo json_encode($transactionArray, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); +} catch (ResponseException $e) { + echo "GraphQL Error: " . $e->getMessage(); +} catch (Exception $e) { + echo "General Error: " . $e->getMessage(); } diff --git a/examples/Verify.php b/examples/Verify.php index 4ef44cf..4b2511a 100644 --- a/examples/Verify.php +++ b/examples/Verify.php @@ -1,21 +1,21 @@ 'your_merchant_id_here', + 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); $verifyRequest = new VerifyRequest(); -$verifyRequest->authority = 'A00000000000000000000000000123456'; // The authority code returned by the initial payment request -$verifyRequest->amount = 15000; // Amount in IRR +$verifyRequest->authority = 'A000000000000000000000000000ydq5y838'; // The authority code returned by the initial payment request +$verifyRequest->amount = 1000; // Amount in IRR try { $response = $paymentGateway->verify($verifyRequest); diff --git a/examples/basic-client.php b/examples/basic-client.php index ffe0751..1174116 100644 --- a/examples/basic-client.php +++ b/examples/basic-client.php @@ -34,18 +34,18 @@ $request->email = 'a@b.c'; $request->currency = 'IRT'; $request->cardPan = '5022291083818920'; -//$request->wages = [ -// [ -// 'iban' => 'IR130570028780010957775103', -// 'amount' =>5000, -// 'description' => 'تسهیم سود فروش' -// ], -// [ -// 'iban' => 'IR670170000000352965862009', -// 'amount' => 5000, -// 'description' => 'تسهیم سود فروش به شخص دوم' -// ] -//]; +$request->wages = [ + [ + 'iban' => 'IR130570028780010957775103', + 'amount' =>5000, + 'description' => 'تسهیم سود فروش' + ], + [ + 'iban' => 'IR670170000000352965862009', + 'amount' => 5000, + 'description' => 'تسهیم سود فروش به شخص دوم' + ] +]; $verify = new VerifyRequest(); $verify->amount = 15000; diff --git a/src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php b/src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php index 91c08c4..d66c68f 100644 --- a/src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php +++ b/src/Endpoint/GraphQL/ResponseTypes/TransactionListResponse.php @@ -12,7 +12,7 @@ class TransactionListResponse public string $status; public int $amount; public string $description; - public string $createdAt; + public string $created_at; public function __construct(array $data) { @@ -20,6 +20,6 @@ public function __construct(array $data) $this->status = $data['status']; $this->amount = $data['amount']; $this->description = $data['description']; - $this->createdAt = $data['created_at']; + $this->created_at = $data['created_at']; } } diff --git a/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php index 0b628e2..61a6789 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php @@ -10,14 +10,9 @@ class InquiryRequest { use Fillable; - public string $merchantId; + public ?string $merchantId = null; public string $authority; - public function __construct(Options $options) - { - $this->merchantId = $options->getMerchantId(); - } - public function validate(): void { $this->validateMerchantId(); @@ -33,7 +28,7 @@ private function validateMerchantId(): void private function validateAuthority(): void { - if ($this->authority === null || !preg_match('/^A[0-9a-zA-Z]{32}$/', $this->authority)) { + if (!preg_match('/^A[0-9a-zA-Z]{35}$/', $this->authority)) { throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); } } diff --git a/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php index 22f6f21..7b3a0b5 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php @@ -10,14 +10,9 @@ class ReverseRequest { use Fillable; - public string $merchantId; + public ?string $merchantId = null; public string $authority; - public function __construct(Options $options) - { - $this->merchantId = $options->getMerchantId(); - } - public function validate(): void { $this->validateMerchantId(); @@ -33,7 +28,7 @@ private function validateMerchantId(): void private function validateAuthority(): void { - if ($this->authority === null || !preg_match('/^A[0-9a-zA-Z]{32}$/', $this->authority)) { + if (!preg_match('/^A[0-9a-zA-Z]{35}$/', $this->authority)) { throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); } } diff --git a/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php index 14063a8..2d5df35 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php @@ -37,7 +37,7 @@ private function validateAmount(): void private function validateAuthority(): void { - if ($this->authority === null || !preg_match('/^A[0-9a-zA-Z]{32}$/', $this->authority)) { + if (!preg_match('/^A[0-9a-zA-Z]{35}$/', $this->authority)) { throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); } } diff --git a/tests/PaymentGateway/PaymentGatewayTest.php b/tests/PaymentGateway/PaymentGatewayTest.php index a21e8b8..3b252dc 100644 --- a/tests/PaymentGateway/PaymentGatewayTest.php +++ b/tests/PaymentGateway/PaymentGatewayTest.php @@ -69,7 +69,7 @@ public function testVerify() $verify = new VerifyRequest(); $verify->amount = 15000; - $verify->authority = 'A00000000000000000000000000123456'; + $verify->authority = 'A000000000000000000000000000ydq5y838'; $response = $this->gateway->verify($verify); $this->assertEquals(100, $response->code); @@ -80,8 +80,8 @@ public function testUnverified() $responseBody = [ 'data' => [ 'list' => [ - ['authority' => 'A00000000000000000000000000123456'], - ['authority' => 'B00000000000000000000000000123457'], + ['authority' => 'A000000000000000000000000000ydq5y838'], + ['authority' => 'A000000000000000000000000000ydq5y839'], ] ], 'errors' => [] @@ -95,7 +95,7 @@ public function testUnverified() $response = $this->gateway->unverified($unverified); $this->assertCount(2, $response->list); - $this->assertEquals('A00000000000000000000000000123456', $response->list[0]['authority']); + $this->assertEquals('A000000000000000000000000000ydq5y838', $response->list[0]['authority']); } public function testReverse() @@ -111,8 +111,8 @@ public function testReverse() ->method('post') ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); - $reverseRequest = new ReverseRequest($this->getOptions()); - $reverseRequest->authority = 'A00000000000000000000000000123456'; + $reverseRequest = new ReverseRequest(); + $reverseRequest->authority = 'A000000000000000000000000000ydq5y838'; $response = $this->gateway->reverse($reverseRequest); $this->assertEquals('Success', $response->status); @@ -131,8 +131,8 @@ public function testInquiry() ->method('post') ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); - $inquiryRequest = new InquiryRequest($this->getOptions()); - $inquiryRequest->authority = 'A00000000000000000000000000123456'; + $inquiryRequest = new InquiryRequest(); + $inquiryRequest->authority = 'A000000000000000000000000000ydq5y838'; $response = $this->gateway->inquiry($inquiryRequest); $this->assertEquals(15000, $response->amount); From 14e9101355186621f76bdae3df929c70355cf611 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Sun, 15 Sep 2024 21:36:41 +0330 Subject: [PATCH 11/23] Update Refund --- examples/Refund.php | 8 ++++---- examples/Reverse.php | 4 ++-- src/Endpoint/GraphQL/RefundService.php | 11 +++++++++-- tests/Graphql/GraphQLRefundTest.php | 11 +++++++---- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/examples/Refund.php b/examples/Refund.php index b121533..2433fbc 100644 --- a/examples/Refund.php +++ b/examples/Refund.php @@ -7,13 +7,13 @@ use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest; $options = new Options([ - 'access_token' => 'your_access_token_here', + 'access_token' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiNjA5NWNjOWYzNDUxZjMyZmQ3ODYxYTFhZWEyM2QwZGJkNWYxMjY0YmFhNDVkYjJjZjJlNzc2MGMzNTMwMzY5MzAyZjdlYTk1OGY0MDM5NmEiLCJpYXQiOjE3MjYzOTMyMjMuNTI5MTM2LCJuYmYiOjE3MjYzOTMyMjMuNTI5MTM4LCJleHAiOjE4ODQxNTk2MjMuNDk1OTMzLCJzdWIiOiIxNDQxNDU3Iiwic2NvcGVzIjpbXX0.tluhzZ7aT7I3x4fD07793nZfMgw11fyHy3x5igPrthVBX7KduuoM4j0KHWszOH9C56me7FJFOX-wm8mf-AILv8W0Up26KVIKRFThDRaOMlnjQ11b0aD9vkZdEoQP6Lb8Z1UsSIq699cRtpbunAPbVj6kr5Cq9aiPVqiUKl_93qshC8kTHpjoIAwvG3614AXQNLXgKhCVmv8Ky8TbV3nqW5AuSB20WTNdouz0ASiwKlU3B3rKsIZAAJ5toe-WGhMjReeIqA_vjX4BN-XmDuthYXOtQqXu4z6UG_M_8B_z2ihliwTAFL1qw3YBSo7u5Pr0U2pggLYsql1IcKVtNHj2AaMefkVd4NEuy4rgcNjK1JPCTyOoE4lLR7AdwlgBxMQ8ZXHDLPE2W75TKR48sh00pOhf6B_f0ptF6aM0_FP4DdSH87F4OdE8GRbUBAwVmVhkMCelfpc1pbAvKB9v3SpojupqkPB4-Xb_Qrd7-VP0aiXhxN0s5oKhszci5OihkfqjDGXaVjQCS3DzjveD0JUQBw-NCFtPj6BOskGVpAWjPKOEpXnQJkYmbU8tvfq_xIUCYvextEOMi6BvwyJSxAxSJbAY5hxY10sdblobaVxmaD-xcR8vwYwebq1JZx4v5WlhFLK2RNNg6g6sEqkXMZTDCcXIRIKcPzCMOuiHEEKx9Pk', ]); $refundService = new RefundService($options); $refundRequest = new RefundRequest(); -$refundRequest->sessionId = '385404539'; +$refundRequest->sessionId = '580868147'; $refundRequest->amount = 20000; // Amount in IRR $refundRequest->description = 'Refund for order 12345'; $refundRequest->method = 'CARD'; // Method: CARD for instant, PAYA for regular @@ -23,10 +23,10 @@ $response = $refundService->refund($refundRequest); echo "Refund Processed: \n"; echo "Transaction ID: " . $response->id . "\n"; - echo "Terminal ID: " . $response->terminal_id . "\n"; + echo "Terminal ID: " . $response->terminalId . "\n"; echo "Refund Amount: " . $response->timeline['refund_amount'] . "\n"; echo "Refund Time: " . $response->timeline['refund_time'] . "\n"; echo "Refund Status: " . $response->timeline['refund_status'] . "\n"; } catch (\Exception $e) { - echo 'Refund failed: ' . $e->getMessage(); + echo 'Refund failed: ' . $response; } diff --git a/examples/Reverse.php b/examples/Reverse.php index 87c826b..7551598 100644 --- a/examples/Reverse.php +++ b/examples/Reverse.php @@ -7,14 +7,14 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\ReverseRequest; $options = new Options([ - 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', + 'merchant_id' => 'efb22724-c8d3-46c8-a4e7-f87b0e07748e', ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); $reverseRequest = new ReverseRequest(); -$reverseRequest->authority = 'A000000000000000000000000000ydq5y838'; // Authority from the original transaction +$reverseRequest->authority = 'A000000000000000000000000000opo6w6y8'; // Authority from the original transaction try { $response = $paymentGateway->reverse($reverseRequest); diff --git a/src/Endpoint/GraphQL/RefundService.php b/src/Endpoint/GraphQL/RefundService.php index 3458019..9cfb8be 100644 --- a/src/Endpoint/GraphQL/RefundService.php +++ b/src/Endpoint/GraphQL/RefundService.php @@ -22,7 +22,7 @@ public function __construct(Options $options) $this->graphqlUrl = $options->getGraphqlUrl(); } - public function refund(RefundRequest $request): array + public function refund(RefundRequest $request): RefundResponse { $query = $request->toGraphQL(); try { @@ -34,14 +34,21 @@ public function refund(RefundRequest $request): array 'body' => $query, ]); - $responseData = $response->toArray(); + // Decode the JSON response to an array + $responseData = json_decode($response->getBody()->getContents(), true); + + // Check for errors in the response if (isset($responseData['errors'])) { throw new ResponseException('GraphQL query error: ' . json_encode($responseData['errors'])); } + // Return a new RefundResponse with the data from the response return new RefundResponse($responseData['data']['resource']); + } catch (RequestException $e) { throw new ResponseException('Request failed: ' . $e->getMessage(), 0, $e); + } catch (\Exception $e) { + throw new ResponseException('An unexpected error occurred: ' . $e->getMessage(), 0, $e); } } } diff --git a/tests/Graphql/GraphQLRefundTest.php b/tests/Graphql/GraphQLRefundTest.php index 7ec23ea..6f31240 100644 --- a/tests/Graphql/GraphQLRefundTest.php +++ b/tests/Graphql/GraphQLRefundTest.php @@ -5,6 +5,7 @@ use Tests\BaseTestCase; use ZarinPal\Sdk\Endpoint\GraphQL\RefundService; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest; +use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\RefundResponse; class GraphQLRefundTest extends BaseTestCase { @@ -23,7 +24,7 @@ public function testRefund() $refundRequest->amount = 20000; $refundRequest->description = 'Test Refund'; - $mockResponse = [ + $mockResponse = new RefundResponse([ 'id' => '1234567890', 'terminal_id' => '238', 'amount' => 20000, @@ -32,13 +33,15 @@ public function testRefund() 'refund_time' => '2024-08-25T15:00:00+03:30', 'refund_status' => 'PENDING' ] - ]; + ]); $this->refundService->method('refund')->willReturn($mockResponse); $response = $this->refundService->refund($refundRequest); - $this->assertArrayHasKey('id', $response); - $this->assertEquals('1234567890', $response['id']); + $this->assertEquals('1234567890', $response->id); + $this->assertEquals(20000, $response->amount); + $this->assertArrayHasKey('refund_status', $response->timeline); } + } From 183c1cd7a715f8d168b7efc6b3e7d380d1acb822 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Wed, 18 Sep 2024 20:25:05 +0330 Subject: [PATCH 12/23] Update Sample --- composer.json | 1 + examples/Inquiry.php | 4 ++-- examples/Refund.php | 4 ++-- examples/Request.php | 12 +++++++----- examples/Reverse.php | 2 +- examples/Transaction.php | 2 +- examples/Verify.php | 4 ++-- examples/basic-client.php | 3 +-- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index b65427d..e83d6dd 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,7 @@ "php-http/client-common": "^2.5", "php-http/discovery": "^1.14", "ext-json": "*", + "ext-curl": "*", "psr/http-client-implementation": "*", "symfony/http-client": "^7.1", "guzzlehttp/guzzle": "^7.9" diff --git a/examples/Inquiry.php b/examples/Inquiry.php index 700978a..a3f030b 100644 --- a/examples/Inquiry.php +++ b/examples/Inquiry.php @@ -7,14 +7,14 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\InquiryRequest; $options = new Options([ - 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', + 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); $inquiryRequest = new InquiryRequest(); -$inquiryRequest->authority = 'A000000000000000000000000000ydq5y838'; // Authority from the original transaction +$inquiryRequest->authority = 'A000000000000000000000000000ydq5y838'; try { $response = $paymentGateway->inquiry($inquiryRequest); diff --git a/examples/Refund.php b/examples/Refund.php index 2433fbc..91c2c50 100644 --- a/examples/Refund.php +++ b/examples/Refund.php @@ -7,7 +7,7 @@ use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest; $options = new Options([ - 'access_token' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiNjA5NWNjOWYzNDUxZjMyZmQ3ODYxYTFhZWEyM2QwZGJkNWYxMjY0YmFhNDVkYjJjZjJlNzc2MGMzNTMwMzY5MzAyZjdlYTk1OGY0MDM5NmEiLCJpYXQiOjE3MjYzOTMyMjMuNTI5MTM2LCJuYmYiOjE3MjYzOTMyMjMuNTI5MTM4LCJleHAiOjE4ODQxNTk2MjMuNDk1OTMzLCJzdWIiOiIxNDQxNDU3Iiwic2NvcGVzIjpbXX0.tluhzZ7aT7I3x4fD07793nZfMgw11fyHy3x5igPrthVBX7KduuoM4j0KHWszOH9C56me7FJFOX-wm8mf-AILv8W0Up26KVIKRFThDRaOMlnjQ11b0aD9vkZdEoQP6Lb8Z1UsSIq699cRtpbunAPbVj6kr5Cq9aiPVqiUKl_93qshC8kTHpjoIAwvG3614AXQNLXgKhCVmv8Ky8TbV3nqW5AuSB20WTNdouz0ASiwKlU3B3rKsIZAAJ5toe-WGhMjReeIqA_vjX4BN-XmDuthYXOtQqXu4z6UG_M_8B_z2ihliwTAFL1qw3YBSo7u5Pr0U2pggLYsql1IcKVtNHj2AaMefkVd4NEuy4rgcNjK1JPCTyOoE4lLR7AdwlgBxMQ8ZXHDLPE2W75TKR48sh00pOhf6B_f0ptF6aM0_FP4DdSH87F4OdE8GRbUBAwVmVhkMCelfpc1pbAvKB9v3SpojupqkPB4-Xb_Qrd7-VP0aiXhxN0s5oKhszci5OihkfqjDGXaVjQCS3DzjveD0JUQBw-NCFtPj6BOskGVpAWjPKOEpXnQJkYmbU8tvfq_xIUCYvextEOMi6BvwyJSxAxSJbAY5hxY10sdblobaVxmaD-xcR8vwYwebq1JZx4v5WlhFLK2RNNg6g6sEqkXMZTDCcXIRIKcPzCMOuiHEEKx9Pk', + 'access_token' => 'your access token', // Access token without Bearer ]); $refundService = new RefundService($options); @@ -28,5 +28,5 @@ echo "Refund Time: " . $response->timeline['refund_time'] . "\n"; echo "Refund Status: " . $response->timeline['refund_status'] . "\n"; } catch (\Exception $e) { - echo 'Refund failed: ' . $response; + echo 'Refund failed: ' . $e->getMessage(); } diff --git a/examples/Request.php b/examples/Request.php index 510dc9b..ae4bc1c 100644 --- a/examples/Request.php +++ b/examples/Request.php @@ -15,11 +15,13 @@ $paymentGateway = $zarinpal->paymentGateway(); $request = new RequestRequest(); -$request->amount = 1000; // Amount in IRR +$request->amount = 10000; //Minimum amount 10000 IRR $request->description = 'Payment for order 12345'; -$request->callback_url = 'http://localhost:8000/examples/verify.php'; -$request->mobile = '09121234567'; // Optional +$request->callback_url = 'https://your-site/examples/verify.php'; +$request->mobile = '09220949640'; // Optional $request->email = 'test@example.com'; // Optional +$request->currency = 'IRR'; // Optional IRR Or IRT (default IRR) +$request->cardPan = '5894631122689482'; // Optional //$request->wages = [ // [ // 'iban' => 'IR130570028780010957775103', @@ -31,11 +33,11 @@ // 'amount' => 5000, // 'description' => 'تسهیم سود فروش به شخص دوم' // ] -//]; +//]; //Optional try { $response = $paymentGateway->request($request); - $url = $paymentGateway->getRedirectUrl($response->authority); + $url = $paymentGateway->getRedirectUrl($response->authority); // create full url Payment header('Location:'. $url); } catch (\Exception $e) { diff --git a/examples/Reverse.php b/examples/Reverse.php index 7551598..bc39c65 100644 --- a/examples/Reverse.php +++ b/examples/Reverse.php @@ -7,7 +7,7 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\ReverseRequest; $options = new Options([ - 'merchant_id' => 'efb22724-c8d3-46c8-a4e7-f87b0e07748e', + 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', ]); $zarinpal = new ZarinPal($options); diff --git a/examples/Transaction.php b/examples/Transaction.php index 7779985..6fa1486 100644 --- a/examples/Transaction.php +++ b/examples/Transaction.php @@ -8,7 +8,7 @@ use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\TransactionListRequest; $options = new Options([ - 'access_token' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiZWU3MjgzZDQ0MzI1ZTJlMDdkODdhM2MzMDc2MzUzMWExZTYyZDI4OWMzOGMxZWY2ODI0NmRkZWZkYTRjZmNlMzY5NjVkMDQ0YjA1ZTMwNGMiLCJpYXQiOjE3MjQ2MTY3MjcuMTU5NTU5LCJuYmYiOjE3MjQ2MTY3MjcuMTU5NTYyLCJleHAiOjE4ODIzODMxMjcuMTIwOTkzLCJzdWIiOiIxMjE3NDYiLCJzY29wZXMiOltdfQ.L7CXjwVQQ0Pm0Ou4-7ALmKXZNHxUvrEvtvwe8i2H_zbcHTUZE51Gzd-wuO5gci09RalsshrOOwZ0UUZfCczuY8P8PfZTvvo5P6pzu6uhiU5FsEgyb8LNyyRakDXDkIekmyfDC-l3Y2dveBG2uAEfg4TflqjSJ-XIgeu4e9l8rnhWC91FS7d854aEqc7anpEbtetQG2gRSbAGgIWq6PA8laanX1Cj0eImUhsdG2B6raX4jTLfmn8bZ4bSmVNbTmgp7ltNGTLlU4ESbYCk79XhcUnGfYt59aeV0P_U82OVIXG0FBhKqrI4p8yJHbcObJgmSymLiZesZXlGfUST6I9u3fsaFCxd3BBFelrI84t6mTyabAEq7eGPJOlIu7pZbHtu3xCoNJoUKjPvltel1Ua25ENuY9GZa2rMFKl1hvSpkZYpJf9ZrYO7lQhxAoOufW-z9YehPD4axRQybVCFRYQ-Co1FczDU7RQPQ91-QBy34Z98Nj8qtl3pg00QieXLLHJHq2l5_ePzXb6-uLnQqIcpu2Sjrm9zObJkwcZ6pqASd4PVHDd76O27hDQ46q_Au3bQ5lm1MphSQ1yST5kpFNaTp8e0TvmkV8URsv8O0Ll9fT16Mf0faCgydtSv6K7saySnB6egs8MaB5qlMZf6oO1FcoJ3Cv9DJm56AxmYFYdYEgU', + 'access_token' => 'your access token', // Access token without Bearer ]); $transactionService = new TransactionService($options); diff --git a/examples/Verify.php b/examples/Verify.php index 4b2511a..dab1a1a 100644 --- a/examples/Verify.php +++ b/examples/Verify.php @@ -7,7 +7,7 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\VerifyRequest; $options = new Options([ - 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', + 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', ]); $zarinpal = new ZarinPal($options); @@ -15,7 +15,7 @@ $verifyRequest = new VerifyRequest(); $verifyRequest->authority = 'A000000000000000000000000000ydq5y838'; // The authority code returned by the initial payment request -$verifyRequest->amount = 1000; // Amount in IRR +$verifyRequest->amount = 10000; // Amount try { $response = $paymentGateway->verify($verifyRequest); diff --git a/examples/basic-client.php b/examples/basic-client.php index 1174116..8c2a97f 100644 --- a/examples/basic-client.php +++ b/examples/basic-client.php @@ -21,7 +21,7 @@ // usage $options = new Options([ 'client_builder' => $clientBuilder, - 'merchant_id' => '25fe4c36-66e4-11e9-a9e4-000c29344814', + 'merchant_id' => 'x1379bc04-196d-47bb-a8f0-0e969ec96179', ]); $sdk = new ZarinPal($options); @@ -70,7 +70,6 @@ // هندل کردن دیگر خطاهای غیرمنتظره echo "Unexpected Error: " . $e->getMessage(); } -die(); $response2 = $sdk->paymentGateway()->verify($verify); $response3 = $sdk->paymentGateway()->unverified($unverified); $response4 = $sdk->paymentGateway()->reverse($reverseRequest); From 4a024eba07419eaf3d375566e21f52d442320029 Mon Sep 17 00:00:00 2001 From: Armin Zahedi <00001212aa@gmail.com> Date: Sun, 22 Sep 2024 03:17:12 +0330 Subject: [PATCH 13/23] Update Examples --- examples/Request.php | 34 ++++++---- examples/Verify.php | 66 +++++++++++++++---- examples/unVerified.php | 37 +++++++++++ .../ResponseTypes/UnverifiedResponse.php | 30 +++++++-- tests/PaymentGateway/PaymentGatewayTest.php | 36 ++++++++-- 5 files changed, 167 insertions(+), 36 deletions(-) create mode 100644 examples/unVerified.php diff --git a/examples/Request.php b/examples/Request.php index ae4bc1c..0a2ed88 100644 --- a/examples/Request.php +++ b/examples/Request.php @@ -2,13 +2,21 @@ require_once __DIR__ . '/../vendor/autoload.php'; +use Http\Client\Common\Plugin\HeaderDefaultsPlugin; +use ZarinPal\Sdk\ClientBuilder; use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\RequestRequest; +$clientBuilder = new ClientBuilder(); +$clientBuilder->addPlugin(new HeaderDefaultsPlugin([ + 'Accept' => 'application/json', +])); + $options = new Options([ + 'client_builder' => $clientBuilder, 'sandbox' => false, // Enable sandbox mode - 'merchant_id' => '1379bc04-196d-47bb-a8f0-0e969ec96179', + 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', ]); $zarinpal = new ZarinPal($options); @@ -22,18 +30,18 @@ $request->email = 'test@example.com'; // Optional $request->currency = 'IRR'; // Optional IRR Or IRT (default IRR) $request->cardPan = '5894631122689482'; // Optional -//$request->wages = [ -// [ -// 'iban' => 'IR130570028780010957775103', -// 'amount' =>5000, -// 'description' => 'تسهیم سود فروش' -// ], -// [ -// 'iban' => 'IR670170000000352965862009', -// 'amount' => 5000, -// 'description' => 'تسهیم سود فروش به شخص دوم' -// ] -//]; //Optional +$request->wages = [ + [ + 'iban' => 'IR130570028780010957775103', + 'amount' =>5000, + 'description' => 'تسهیم سود فروش' + ], + [ + 'iban' => 'IR670170000000352965862009', + 'amount' => 5000, + 'description' => 'تسهیم سود فروش به شخص دوم' + ] +]; //Optional try { $response = $paymentGateway->request($request); diff --git a/examples/Verify.php b/examples/Verify.php index dab1a1a..15e49cd 100644 --- a/examples/Verify.php +++ b/examples/Verify.php @@ -2,26 +2,68 @@ require_once __DIR__ . '/../vendor/autoload.php'; +use Http\Client\Common\Plugin\HeaderDefaultsPlugin; +use ZarinPal\Sdk\ClientBuilder; use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\VerifyRequest; +// ایجاد ClientBuilder برای تنظیم هدرهای پیش‌فرض +$clientBuilder = new ClientBuilder(); +$clientBuilder->addPlugin(new HeaderDefaultsPlugin([ + 'Accept' => 'application/json', +])); + +// پیکربندی SDK $options = new Options([ - 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + 'client_builder' => $clientBuilder, + 'sandbox' => false, // غیرفعال‌سازی حالت تستی برای تراکنش‌های واقعی + 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', // Merchant ID شما ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); -$verifyRequest = new VerifyRequest(); -$verifyRequest->authority = 'A000000000000000000000000000ydq5y838'; // The authority code returned by the initial payment request -$verifyRequest->amount = 10000; // Amount - -try { - $response = $paymentGateway->verify($verifyRequest); - echo "Payment Verified: \n"; - echo "Reference ID: " . $response->ref_id . "\n"; - echo "Code: " . $response->code . "\n"; -} catch (\Exception $e) { - echo 'Payment verification failed: ' . $e->getMessage(); +// دریافت authority و status از کوئری استرینگ +$authority = $_GET['Authority']; +$status = $_GET['Status']; + +// بررسی وضعیت تراکنش +if ($status === 'OK') { + // جستجوی مبلغ تراکنش در دیتابیس بر اساس authority + // این قسمت باید جستجوی مبلغ مربوط به authority در دیتابیس شما انجام شود + $amount = getAmountFromDatabase($authority); // تابع فرضی برای دریافت مبلغ از دیتابیس + + if ($amount) { + // ایجاد درخواست برای تأیید پرداخت + $verifyRequest = new VerifyRequest(); + $verifyRequest->authority = $authority; // استفاده از authority دریافتی از درگاه + $verifyRequest->amount = $amount; // ارسال مبلغ پیدا شده از دیتابیس + + try { + // ارسال درخواست تأیید پرداخت به زرین‌پال + $response = $paymentGateway->verify($verifyRequest); + + // بررسی وضعیت تراکنش با کدهای 100 و 101 + if ($response->code === 100 || $response->code === 101) { + // تراکنش موفق است، نمایش اطلاعات تراکنش به کاربر + echo "Payment Verified: \n"; + echo "Reference ID: " . $response->ref_id . "\n"; + echo "Card PAN: " . $response->card_pan . "\n"; + echo "Fee: " . $response->fee . "\n"; + } else { + // نمایش خطای تراکنش ناموفق + echo "Transaction failed with code: " . $response->code; + } + + } catch (\Exception $e) { + // مدیریت خطا در صورت ناموفق بودن تأیید پرداخت + echo 'Payment verification failed: ' . $e->getMessage(); + } + } else { + echo 'No matching transaction found for this authority code.'; + } +} else { + // اگر وضعیت NOK باشد، تراکنش ناموفق یا لغو شده است + echo 'Transaction was cancelled or failed.'; } diff --git a/examples/unVerified.php b/examples/unVerified.php new file mode 100644 index 0000000..8fd32b1 --- /dev/null +++ b/examples/unVerified.php @@ -0,0 +1,37 @@ + 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', +]); + +$zarinpal = new ZarinPal($options); +$paymentGateway = $zarinpal->paymentGateway(); + +$unverifiedRequest = new UnverifiedRequest(); + +try { + + $response = $paymentGateway->unverified($unverifiedRequest); + + if ($response->code === 100) { + foreach ($response->authorities as $transaction) { + echo "Transaction Authority: " . $transaction['authority'] . "\n"; + echo "Amount: " . $transaction['amount'] . "\n"; + echo "Callback URL: " . $transaction['callback_url'] . "\n"; + echo "Referer: " . $transaction['referer'] . "\n"; + echo "Date: " . $transaction['date'] . "\n"; + echo "--------------------------\n"; + } + } else { + echo "Failed to retrieve unverified transactions. Code: " . $response->code . "\n"; + echo "Message: " . $response->message . "\n"; + } +} catch (\Exception $e) { + echo 'Unverified inquiry failed: ' . $e->getMessage(); +} \ No newline at end of file diff --git a/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php b/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php index 0fbbc98..7213cdc 100644 --- a/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php +++ b/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php @@ -6,11 +6,33 @@ class UnverifiedResponse { - use Fillable; - public array $authorities; - public array $list; + public int $code; + public string $message; + public array $authorities = []; + + public function __construct(array $data = null) + { + if ($data === null || !isset($data['code'], $data['message'])) { + $this->code = 0; + $this->message = 'No data received'; + return; + } + $this->code = $data['code']; + $this->message = $data['message']; -} \ No newline at end of file + if (isset($data['authorities']) && is_array($data['authorities'])) { + foreach ($data['authorities'] as $authorityData) { + $this->authorities[] = [ + 'authority' => $authorityData['authority'] ?? '', + 'amount' => $authorityData['amount'] ?? 0, + 'callback_url' => $authorityData['callback_url'] ?? '', + 'referer' => $authorityData['referer'] ?? '', + 'date' => $authorityData['date'] ?? '', + ]; + } + } + } +} diff --git a/tests/PaymentGateway/PaymentGatewayTest.php b/tests/PaymentGateway/PaymentGatewayTest.php index 3b252dc..04cb687 100644 --- a/tests/PaymentGateway/PaymentGatewayTest.php +++ b/tests/PaymentGateway/PaymentGatewayTest.php @@ -79,10 +79,24 @@ public function testUnverified() { $responseBody = [ 'data' => [ - 'list' => [ - ['authority' => 'A000000000000000000000000000ydq5y838'], - ['authority' => 'A000000000000000000000000000ydq5y839'], - ] + 'code' => 100, + 'message' => 'Success', + 'authorities' => [ + [ + 'authority' => 'A000000000000000000000000000ydq5y838', + 'amount' => 50000, + 'callback_url' => 'https://example.com/callback', + 'referer' => 'https://example.com/referer', + 'date' => '2024-09-22 10:00:00' + ], + [ + 'authority' => 'A000000000000000000000000000ydq5y839', + 'amount' => 75000, + 'callback_url' => 'https://example.com/callback2', + 'referer' => 'https://example.com/referer2', + 'date' => '2024-09-22 12:00:00' + ], + ], ], 'errors' => [] ]; @@ -92,10 +106,18 @@ public function testUnverified() ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); $unverified = new UnverifiedRequest(); - $response = $this->gateway->unverified($unverified); - $this->assertCount(2, $response->list); - $this->assertEquals('A000000000000000000000000000ydq5y838', $response->list[0]['authority']); + + $this->assertEquals(100, $response->code); + $this->assertCount(2, $response->authorities); + $this->assertEquals('A000000000000000000000000000ydq5y838', $response->authorities[0]['authority']); + $this->assertEquals(50000, $response->authorities[0]['amount']); + $this->assertEquals('https://example.com/callback', $response->authorities[0]['callback_url']); + $this->assertEquals('2024-09-22 10:00:00', $response->authorities[0]['date']); + $this->assertEquals('A000000000000000000000000000ydq5y839', $response->authorities[1]['authority']); + $this->assertEquals(75000, $response->authorities[1]['amount']); + $this->assertEquals('https://example.com/callback2', $response->authorities[1]['callback_url']); + $this->assertEquals('2024-09-22 12:00:00', $response->authorities[1]['date']); } public function testReverse() From 27045cde2569ae935175bcaf478e9d97f983d337 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Wed, 25 Sep 2024 12:25:14 +0330 Subject: [PATCH 14/23] Update Doc --- examples/Verify.php | 23 +++-------- examples/basic-client.php | 78 -------------------------------------- examples/basic-client2.php | 28 -------------- 3 files changed, 6 insertions(+), 123 deletions(-) delete mode 100644 examples/basic-client.php delete mode 100644 examples/basic-client2.php diff --git a/examples/Verify.php b/examples/Verify.php index 15e49cd..5a6164a 100644 --- a/examples/Verify.php +++ b/examples/Verify.php @@ -8,62 +8,51 @@ use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\VerifyRequest; -// ایجاد ClientBuilder برای تنظیم هدرهای پیش‌فرض + $clientBuilder = new ClientBuilder(); $clientBuilder->addPlugin(new HeaderDefaultsPlugin([ 'Accept' => 'application/json', ])); -// پیکربندی SDK $options = new Options([ 'client_builder' => $clientBuilder, - 'sandbox' => false, // غیرفعال‌سازی حالت تستی برای تراکنش‌های واقعی - 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', // Merchant ID شما + 'sandbox' => false, + 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', ]); $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); -// دریافت authority و status از کوئری استرینگ $authority = $_GET['Authority']; $status = $_GET['Status']; -// بررسی وضعیت تراکنش if ($status === 'OK') { - // جستجوی مبلغ تراکنش در دیتابیس بر اساس authority - // این قسمت باید جستجوی مبلغ مربوط به authority در دیتابیس شما انجام شود + $amount = getAmountFromDatabase($authority); // تابع فرضی برای دریافت مبلغ از دیتابیس if ($amount) { - // ایجاد درخواست برای تأیید پرداخت $verifyRequest = new VerifyRequest(); - $verifyRequest->authority = $authority; // استفاده از authority دریافتی از درگاه - $verifyRequest->amount = $amount; // ارسال مبلغ پیدا شده از دیتابیس + $verifyRequest->authority = $authority; + $verifyRequest->amount = $amount; try { - // ارسال درخواست تأیید پرداخت به زرین‌پال $response = $paymentGateway->verify($verifyRequest); - // بررسی وضعیت تراکنش با کدهای 100 و 101 if ($response->code === 100 || $response->code === 101) { - // تراکنش موفق است، نمایش اطلاعات تراکنش به کاربر echo "Payment Verified: \n"; echo "Reference ID: " . $response->ref_id . "\n"; echo "Card PAN: " . $response->card_pan . "\n"; echo "Fee: " . $response->fee . "\n"; } else { - // نمایش خطای تراکنش ناموفق echo "Transaction failed with code: " . $response->code; } } catch (\Exception $e) { - // مدیریت خطا در صورت ناموفق بودن تأیید پرداخت echo 'Payment verification failed: ' . $e->getMessage(); } } else { echo 'No matching transaction found for this authority code.'; } } else { - // اگر وضعیت NOK باشد، تراکنش ناموفق یا لغو شده است echo 'Transaction was cancelled or failed.'; } diff --git a/examples/basic-client.php b/examples/basic-client.php deleted file mode 100644 index 8c2a97f..0000000 --- a/examples/basic-client.php +++ /dev/null @@ -1,78 +0,0 @@ -addPlugin(new HeaderDefaultsPlugin([ - 'Accept' => 'application/json', -])); - -// usage -$options = new Options([ - 'client_builder' => $clientBuilder, - 'merchant_id' => 'x1379bc04-196d-47bb-a8f0-0e969ec96179', -]); - -$sdk = new ZarinPal($options); - -$request = new RequestRequest(); -$request->amount = 10000; -$request->description = 'پرداخت تست'; -$request->callback_url = 'https://tehran.ir'; -$request->mobile = '09370000000'; -$request->email = 'a@b.c'; -$request->currency = 'IRT'; -$request->cardPan = '5022291083818920'; -$request->wages = [ - [ - 'iban' => 'IR130570028780010957775103', - 'amount' =>5000, - 'description' => 'تسهیم سود فروش' - ], - [ - 'iban' => 'IR670170000000352965862009', - 'amount' => 5000, - 'description' => 'تسهیم سود فروش به شخص دوم' - ] -]; - -$verify = new VerifyRequest(); -$verify->amount = 15000; -$verify->authority = 'A00000000000000000000000000123456'; - -$unverified = new UnverifiedRequest(); - -$reverseRequest = new ReverseRequest($options); -$reverseRequest->authority = 'A00000000000000000000000000123456'; - -$inquiryRequest = new InquiryRequest($options); -$inquiryRequest->authority = 'A00000000000000000000000000123456'; - -try { - $response = $sdk->paymentGateway()->request($request); - // نمایش نتیجه در صورت موفقیت - echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); -} catch (ResponseException $e) { - // خطا به صورت JSON برمی‌گردد، بدون اینکه برنامه قطع شود - echo "Error: " . $e->getMessage(); -} catch (Exception $e) { - // هندل کردن دیگر خطاهای غیرمنتظره - echo "Unexpected Error: " . $e->getMessage(); -} -$response2 = $sdk->paymentGateway()->verify($verify); -$response3 = $sdk->paymentGateway()->unverified($unverified); -$response4 = $sdk->paymentGateway()->reverse($reverseRequest); -$response5 = $sdk->paymentGateway()->inquiry($inquiryRequest); - -die(print_r($response) . print_r($response2) . print_r($response3) . print_r($response4) . print_r($response5)); diff --git a/examples/basic-client2.php b/examples/basic-client2.php deleted file mode 100644 index be71eda..0000000 --- a/examples/basic-client2.php +++ /dev/null @@ -1,28 +0,0 @@ - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiZWU3MjgzZDQ0MzI1ZTJlMDdkODdhM2MzMDc2MzUzMWExZTYyZDI4OWMzOGMxZWY2ODI0NmRkZWZkYTRjZmNlMzY5NjVkMDQ0YjA1ZTMwNGMiLCJpYXQiOjE3MjQ2MTY3MjcuMTU5NTU5LCJuYmYiOjE3MjQ2MTY3MjcuMTU5NTYyLCJleHAiOjE4ODIzODMxMjcuMTIwOTkzLCJzdWIiOiIxMjE3NDYiLCJzY29wZXMiOltdfQ.L7CXjwVQQ0Pm0Ou4-7ALmKXZNHxUvrEvtvwe8i2H_zbcHTUZE51Gzd-wuO5gci09RalsshrOOwZ0UUZfCczuY8P8PfZTvvo5P6pzu6uhiU5FsEgyb8LNyyRakDXDkIekmyfDC-l3Y2dveBG2uAEfg4TflqjSJ-XIgeu4e9l8rnhWC91FS7d854aEqc7anpEbtetQG2gRSbAGgIWq6PA8laanX1Cj0eImUhsdG2B6raX4jTLfmn8bZ4bSmVNbTmgp7ltNGTLlU4ESbYCk79XhcUnGfYt59aeV0P_U82OVIXG0FBhKqrI4p8yJHbcObJgmSymLiZesZXlGfUST6I9u3fsaFCxd3BBFelrI84t6mTyabAEq7eGPJOlIu7pZbHtu3xCoNJoUKjPvltel1Ua25ENuY9GZa2rMFKl1hvSpkZYpJf9ZrYO7lQhxAoOufW-z9YehPD4axRQybVCFRYQ-Co1FczDU7RQPQ91-QBy34Z98Nj8qtl3pg00QieXLLHJHq2l5_ePzXb6-uLnQqIcpu2Sjrm9zObJkwcZ6pqASd4PVHDd76O27hDQ46q_Au3bQ5lm1MphSQ1yST5kpFNaTp8e0TvmkV8URsv8O0Ll9fT16Mf0faCgydtSv6K7saySnB6egs8MaB5qlMZf6oO1FcoJ3Cv9DJm56AxmYFYdYEgU', -]); - -$transactionService = new TransactionService($options); - -$transactionRequest = new TransactionListRequest(); -$transactionRequest->terminalId = '238'; -$transactionRequest->filter = 'PAID'; - -try { - $transactions = $transactionService->getTransactions($transactionRequest); - foreach ($transactions as $transaction) { - // Convert object to array and print it - print_r(json_decode(json_encode($transaction), true)); - } -} catch (Exception $e) { - echo 'Transaction fetch failed: ' . $e->getMessage(); -} - From 8c4b468816eb089a7183690fe622fd8c46f88f08 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Wed, 25 Sep 2024 12:31:27 +0330 Subject: [PATCH 15/23] Update Doc --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e83d6dd..4d8a77c 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,10 @@ { "name": "Hooman Naghiee", "email": "h.naghiee@zarinpal.com" + }, + { + "name": "Armin Zahedi", + "email": "arminzahedi1999@zarinpal.com" } ], "minimum-stability": "stable", @@ -39,7 +43,6 @@ "require-dev": { "php-http/curl-client": "^2.2", "laminas/laminas-diactoros": "^2.17", - "phpstan/phpstan": "^1.8", "phpunit/phpunit": "^9", "php-http/mock-client": "^1.5" }, From b7b28cbabd936fdcb3e388ed049a4d856b8ded38 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Mon, 30 Sep 2024 12:34:08 +0330 Subject: [PATCH 16/23] Update composer.json --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4d8a77c..8ced1e1 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,8 @@ "ext-curl": "*", "psr/http-client-implementation": "*", "symfony/http-client": "^7.1", - "guzzlehttp/guzzle": "^7.9" + "guzzlehttp/guzzle": "^7.9", + "php-http/guzzle6-adapter": "^1.1" }, "require-dev": { "php-http/curl-client": "^2.2", From 5231a4f1d886a309bb71faf44ebac0275a700eb5 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Mon, 30 Sep 2024 12:36:08 +0330 Subject: [PATCH 17/23] Update composer.json --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 8ced1e1..4d8a77c 100644 --- a/composer.json +++ b/composer.json @@ -38,8 +38,7 @@ "ext-curl": "*", "psr/http-client-implementation": "*", "symfony/http-client": "^7.1", - "guzzlehttp/guzzle": "^7.9", - "php-http/guzzle6-adapter": "^1.1" + "guzzlehttp/guzzle": "^7.9" }, "require-dev": { "php-http/curl-client": "^2.2", From 7073fe4045630c5bf4216e08175030b87f2d1808 Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Wed, 2 Oct 2024 20:29:21 +0330 Subject: [PATCH 18/23] Fix Bug --- composer.json | 3 +- composer.lock | 662 ++++-------------- examples/Refund.php | 11 +- examples/Request.php | 8 +- examples/Transaction.php | 13 +- examples/Verify.php | 8 +- src/ClientBuilder.php | 24 +- src/Endpoint/GraphQL/RefundService.php | 100 ++- .../RequestTypes/TransactionListRequest.php | 8 + src/Endpoint/GraphQL/TransactionService.php | 103 ++- .../PaymentGateway/PaymentGateway.php | 39 +- .../Exception/ResponseException.php | 14 +- src/Options.php | 13 +- src/ZarinPal.php | 14 +- tests/Graphql/GraphQLRefundTest.php | 18 +- tests/Graphql/TransactionServiceTest.php | 46 +- tests/PaymentGateway/PaymentGatewayTest.php | 29 +- 17 files changed, 415 insertions(+), 698 deletions(-) diff --git a/composer.json b/composer.json index 4d8a77c..789189b 100644 --- a/composer.json +++ b/composer.json @@ -38,10 +38,9 @@ "ext-curl": "*", "psr/http-client-implementation": "*", "symfony/http-client": "^7.1", - "guzzlehttp/guzzle": "^7.9" + "php-http/curl-client": "^2.2" }, "require-dev": { - "php-http/curl-client": "^2.2", "laminas/laminas-diactoros": "^2.17", "phpunit/phpunit": "^9", "php-http/mock-client": "^1.5" diff --git a/composer.lock b/composer.lock index 7692dba..0684788 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6fb28754c98b5675132beb8d0b401b05", + "content-hash": "d7b455e9708c0623ad236a83c28d967b", "packages": [ { "name": "clue/stream-filter", @@ -73,256 +73,48 @@ "time": "2023-12-20T15:40:13+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "7.9.2", + "name": "php-http/client-common", + "version": "2.7.2", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + "url": "https://github.com/php-http/client-common.git", + "reference": "0cfe9858ab9d3b213041b947c881d5b19ceeca46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "url": "https://api.github.com/repos/php-http/client-common/zipball/0cfe9858ab9d3b213041b947c881d5b19ceeca46", + "reference": "0cfe9858ab9d3b213041b947c881d5b19ceeca46", "shasum": "" }, "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", - "php": "^7.2.5 || ^8.0", + "php": "^7.1 || ^8.0", + "php-http/httplug": "^2.0", + "php-http/message": "^1.6", "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0" - }, - "provide": { - "psr/http-client-implementation": "1.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-curl": "*", - "guzzle/client-integration-tests": "3.0.2", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.39 || ^9.6.20", - "psr/log": "^1.1 || ^2.0 || ^3.0" - }, - "suggest": { - "ext-curl": "Required for CURL handler support", - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "psr-18", - "psr-7", - "rest", - "web service" - ], - "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.2" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", - "type": "tidelift" - } - ], - "time": "2024-07-24T11:22:20+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", - "type": "tidelift" - } - ], - "time": "2024-07-18T10:29:17+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "2.7.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" + "psr/http-message": "^1.0 || ^2.0", + "symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0 || ^7.0", + "symfony/polyfill-php80": "^1.17" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "doctrine/instantiator": "^1.1", + "guzzlehttp/psr7": "^1.4", + "nyholm/psr7": "^1.2", + "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", + "phpspec/prophecy": "^1.10.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.33 || ^9.6.7" }, "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + "ext-json": "To detect JSON responses with the ContentTypePlugin", + "ext-libxml": "To detect XML responses with the ContentTypePlugin", + "php-http/cache-plugin": "PSR-6 Cache plugin", + "php-http/logger-plugin": "PSR-3 Logger plugin", + "php-http/stopwatch-plugin": "Symfony Stopwatch plugin" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" + "Http\\Client\\Common\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -330,116 +122,65 @@ "MIT" ], "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, { "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" + "email": "mark.sagikazar@gmail.com" } ], - "description": "PSR-7 message implementation that also provides common utility methods", + "description": "Common HTTP Client implementations and tools for HTTPlug", + "homepage": "http://httplug.io", "keywords": [ + "client", + "common", "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" + "httplug" ], "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.0" + "issues": "https://github.com/php-http/client-common/issues", + "source": "https://github.com/php-http/client-common/tree/2.7.2" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "time": "2024-07-18T11:15:46+00:00" + "time": "2024-09-24T06:21:48+00:00" }, { - "name": "php-http/client-common", - "version": "2.7.1", + "name": "php-http/curl-client", + "version": "2.3.2", "source": { "type": "git", - "url": "https://github.com/php-http/client-common.git", - "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612" + "url": "https://github.com/php-http/curl-client.git", + "reference": "0b869922458b1cde9137374545ed4fff7ac83623" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/client-common/zipball/1e19c059b0e4d5f717bf5d524d616165aeab0612", - "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612", + "url": "https://api.github.com/repos/php-http/curl-client/zipball/0b869922458b1cde9137374545ed4fff7ac83623", + "reference": "0b869922458b1cde9137374545ed4fff7ac83623", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0", + "ext-curl": "*", + "php": "^7.4 || ^8.0", + "php-http/discovery": "^1.6", "php-http/httplug": "^2.0", - "php-http/message": "^1.6", + "php-http/message": "^1.2", "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0 || ^2.0", - "symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0 || ^7.0", - "symfony/polyfill-php80": "^1.17" + "psr/http-factory-implementation": "^1.0", + "symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" }, - "require-dev": { - "doctrine/instantiator": "^1.1", - "guzzlehttp/psr7": "^1.4", - "nyholm/psr7": "^1.2", - "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", - "phpspec/prophecy": "^1.10.2", - "phpunit/phpunit": "^7.5.20 || ^8.5.33 || ^9.6.7" + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0", + "psr/http-client-implementation": "1.0" }, - "suggest": { - "ext-json": "To detect JSON responses with the ContentTypePlugin", - "ext-libxml": "To detect XML responses with the ContentTypePlugin", - "php-http/cache-plugin": "PSR-6 Cache plugin", - "php-http/logger-plugin": "PSR-3 Logger plugin", - "php-http/stopwatch-plugin": "Symfony Stopwatch plugin" + "require-dev": { + "guzzlehttp/psr7": "^2.0", + "laminas/laminas-diactoros": "^2.0", + "php-http/client-integration-tests": "^3.0", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^7.5 || ^9.4" }, "type": "library", "autoload": { "psr-4": { - "Http\\Client\\Common\\": "src/" + "Http\\Client\\Curl\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -448,36 +189,35 @@ ], "authors": [ { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" + "name": "Михаил Красильников", + "email": "m.krasilnikov@yandex.ru" } ], - "description": "Common HTTP Client implementations and tools for HTTPlug", - "homepage": "http://httplug.io", + "description": "PSR-18 and HTTPlug Async client with cURL", + "homepage": "http://php-http.org", "keywords": [ - "client", - "common", + "curl", "http", - "httplug" + "psr-18" ], "support": { - "issues": "https://github.com/php-http/client-common/issues", - "source": "https://github.com/php-http/client-common/tree/2.7.1" + "issues": "https://github.com/php-http/curl-client/issues", + "source": "https://github.com/php-http/curl-client/tree/2.3.2" }, - "time": "2023-11-30T10:31:25+00:00" + "time": "2024-03-03T08:21:07+00:00" }, { "name": "php-http/discovery", - "version": "1.19.4", + "version": "1.20.0", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "0700efda8d7526335132360167315fdab3aeb599" + "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599", - "reference": "0700efda8d7526335132360167315fdab3aeb599", + "url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d", + "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d", "shasum": "" }, "require": { @@ -541,22 +281,22 @@ ], "support": { "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.19.4" + "source": "https://github.com/php-http/discovery/tree/1.20.0" }, - "time": "2024-03-29T13:00:05+00:00" + "time": "2024-10-02T11:20:13+00:00" }, { "name": "php-http/httplug", - "version": "2.4.0", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/php-http/httplug.git", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67" + "reference": "5cad731844891a4c282f3f3e1b582c46839d22f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67", + "url": "https://api.github.com/repos/php-http/httplug/zipball/5cad731844891a4c282f3f3e1b582c46839d22f4", + "reference": "5cad731844891a4c282f3f3e1b582c46839d22f4", "shasum": "" }, "require": { @@ -598,22 +338,22 @@ ], "support": { "issues": "https://github.com/php-http/httplug/issues", - "source": "https://github.com/php-http/httplug/tree/2.4.0" + "source": "https://github.com/php-http/httplug/tree/2.4.1" }, - "time": "2023-04-14T15:10:03+00:00" + "time": "2024-09-23T11:39:58+00:00" }, { "name": "php-http/message", - "version": "1.16.1", + "version": "1.16.2", "source": { "type": "git", "url": "https://github.com/php-http/message.git", - "reference": "5997f3289332c699fa2545c427826272498a2088" + "reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/message/zipball/5997f3289332c699fa2545c427826272498a2088", - "reference": "5997f3289332c699fa2545c427826272498a2088", + "url": "https://api.github.com/repos/php-http/message/zipball/06dd5e8562f84e641bf929bfe699ee0f5ce8080a", + "reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a", "shasum": "" }, "require": { @@ -667,9 +407,9 @@ ], "support": { "issues": "https://github.com/php-http/message/issues", - "source": "https://github.com/php-http/message/tree/1.16.1" + "source": "https://github.com/php-http/message/tree/1.16.2" }, - "time": "2024-03-07T13:22:09+00:00" + "time": "2024-10-02T11:34:13+00:00" }, { "name": "php-http/promise", @@ -938,16 +678,16 @@ }, { "name": "psr/log", - "version": "3.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "79dff0b268932c640297f5208d6298f71855c03e" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/79dff0b268932c640297f5208d6298f71855c03e", - "reference": "79dff0b268932c640297f5208d6298f71855c03e", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -982,53 +722,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.1" - }, - "time": "2024-08-21T13:31:24+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2019-03-08T08:55:37+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1099,16 +795,16 @@ }, { "name": "symfony/http-client", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "b79858aa7a051ea791b0d50269a234a0b50cb231" + "reference": "abca35865118edf35a23f2f24978a1784c831cb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/b79858aa7a051ea791b0d50269a234a0b50cb231", - "reference": "b79858aa7a051ea791b0d50269a234a0b50cb231", + "url": "https://api.github.com/repos/symfony/http-client/zipball/abca35865118edf35a23f2f24978a1784c831cb4", + "reference": "abca35865118edf35a23f2f24978a1784c831cb4", "shasum": "" }, "require": { @@ -1173,7 +869,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.1.3" + "source": "https://github.com/symfony/http-client/tree/v7.1.5" }, "funding": [ { @@ -1189,7 +885,7 @@ "type": "tidelift" } ], - "time": "2024-07-17T06:10:24+00:00" + "time": "2024-09-20T13:35:23+00:00" }, { "name": "symfony/http-client-contracts", @@ -1338,20 +1034,20 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -1398,7 +1094,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -1414,7 +1110,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/service-contracts", @@ -1730,16 +1426,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.1.0", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3abf7425cd284141dc5d8d14a9ee444de3345d1a", + "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a", "shasum": "" }, "require": { @@ -1782,9 +1478,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.0" }, - "time": "2024-07-01T20:03:41+00:00" + "time": "2024-09-29T13:56:26+00:00" }, { "name": "phar-io/manifest", @@ -1904,71 +1600,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "php-http/curl-client", - "version": "2.3.2", - "source": { - "type": "git", - "url": "https://github.com/php-http/curl-client.git", - "reference": "0b869922458b1cde9137374545ed4fff7ac83623" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/curl-client/zipball/0b869922458b1cde9137374545ed4fff7ac83623", - "reference": "0b869922458b1cde9137374545ed4fff7ac83623", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "php": "^7.4 || ^8.0", - "php-http/discovery": "^1.6", - "php-http/httplug": "^2.0", - "php-http/message": "^1.2", - "psr/http-client": "^1.0", - "psr/http-factory-implementation": "^1.0", - "symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "provide": { - "php-http/async-client-implementation": "1.0", - "php-http/client-implementation": "1.0", - "psr/http-client-implementation": "1.0" - }, - "require-dev": { - "guzzlehttp/psr7": "^2.0", - "laminas/laminas-diactoros": "^2.0", - "php-http/client-integration-tests": "^3.0", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^7.5 || ^9.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Client\\Curl\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Михаил Красильников", - "email": "m.krasilnikov@yandex.ru" - } - ], - "description": "PSR-18 and HTTPlug Async client with cURL", - "homepage": "http://php-http.org", - "keywords": [ - "curl", - "http", - "psr-18" - ], - "support": { - "issues": "https://github.com/php-http/curl-client/issues", - "source": "https://github.com/php-http/curl-client/tree/2.3.2" - }, - "time": "2024-03-03T08:21:07+00:00" - }, { "name": "php-http/mock-client", "version": "1.6.0", @@ -2031,64 +1662,6 @@ }, "time": "2023-05-21T08:31:38+00:00" }, - { - "name": "phpstan/phpstan", - "version": "1.11.11", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/707c2aed5d8d0075666e673a5e71440c1d01a5a3", - "reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-08-19T14:37:29+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "9.2.32", @@ -2410,16 +1983,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.20", + "version": "9.6.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", "shasum": "" }, "require": { @@ -2434,7 +2007,7 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-code-coverage": "^9.2.32", "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.4", @@ -2493,7 +2066,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" }, "funding": [ { @@ -2509,7 +2082,7 @@ "type": "tidelift" } ], - "time": "2024-07-10T11:45:39+00:00" + "time": "2024-09-19T10:50:18+00:00" }, { "name": "sebastian/cli-parser", @@ -3532,7 +3105,8 @@ "prefer-lowest": false, "platform": { "php": ">=7.4", - "ext-json": "*" + "ext-json": "*", + "ext-curl": "*" }, "platform-dev": [], "plugin-api-version": "2.6.0" diff --git a/examples/Refund.php b/examples/Refund.php index 91c2c50..18759d1 100644 --- a/examples/Refund.php +++ b/examples/Refund.php @@ -3,15 +3,20 @@ require_once __DIR__ . '/../vendor/autoload.php'; use ZarinPal\Sdk\Options; -use ZarinPal\Sdk\Endpoint\GraphQL\RefundService; +use ZarinPal\Sdk\ClientBuilder; +use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest; +$clientBuilder = new ClientBuilder(30); + $options = new Options([ - 'access_token' => 'your access token', // Access token without Bearer + 'client_builder' => $clientBuilder, + 'access_token' => 'your_access_token', // Access token بدون Bearer ]); -$refundService = new RefundService($options); +$zarinpal = new ZarinPal($options); +$refundService = $zarinpal->refundService(); $refundRequest = new RefundRequest(); $refundRequest->sessionId = '580868147'; $refundRequest->amount = 20000; // Amount in IRR diff --git a/examples/Request.php b/examples/Request.php index 0a2ed88..59cd044 100644 --- a/examples/Request.php +++ b/examples/Request.php @@ -4,6 +4,7 @@ use Http\Client\Common\Plugin\HeaderDefaultsPlugin; use ZarinPal\Sdk\ClientBuilder; +use ZarinPal\Sdk\HttpClient\Exception\ResponseException; use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\RequestRequest; @@ -48,6 +49,9 @@ $url = $paymentGateway->getRedirectUrl($response->authority); // create full url Payment header('Location:'. $url); +} catch (ResponseException $e) { + var_dump($e->getErrorDetails()); + } catch (\Exception $e) { - echo 'Payment request failed: ' . $e->getMessage(); -} + var_dump($e->getMessage()); + } diff --git a/examples/Transaction.php b/examples/Transaction.php index 6fa1486..e3eba3d 100644 --- a/examples/Transaction.php +++ b/examples/Transaction.php @@ -4,20 +4,27 @@ use ZarinPal\Sdk\HttpClient\Exception\ResponseException; use ZarinPal\Sdk\Options; -use ZarinPal\Sdk\Endpoint\GraphQL\TransactionService; +use ZarinPal\Sdk\ClientBuilder; +use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\TransactionListRequest; +$clientBuilder = new ClientBuilder(); + $options = new Options([ + 'client_builder' => $clientBuilder, 'access_token' => 'your access token', // Access token without Bearer ]); -$transactionService = new TransactionService($options); +$zarinpal = new ZarinPal($options); + +$transactionService = $zarinpal->transactionService(); $transactionRequest = new TransactionListRequest(); -$transactionRequest->terminalId = '250'; +$transactionRequest->terminalId = '349555'; $transactionRequest->filter = 'PAID'; // Optional filter: PAID, VERIFIED, TRASH, ACTIVE, REFUNDED try { + $transactions = $transactionService->getTransactions($transactionRequest); $transactionArray = []; diff --git a/examples/Verify.php b/examples/Verify.php index 5a6164a..f95a6c0 100644 --- a/examples/Verify.php +++ b/examples/Verify.php @@ -23,8 +23,8 @@ $zarinpal = new ZarinPal($options); $paymentGateway = $zarinpal->paymentGateway(); -$authority = $_GET['Authority']; -$status = $_GET['Status']; +$authority = filter_input(INPUT_GET, 'Authority', FILTER_SANITIZE_STRING); +$status = filter_input(INPUT_GET, 'Status', FILTER_SANITIZE_STRING); if ($status === 'OK') { @@ -38,11 +38,13 @@ try { $response = $paymentGateway->verify($verifyRequest); - if ($response->code === 100 || $response->code === 101) { + if ($response->code === 100) { echo "Payment Verified: \n"; echo "Reference ID: " . $response->ref_id . "\n"; echo "Card PAN: " . $response->card_pan . "\n"; echo "Fee: " . $response->fee . "\n"; + } else if ($response->code === 101) { + echo "Payment already verified: \n"; } else { echo "Transaction failed with code: " . $response->code; } diff --git a/src/ClientBuilder.php b/src/ClientBuilder.php index 13988a5..0dbbeb4 100644 --- a/src/ClientBuilder.php +++ b/src/ClientBuilder.php @@ -4,11 +4,11 @@ namespace ZarinPal\Sdk; +use Http\Client\Curl\Client as CurlClient; use Http\Client\Common\HttpMethodsClient; use Http\Client\Common\HttpMethodsClientInterface; use Http\Client\Common\Plugin; use Http\Client\Common\PluginClientFactory; -use Http\Discovery\HttpClientDiscovery; use Http\Discovery\Psr17FactoryDiscovery; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; @@ -17,23 +17,29 @@ final class ClientBuilder { private ClientInterface $httpClient; - private RequestFactoryInterface $requestFactoryInterface; - private StreamFactoryInterface $streamFactoryInterface; - /** - * @var Plugin[] $plugins - */ private array $plugins = []; public function __construct( - ClientInterface $httpClient = null, + int $timeout = 30, + ClientInterface $httpClient = null, RequestFactoryInterface $requestFactoryInterface = null, - StreamFactoryInterface $streamFactoryInterface = null + StreamFactoryInterface $streamFactoryInterface = null ) { - $this->httpClient = $httpClient ?: HttpClientDiscovery::find(); + $responseFactory = Psr17FactoryDiscovery::findResponseFactory(); + + $this->httpClient = $httpClient ?: new CurlClient( + $responseFactory, + Psr17FactoryDiscovery::findStreamFactory(), + [ + CURLOPT_TIMEOUT => $timeout, + CURLOPT_CONNECTTIMEOUT => $timeout, + ] + ); + $this->requestFactoryInterface = $requestFactoryInterface ?: Psr17FactoryDiscovery::findRequestFactory(); $this->streamFactoryInterface = $streamFactoryInterface ?: Psr17FactoryDiscovery::findStreamFactory(); } diff --git a/src/Endpoint/GraphQL/RefundService.php b/src/Endpoint/GraphQL/RefundService.php index 9cfb8be..f3887d8 100644 --- a/src/Endpoint/GraphQL/RefundService.php +++ b/src/Endpoint/GraphQL/RefundService.php @@ -2,22 +2,24 @@ namespace ZarinPal\Sdk\Endpoint\GraphQL; -use GuzzleHttp\Client; -use GuzzleHttp\Exception\RequestException; +use ZarinPal\Sdk\ClientBuilder; +use ZarinPal\Sdk\Options; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest; use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\RefundResponse; use ZarinPal\Sdk\HttpClient\Exception\ResponseException; -use ZarinPal\Sdk\Options; +use Psr\Http\Message\ResponseInterface; +use JsonException; +use Exception; class RefundService { - private Client $client; + private ClientBuilder $clientBuilder; private Options $options; private string $graphqlUrl; - public function __construct(Options $options) + public function __construct(ClientBuilder $clientBuilder, Options $options) { - $this->client = new Client(); // Instantiate Guzzle client + $this->clientBuilder = $clientBuilder; $this->options = $options; $this->graphqlUrl = $options->getGraphqlUrl(); } @@ -25,32 +27,70 @@ public function __construct(Options $options) public function refund(RefundRequest $request): RefundResponse { $query = $request->toGraphQL(); + + $response = $this->httpHandler($this->graphqlUrl, $query); + + return new RefundResponse($response['data']['resource']); + } + + private function httpHandler(string $uri, string $body): array + { try { - $response = $this->client->request('POST', $this->graphqlUrl, [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), - 'Content-Type' => 'application/json', - ], - 'body' => $query, - ]); - - // Decode the JSON response to an array - $responseData = json_decode($response->getBody()->getContents(), true); - - // Check for errors in the response - if (isset($responseData['errors'])) { - throw new ResponseException('GraphQL query error: ' . json_encode($responseData['errors'])); - } - - // Return a new RefundResponse with the data from the response - return new RefundResponse($responseData['data']['resource']); - - } catch (RequestException $e) { - throw new ResponseException('Request failed: ' . $e->getMessage(), 0, $e); - } catch (\Exception $e) { - throw new ResponseException('An unexpected error occurred: ' . $e->getMessage(), 0, $e); + $httpClient = $this->clientBuilder->getHttpClient(); + + $response = $httpClient->post($uri, [ + 'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION), + 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), + 'Content-Type' => 'application/json', + ], $body); + + $this->checkHttpError($response); + + $responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); + + } catch (JsonException $e) { + throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]); + } catch (ResponseException $e) { + throw $e; + } catch (Exception $e) { + throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]); } + + return $this->checkGraphQLError($responseData); } -} + private function checkHttpError(ResponseInterface $response): void + { + $statusCode = $response->getStatusCode(); + if ($statusCode !== 200) { + $body = $response->getBody()->getContents(); + $parsedBody = json_decode($body, true); + + $errorData = [ + 'data' => [], + 'errors' => [ + 'message' => $response->getReasonPhrase(), + 'code' => $statusCode, + 'details' => $parsedBody ?? [] + ] + ]; + throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData); + } + } + + private function checkGraphQLError(array $response): array + { + if (isset($response['errors']) || empty($response['data'])) { + $errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1]; + throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']); + } + + return $response; + } + + private function getClassName(): string + { + return basename(str_replace('\\', '/', __CLASS__)); + } +} diff --git a/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php b/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php index c187d0b..1db4c45 100644 --- a/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php +++ b/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php @@ -17,6 +17,8 @@ class TransactionListRequest public ?string $email = null; public ?string $mobile = null; public ?string $description = null; + public ?int $limit = 25; + public ?int $offset = 0; public function validate(): void { @@ -41,6 +43,8 @@ public function toGraphQL(): string $email: String, $mobile: CellNumber, $description: String + $limit: Int + $offset: Int ) { Session( terminal_id: $terminal_id, @@ -52,6 +56,8 @@ public function toGraphQL(): string email: $email, mobile: $mobile, description: $description + limit: $limit + offset: $offset ) { id, status, @@ -71,6 +77,8 @@ public function toGraphQL(): string 'email' => $this->email, 'mobile' => $this->mobile, 'description' => $this->description, + 'limit' => $this->limit, + 'offset' => $this->offset, ] ], JSON_THROW_ON_ERROR); } diff --git a/src/Endpoint/GraphQL/TransactionService.php b/src/Endpoint/GraphQL/TransactionService.php index 3b95a2b..e8b8d56 100644 --- a/src/Endpoint/GraphQL/TransactionService.php +++ b/src/Endpoint/GraphQL/TransactionService.php @@ -2,22 +2,24 @@ namespace ZarinPal\Sdk\Endpoint\GraphQL; -use GuzzleHttp\Client; -use GuzzleHttp\Exception\RequestException; +use ZarinPal\Sdk\ClientBuilder; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\TransactionListRequest; use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\TransactionListResponse; use ZarinPal\Sdk\HttpClient\Exception\ResponseException; use ZarinPal\Sdk\Options; +use Psr\Http\Message\ResponseInterface; +use JsonException; +use Exception; class TransactionService { - private Client $client; + private ClientBuilder $clientBuilder; private Options $options; private string $graphqlUrl; - public function __construct(Options $options) + public function __construct(ClientBuilder $clientBuilder, Options $options) { - $this->client = new Client(); // Instantiate Guzzle client + $this->clientBuilder = $clientBuilder; $this->options = $options; $this->graphqlUrl = $options->getGraphqlUrl(); } @@ -25,29 +27,76 @@ public function __construct(Options $options) public function getTransactions(TransactionListRequest $request): array { $query = $request->toGraphQL(); + + $response = $this->httpHandler($this->graphqlUrl, $query); + + $transactions = []; + foreach ($response['data']['Session'] as $data) { + $transactions[] = new TransactionListResponse($data); + } + + return $transactions; + } + + private function httpHandler(string $uri, string $body): array + { try { - $response = $this->client->post($this->graphqlUrl, [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), - 'Content-Type' => 'application/json', - ], - 'body' => $query, - ]); - - $responseData = json_decode($response->getBody()->getContents(), true); - if (isset($responseData['errors'])) { - throw new ResponseException('GraphQL query error: ' . json_encode($responseData['errors'])); - } - - $transactions = []; - foreach ($responseData['data']['Session'] as $data) { - $transactions[] = new TransactionListResponse($data); - } - - return $transactions; - } catch (RequestException $e) { - throw new ResponseException('Request failed: ' . $e->getMessage(), 0, $e); + $httpClient = $this->clientBuilder->getHttpClient(); + $response = $httpClient->post($uri, [ + 'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION), + 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), + 'Content-Type' => 'application/json', + ], $body); + + $responseContent = $response->getBody()->getContents(); + $this->checkHttpError($response); + + $responseData = json_decode($responseContent, true, 512, JSON_THROW_ON_ERROR); + + } catch (JsonException $e) { + throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]); + } catch (ResponseException $e) { + throw $e; + } catch (Exception $e) { + throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]); } + + return $this->checkGraphQLError($responseData); } -} + + private function checkHttpError(ResponseInterface $response): void + { + $statusCode = $response->getStatusCode(); + if ($statusCode !== 200) { + $body = $response->getBody()->getContents(); + $parsedBody = json_decode($body, true); + + $errorData = [ + 'data' => [], + 'errors' => [ + 'message' => $response->getReasonPhrase(), + 'code' => $statusCode, + 'details' => $parsedBody ?? [] + ] + ]; + + throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData); + } + } + + private function checkGraphQLError(array $response): array + { + if (isset($response['errors']) || empty($response['data'])) { + $errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1]; + throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']); + } + + return $response; + } + + private function getClassName(): string + { + return basename(str_replace('\\', '/', __CLASS__)); + } +} diff --git a/src/Endpoint/PaymentGateway/PaymentGateway.php b/src/Endpoint/PaymentGateway/PaymentGateway.php index b6c66b5..3a12140 100644 --- a/src/Endpoint/PaymentGateway/PaymentGateway.php +++ b/src/Endpoint/PaymentGateway/PaymentGateway.php @@ -87,16 +87,16 @@ private function fillMerchantId($request): void private function httpHandler(string $uri, string $body): array { try { - $fullUri = $this->sdk->getOptions()->getBaseUrl() . $uri; // Use the correct base URL (sandbox or production) + $fullUri = $this->sdk->getOptions()->getBaseUrl() . $uri; $response = $this->sdk->getHttpClient()->post($fullUri, [], $body); $this->checkHttpError($response); $response = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { - throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, $e); + throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]); } catch (ResponseException $e) { - throw $e; // Re-throw the original ResponseException to show exact status and message + throw $e; } catch (Exception $e) { - throw new ResponseException('Request failed: ' . $e->getMessage(), -99, $e); + throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]); } return $this->checkPaymentGatewayError($response); @@ -109,35 +109,28 @@ private function checkHttpError(ResponseInterface $response): void $body = $response->getBody()->getContents(); $parsedBody = json_decode($body, true); - if (isset($parsedBody['errors']['message'], $parsedBody['errors']['code'])) { - $message = $parsedBody['errors']['message']; - $code = $parsedBody['errors']['code']; + if (isset($parsedBody['errors'])) { + $errorData = $parsedBody; } else { - $message = 'HTTP Error: ' . $response->getReasonPhrase(); - $code = $statusCode; + $errorData = [ + 'data' => [], + 'errors' => [ + 'message' => $response->getReasonPhrase(), + 'code' => $statusCode, + 'validations' => [] + ] + ]; } - // Create the error response as an array - $errorResponse = [ - 'http_status_code' => $statusCode, - 'error_code' => $code, - 'error_message' => $message, - ]; - - // Convert the error response to JSON - $errorJson = json_encode($errorResponse, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); - - // Instead of displaying the error, throw it as JSON - throw new ResponseException($errorJson, $code); + throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData); } } - private function checkPaymentGatewayError(array $response): array { if (!empty($response['errors']) || empty($response['data'])) { $errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1]; - throw new PaymentGatewayException($errorDetails); + throw new PaymentGatewayException($errorDetails['message'], $errorDetails['code'], null, $response); } return $response; } diff --git a/src/HttpClient/Exception/ResponseException.php b/src/HttpClient/Exception/ResponseException.php index b5aa815..4a60e28 100644 --- a/src/HttpClient/Exception/ResponseException.php +++ b/src/HttpClient/Exception/ResponseException.php @@ -5,6 +5,18 @@ use Exception; -class ResponseException extends Exception +class ResponseException extends \Exception { + private $errorDetails; + + public function __construct($message, $code, $previous = null, array $errorDetails = []) + { + parent::__construct($message, $code, $previous); + $this->errorDetails = $errorDetails; + } + + public function getErrorDetails() + { + return $this->errorDetails; + } } \ No newline at end of file diff --git a/src/Options.php b/src/Options.php index f2017ba..1f001f4 100644 --- a/src/Options.php +++ b/src/Options.php @@ -26,12 +26,12 @@ private function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'client_builder' => new ClientBuilder(), 'uri_factory' => Psr17FactoryDiscovery::findUriFactory(), - 'base_url' => 'https://payment.zarinpal.com', - 'sandbox_base_url' => 'https://sandbox.zarinpal.com', + 'base_url' => $this->arrayGet(getenv(), 'ZARINPAL_BASE_URL', 'https://payment.zarinpal.com'), + 'sandbox_base_url' => $this->arrayGet(getenv(), 'ZARINPAL_SANDBOX_BASE_URL', 'https://sandbox.zarinpal.com'), 'merchant_id' => $this->arrayGet(getenv(), 'ZARINPAL_MERCHANT_KEY', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'), - 'graphql_url' => 'https://next.zarinpal.com/api/v4/graphql/', // Fixed GraphQL URL + 'graphql_url' => $this->arrayGet(getenv(), 'ZARINPAL_GRAPHQL_URL', 'https://next.zarinpal.com/api/v4/graphql/'), 'access_token' => $this->arrayGet(getenv(), 'ZARINPAL_ACCESS_TOKEN', ''), - 'sandbox' => false, // Default is production mode + 'sandbox' => $this->arrayGet(getenv(), 'ZARINPAL_SANDBOX', 'false') === 'true', ]); $resolver->setAllowedTypes('client_builder', ClientBuilder::class); @@ -83,9 +83,4 @@ public function getAccessToken(): string { return $this->options['access_token']; } - - public function isSandbox(): bool - { - return $this->options['sandbox']; - } } diff --git a/src/ZarinPal.php b/src/ZarinPal.php index c8dc378..3e510a7 100644 --- a/src/ZarinPal.php +++ b/src/ZarinPal.php @@ -1,12 +1,12 @@ clientBuilder, $this->options); + } + + public function refundService(): RefundService + { + return new RefundService($this->clientBuilder, $this->options); + } + public function getMerchantId(): string { return $this->options->getMerchantId(); diff --git a/tests/Graphql/GraphQLRefundTest.php b/tests/Graphql/GraphQLRefundTest.php index 6f31240..4c77ba3 100644 --- a/tests/Graphql/GraphQLRefundTest.php +++ b/tests/Graphql/GraphQLRefundTest.php @@ -3,6 +3,8 @@ namespace Tests\Graphql; use Tests\BaseTestCase; +use ZarinPal\Sdk\Options; +use ZarinPal\Sdk\ClientBuilder; use ZarinPal\Sdk\Endpoint\GraphQL\RefundService; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest; use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\RefundResponse; @@ -14,7 +16,15 @@ class GraphQLRefundTest extends BaseTestCase protected function setUp(): void { parent::setUp(); - $this->refundService = $this->createMock(RefundService::class); + + $clientBuilder = new ClientBuilder(); + + $options = new Options([ + 'client_builder' => $clientBuilder, + 'access_token' => 'your_access_token', + ]); + + $this->refundService = new RefundService($clientBuilder, $options); } public function testRefund() @@ -35,13 +45,13 @@ public function testRefund() ] ]); - $this->refundService->method('refund')->willReturn($mockResponse); + $refundServiceMock = $this->createMock(RefundService::class); + $refundServiceMock->method('refund')->willReturn($mockResponse); - $response = $this->refundService->refund($refundRequest); + $response = $refundServiceMock->refund($refundRequest); $this->assertEquals('1234567890', $response->id); $this->assertEquals(20000, $response->amount); $this->assertArrayHasKey('refund_status', $response->timeline); } - } diff --git a/tests/Graphql/TransactionServiceTest.php b/tests/Graphql/TransactionServiceTest.php index 061eaf5..65c0d02 100644 --- a/tests/Graphql/TransactionServiceTest.php +++ b/tests/Graphql/TransactionServiceTest.php @@ -2,13 +2,12 @@ namespace Tests\Graphql; -use GuzzleHttp\Client; -use GuzzleHttp\Handler\MockHandler; -use GuzzleHttp\HandlerStack; -use GuzzleHttp\Psr7\Response; use Tests\BaseTestCase; +use ZarinPal\Sdk\ClientBuilder; use ZarinPal\Sdk\Endpoint\GraphQL\TransactionService; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\TransactionListRequest; +use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\TransactionListResponse; +use ZarinPal\Sdk\Options; class TransactionServiceTest extends BaseTestCase { @@ -18,32 +17,23 @@ protected function setUp(): void { parent::setUp(); - // Mock the response without the errors key - $mock = new MockHandler([ - new Response(200, [], json_encode([ - 'data' => [ - 'Session' => [ - [ - 'id' => '1234567890', - 'status' => 'PAID', - 'amount' => 10000, - 'description' => 'Test transaction', - 'created_at' => '2024-08-25T15:00:00+03:30' - ] - ] - ] - ])), + $clientBuilder = new ClientBuilder(); + $options = new Options([ + 'client_builder' => $clientBuilder, + 'access_token' => 'your_access_token', + 'graphql_url' => 'https://your-graphql-endpoint', ]); - $handlerStack = HandlerStack::create($mock); - $mockClient = new Client(['handler' => $handlerStack]); - - // Inject mock client into the TransactionService - $this->transactionService = new TransactionService($this->getOptions()); - $reflection = new \ReflectionClass($this->transactionService); - $clientProperty = $reflection->getProperty('client'); - $clientProperty->setAccessible(true); - $clientProperty->setValue($this->transactionService, $mockClient); + $this->transactionService = $this->createMock(TransactionService::class); + $this->transactionService->method('getTransactions')->willReturn([ + new TransactionListResponse([ + 'id' => '1234567890', + 'status' => 'PAID', + 'amount' => 10000, + 'description' => 'Test transaction', + 'created_at' => '2024-08-25T15:00:00+03:30' + ]) + ]); } public function testGetTransactions() diff --git a/tests/PaymentGateway/PaymentGatewayTest.php b/tests/PaymentGateway/PaymentGatewayTest.php index 04cb687..e64905d 100644 --- a/tests/PaymentGateway/PaymentGatewayTest.php +++ b/tests/PaymentGateway/PaymentGatewayTest.php @@ -3,7 +3,8 @@ namespace Tests\PaymentGateway; use Http\Client\Common\HttpMethodsClientInterface; -use Http\Mock\Client as MockClient; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; use Tests\BaseTestCase; use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\PaymentGateway; @@ -29,18 +30,30 @@ protected function setUp(): void $this->gateway = new PaymentGateway($zarinpal); } + private function createMockResponse($body, $statusCode = 200) + { + $stream = $this->createMock(StreamInterface::class); + $stream->method('getContents')->willReturn(json_encode($body)); + + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn($stream); + $response->method('getStatusCode')->willReturn($statusCode); + + return $response; + } + public function testRequest() { $responseBody = [ 'data' => [ - 'authority' => 'A00000000000000000000000000123456', + 'authority' => 'A0000000000000000000000000012b4A6', ], 'errors' => [] ]; $this->clientMock->expects($this->once()) ->method('post') - ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + ->willReturn($this->createMockResponse($responseBody)); $request = new RequestRequest(); $request->amount = 10000; @@ -50,7 +63,7 @@ public function testRequest() $request->email = 'test@example.com'; $response = $this->gateway->request($request); - $this->assertEquals('A00000000000000000000000000123456', $response->authority); + $this->assertEquals('A0000000000000000000000000012b4A6', $response->authority); } public function testVerify() @@ -65,7 +78,7 @@ public function testVerify() $this->clientMock->expects($this->once()) ->method('post') - ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + ->willReturn($this->createMockResponse($responseBody)); $verify = new VerifyRequest(); $verify->amount = 15000; @@ -103,7 +116,7 @@ public function testUnverified() $this->clientMock->expects($this->once()) ->method('post') - ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + ->willReturn($this->createMockResponse($responseBody)); $unverified = new UnverifiedRequest(); $response = $this->gateway->unverified($unverified); @@ -131,7 +144,7 @@ public function testReverse() $this->clientMock->expects($this->once()) ->method('post') - ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + ->willReturn($this->createMockResponse($responseBody)); $reverseRequest = new ReverseRequest(); $reverseRequest->authority = 'A000000000000000000000000000ydq5y838'; @@ -151,7 +164,7 @@ public function testInquiry() $this->clientMock->expects($this->once()) ->method('post') - ->willReturn(new \GuzzleHttp\Psr7\Response(200, [], json_encode($responseBody))); + ->willReturn($this->createMockResponse($responseBody)); $inquiryRequest = new InquiryRequest(); $inquiryRequest->authority = 'A000000000000000000000000000ydq5y838'; From f33d7d63ef551edbbac5282a2e9e800c4bd9d202 Mon Sep 17 00:00:00 2001 From: Armin Zahedi <00001212aa@gmail.com> Date: Thu, 3 Oct 2024 18:10:38 +0330 Subject: [PATCH 19/23] Add Validator Class --- .../GraphQL/RequestTypes/RefundRequest.php | 11 +- .../RequestTypes/TransactionListRequest.php | 21 ++- .../RequestTypes/InquiryRequest.php | 21 +-- .../RequestTypes/RequestRequest.php | 84 ++-------- .../RequestTypes/ReverseRequest.php | 21 +-- .../RequestTypes/UnverifiedRequest.php | 11 +- .../RequestTypes/VerifyRequest.php | 29 +--- src/Validator.php | 147 ++++++++++++++++++ 8 files changed, 186 insertions(+), 159 deletions(-) create mode 100644 src/Validator.php diff --git a/src/Endpoint/GraphQL/RequestTypes/RefundRequest.php b/src/Endpoint/GraphQL/RequestTypes/RefundRequest.php index 7481453..24887f0 100644 --- a/src/Endpoint/GraphQL/RequestTypes/RefundRequest.php +++ b/src/Endpoint/GraphQL/RequestTypes/RefundRequest.php @@ -3,6 +3,7 @@ namespace ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes; use ZarinPal\Sdk\Endpoint\Fillable; +use ZarinPal\Sdk\Validator; class RefundRequest { @@ -24,12 +25,10 @@ class RefundRequest public function validate(): void { - if (empty($this->sessionId)) { - throw new \InvalidArgumentException('Session ID is required.'); - } - if ($this->amount < 20000) { - throw new \InvalidArgumentException('Amount must be at least 20000 IRR.'); - } + Validator::validateSessionId($this->sessionId); + Validator::validateAmount($this->amount, 20000); + Validator::validateMethod($this->method); + Validator::validateReason($this->reason); } public function toGraphQL(): string diff --git a/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php b/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php index 1db4c45..592bfc5 100644 --- a/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php +++ b/src/Endpoint/GraphQL/RequestTypes/TransactionListRequest.php @@ -3,13 +3,14 @@ namespace ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes; use ZarinPal\Sdk\Endpoint\Fillable; +use ZarinPal\Sdk\Validator; class TransactionListRequest { use Fillable; public string $terminalId; - public ?string $filter = null; // Optional filter: PAID, VERIFIED, TRASH, ACTIVE, REFUNDED + public ?string $filter = null; public ?string $id = null; public ?string $referenceId = null; public ?string $rrn = null; @@ -22,9 +23,13 @@ class TransactionListRequest public function validate(): void { - if (empty($this->terminalId)) { - throw new \InvalidArgumentException('Terminal ID is required.'); - } + Validator::validateTerminalId($this->terminalId); + Validator::validateFilter($this->filter); + Validator::validateEmail($this->email); + Validator::validateMobile($this->mobile); + Validator::validateCardPan($this->cardPan); + Validator::validateLimit($this->limit); + Validator::validateOffset($this->offset); } public function toGraphQL(): string @@ -42,8 +47,8 @@ public function toGraphQL(): string $card_pan: String, $email: String, $mobile: CellNumber, - $description: String - $limit: Int + $description: String, + $limit: Int, $offset: Int ) { Session( @@ -55,8 +60,8 @@ public function toGraphQL(): string card_pan: $card_pan, email: $email, mobile: $mobile, - description: $description - limit: $limit + description: $description, + limit: $limit, offset: $offset ) { id, diff --git a/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php index 61a6789..ea5a0e8 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/InquiryRequest.php @@ -2,9 +2,8 @@ namespace ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes; -use InvalidArgumentException; use ZarinPal\Sdk\Endpoint\Fillable; -use ZarinPal\Sdk\Options; +use ZarinPal\Sdk\Validator; class InquiryRequest { @@ -15,22 +14,8 @@ class InquiryRequest public function validate(): void { - $this->validateMerchantId(); - $this->validateAuthority(); - } - - private function validateMerchantId(): void - { - if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { - throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); - } - } - - private function validateAuthority(): void - { - if (!preg_match('/^A[0-9a-zA-Z]{35}$/', $this->authority)) { - throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); - } + Validator::validateMerchantId($this->merchantId); + Validator::validateAuthority($this->authority); } final public function toString(): string diff --git a/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php index 060b00b..689905c 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php @@ -4,6 +4,7 @@ use InvalidArgumentException; use ZarinPal\Sdk\Endpoint\Fillable; +use ZarinPal\Sdk\Validator; class RequestRequest { @@ -21,81 +22,14 @@ class RequestRequest public function validate(): void { - $this->validateMerchantId(); - $this->validateAmount(); - $this->validateCallbackUrl(); - $this->validateMobile(); - $this->validateEmail(); - $this->validateCurrency(); - $this->validateWages(); - $this->validateCardPan(); - } - - private function validateMerchantId(): void - { - if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { - throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); - } - } - - private function validateAmount(): void - { - if ($this->amount <= 0) { - throw new InvalidArgumentException('Amount must be greater than zero.'); - } - } - - private function validateCallbackUrl(): void - { - if (!preg_match('/^https?:\/\/.*/', $this->callback_url)) { - throw new InvalidArgumentException('Invalid callback URL format. It should start with http:// or https://.'); - } - } - - private function validateMobile(): void - { - if ($this->mobile !== null && !preg_match('/^09[0-9]{9}$/', $this->mobile)) { - throw new InvalidArgumentException('Invalid mobile number format.'); - } - } - - private function validateEmail(): void - { - if ($this->email !== null && !filter_var($this->email, FILTER_VALIDATE_EMAIL)) { - throw new InvalidArgumentException('Invalid email format.'); - } - } - - private function validateCurrency(): void - { - $validCurrencies = ['IRR', 'IRT']; - if ($this->currency !== null && !in_array($this->currency, $validCurrencies)) { - throw new InvalidArgumentException('Invalid currency format. Allowed values are "IRR" or "IRT".'); - } - } - - private function validateWages(): void - { - if ($this->wages !== null) { - foreach ($this->wages as $wage) { - if (!isset($wage['iban']) || !preg_match('/^IR[0-9]{2}[0-9A-Z]{1,24}$/', $wage['iban'])) { - throw new InvalidArgumentException('Invalid IBAN format in wages.'); - } - if (!isset($wage['amount']) || $wage['amount'] <= 0) { - throw new InvalidArgumentException('Wage amount must be greater than zero.'); - } - if (!isset($wage['description']) || strlen($wage['description']) > 255) { - throw new InvalidArgumentException('Wage description must be provided and less than 255 characters.'); - } - } - } - } - - private function validateCardPan(): void - { - if ($this->cardPan !== null && !preg_match('/^[0-9]{16}$/', $this->cardPan)) { - throw new InvalidArgumentException('Invalid card PAN format. It should be a 16-digit number.'); - } + Validator::validateMerchantId($this->merchantId); + Validator::validateAmount($this->amount); + Validator::validateCallbackUrl($this->callback_url); + Validator::validateMobile($this->mobile); + Validator::validateEmail($this->email); + Validator::validateCurrency($this->currency); + Validator::validateWages($this->wages); + Validator::validateCardPan($this->cardPan); } final public function toString(): string diff --git a/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php index 7b3a0b5..8f7b947 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/ReverseRequest.php @@ -2,9 +2,8 @@ namespace ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes; -use InvalidArgumentException; use ZarinPal\Sdk\Endpoint\Fillable; -use ZarinPal\Sdk\Options; +use ZarinPal\Sdk\Validator; class ReverseRequest { @@ -15,22 +14,8 @@ class ReverseRequest public function validate(): void { - $this->validateMerchantId(); - $this->validateAuthority(); - } - - private function validateMerchantId(): void - { - if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { - throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); - } - } - - private function validateAuthority(): void - { - if (!preg_match('/^A[0-9a-zA-Z]{35}$/', $this->authority)) { - throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); - } + Validator::validateMerchantId($this->merchantId); + Validator::validateAuthority($this->authority); } final public function toString(): string diff --git a/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php index b520001..a06b47e 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/UnverifiedRequest.php @@ -2,9 +2,9 @@ namespace ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes; -use InvalidArgumentException; use JsonException; use ZarinPal\Sdk\Endpoint\Fillable; +use ZarinPal\Sdk\Validator; class UnverifiedRequest { @@ -14,14 +14,7 @@ class UnverifiedRequest public function validate(): void { - $this->validateMerchantId(); - } - - private function validateMerchantId(): void - { - if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { - throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); - } + Validator::validateMerchantId($this->merchantId); } /** diff --git a/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php index 2d5df35..4874473 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/VerifyRequest.php @@ -2,9 +2,9 @@ namespace ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes; -use InvalidArgumentException; use JsonException; use ZarinPal\Sdk\Endpoint\Fillable; +use ZarinPal\Sdk\Validator; class VerifyRequest { @@ -16,30 +16,9 @@ class VerifyRequest public function validate(): void { - $this->validateMerchantId(); - $this->validateAmount(); - $this->validateAuthority(); - } - - private function validateMerchantId(): void - { - if ($this->merchantId === null || !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $this->merchantId)) { - throw new InvalidArgumentException('Invalid merchant_id format. It should be a valid UUID.'); - } - } - - private function validateAmount(): void - { - if ($this->amount <= 0) { - throw new InvalidArgumentException('Amount must be greater than zero.'); - } - } - - private function validateAuthority(): void - { - if (!preg_match('/^A[0-9a-zA-Z]{35}$/', $this->authority)) { - throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 32 alphanumeric characters.'); - } + Validator::validateMerchantId($this->merchantId); + Validator::validateAmount($this->amount); + Validator::validateAuthority($this->authority); } /** diff --git a/src/Validator.php b/src/Validator.php new file mode 100644 index 0000000..f7fac08 --- /dev/null +++ b/src/Validator.php @@ -0,0 +1,147 @@ + 255) { + throw new InvalidArgumentException('Wage description must be provided and less than 255 characters.'); + } + } + } + } + + public static function validateTerminalId(string $terminalId): void + { + if (empty($terminalId)) { + throw new InvalidArgumentException('Terminal ID is required.'); + } + } + + public static function validateFilter(?string $filter): void + { + if ($filter !== null) { + $validFilters = ['PAID', 'VERIFIED', 'TRASH', 'ACTIVE', 'REFUNDED']; + if (!in_array($filter, $validFilters)) { + throw new InvalidArgumentException('Invalid filter value.'); + } + } + } + + public static function validateLimit(?int $limit): void + { + if ($limit !== null && $limit <= 0) { + throw new InvalidArgumentException('Limit must be a positive integer.'); + } + } + + public static function validateOffset(?int $offset): void + { + if ($offset !== null && $offset < 0) { + throw new InvalidArgumentException('Offset must be a non-negative integer.'); + } + } + + public static function validateCardPan(?string $cardPan): void + { + if ($cardPan !== null && !preg_match('/^[0-9]{16}$/', $cardPan)) { + throw new InvalidArgumentException('Invalid card PAN format. It should be a 16-digit number.'); + } + } + + public static function validateSessionId(string $sessionId): void + { + if (empty($sessionId)) { + throw new InvalidArgumentException('Session ID is required.'); + } + } + + public static function validateMethod(string $method): void + { + $validMethods = ['PAYA', 'CARD']; + if (!in_array($method, $validMethods)) { + throw new InvalidArgumentException('Invalid method. Allowed values are "PAYA" or "CARD".'); + } + } + + public static function validateReason(string $reason): void + { + $validReasons = [ + 'CUSTOMER_REQUEST', + 'DUPLICATE_TRANSACTION', + 'SUSPICIOUS_TRANSACTION', + 'OTHER' + ]; + if (!in_array($reason, $validReasons)) { + throw new InvalidArgumentException('Invalid reason. Allowed values are "CUSTOMER_REQUEST", "DUPLICATE_TRANSACTION", "SUSPICIOUS_TRANSACTION", or "OTHER".'); + } + } +} From 12116c2e75fbb743648a9eaabdafbd5d93a0b94b Mon Sep 17 00:00:00 2001 From: Armin Zahedi <00001212aa@gmail.com> Date: Thu, 3 Oct 2024 19:07:42 +0330 Subject: [PATCH 20/23] Generate UUID --- examples/Inquiry.php | 2 +- examples/Request.php | 2 +- examples/Reverse.php | 2 +- examples/Transaction.php | 2 ++ examples/Verify.php | 2 +- examples/unVerified.php | 20 +++++++++++-------- .../ResponseTypes/UnverifiedResponse.php | 6 ------ src/Validator.php | 4 ++-- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/Inquiry.php b/examples/Inquiry.php index a3f030b..9e26dcb 100644 --- a/examples/Inquiry.php +++ b/examples/Inquiry.php @@ -7,7 +7,7 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\InquiryRequest; $options = new Options([ - 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', ]); $zarinpal = new ZarinPal($options); diff --git a/examples/Request.php b/examples/Request.php index 59cd044..1f51a50 100644 --- a/examples/Request.php +++ b/examples/Request.php @@ -17,7 +17,7 @@ $options = new Options([ 'client_builder' => $clientBuilder, 'sandbox' => false, // Enable sandbox mode - 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', ]); $zarinpal = new ZarinPal($options); diff --git a/examples/Reverse.php b/examples/Reverse.php index bc39c65..2f5cd1d 100644 --- a/examples/Reverse.php +++ b/examples/Reverse.php @@ -7,7 +7,7 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\ReverseRequest; $options = new Options([ - 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', ]); $zarinpal = new ZarinPal($options); diff --git a/examples/Transaction.php b/examples/Transaction.php index e3eba3d..4d3c25a 100644 --- a/examples/Transaction.php +++ b/examples/Transaction.php @@ -27,6 +27,8 @@ $transactions = $transactionService->getTransactions($transactionRequest); + die(var_dump($transactions)); + $transactionArray = []; foreach ($transactions as $transaction) { $transactionArray[] = [ diff --git a/examples/Verify.php b/examples/Verify.php index f95a6c0..d77824b 100644 --- a/examples/Verify.php +++ b/examples/Verify.php @@ -17,7 +17,7 @@ $options = new Options([ 'client_builder' => $clientBuilder, 'sandbox' => false, - 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', ]); $zarinpal = new ZarinPal($options); diff --git a/examples/unVerified.php b/examples/unVerified.php index 8fd32b1..7ac83ce 100644 --- a/examples/unVerified.php +++ b/examples/unVerified.php @@ -7,7 +7,7 @@ use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\UnverifiedRequest; $options = new Options([ - 'merchant_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', ]); $zarinpal = new ZarinPal($options); @@ -20,13 +20,17 @@ $response = $paymentGateway->unverified($unverifiedRequest); if ($response->code === 100) { - foreach ($response->authorities as $transaction) { - echo "Transaction Authority: " . $transaction['authority'] . "\n"; - echo "Amount: " . $transaction['amount'] . "\n"; - echo "Callback URL: " . $transaction['callback_url'] . "\n"; - echo "Referer: " . $transaction['referer'] . "\n"; - echo "Date: " . $transaction['date'] . "\n"; - echo "--------------------------\n"; + if (empty($response->authorities)) { + echo "No authorities found.\n"; + } else { + foreach ($response->authorities as $transaction) { + echo "Transaction Authority: " . $transaction['authority'] . "\n"; + echo "Amount: " . $transaction['amount'] . "\n"; + echo "Callback URL: " . $transaction['callback_url'] . "\n"; + echo "Referer: " . $transaction['referer'] . "\n"; + echo "Date: " . $transaction['date'] . "\n"; + echo "--------------------------\n"; + } } } else { echo "Failed to retrieve unverified transactions. Code: " . $response->code . "\n"; diff --git a/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php b/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php index 7213cdc..5f5e586 100644 --- a/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php +++ b/src/Endpoint/PaymentGateway/ResponseTypes/UnverifiedResponse.php @@ -14,12 +14,6 @@ class UnverifiedResponse public function __construct(array $data = null) { - if ($data === null || !isset($data['code'], $data['message'])) { - $this->code = 0; - $this->message = 'No data received'; - return; - } - $this->code = $data['code']; $this->message = $data['message']; diff --git a/src/Validator.php b/src/Validator.php index f7fac08..56a74e2 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -21,8 +21,8 @@ public static function validateMerchantId(?string $merchantId): void public static function validateAuthority(string $authority): void { - if (!preg_match('/^A[0-9a-zA-Z]{35}$/', $authority)) { - throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" followed by 35 alphanumeric characters.'); + if (!preg_match('/^[AS][0-9a-zA-Z]{35}$/', $authority)) { + throw new InvalidArgumentException('Invalid authority format. It should be a string starting with "A" or "S" followed by 35 alphanumeric characters.'); } } From 44694d8a4ed456c707e46c459e8c9e9e9afd9705 Mon Sep 17 00:00:00 2001 From: Armin Zahedi <00001212aa@gmail.com> Date: Thu, 3 Oct 2024 19:11:01 +0330 Subject: [PATCH 21/23] Generate UUID --- tests/BaseTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index 6a18977..14ffc96 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -18,7 +18,7 @@ protected function setUp(): void $this->mockClient = new MockClient(); $this->options = new Options([ 'access_token' => 'mock-access-token', - 'merchant_id' => '25fe4c36-66e4-11e9-a9e4-000c29344814', + 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', ]); } From e334872b1b7ddf96528c4f24441f1612942391dc Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Sun, 6 Oct 2024 16:02:45 +0330 Subject: [PATCH 22/23] Add Refrrer Id --- examples/Inquiry.php | 6 +++++- examples/Request.php | 7 ++++--- examples/Reverse.php | 8 +++++++- examples/Transaction.php | 8 ++------ examples/Verify.php | 8 +++++--- examples/unVerified.php | 7 +++++++ .../PaymentGateway/RequestTypes/RequestRequest.php | 2 ++ 7 files changed, 32 insertions(+), 14 deletions(-) diff --git a/examples/Inquiry.php b/examples/Inquiry.php index 9e26dcb..f592a68 100644 --- a/examples/Inquiry.php +++ b/examples/Inquiry.php @@ -4,6 +4,7 @@ use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; +use ZarinPal\Sdk\HttpClient\Exception\ResponseException; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\InquiryRequest; $options = new Options([ @@ -22,6 +23,9 @@ echo "Amount: " . $response->code . "\n"; echo "Status: " . $response->message . "\n"; echo "Status: " . $response->status . "\n"; + +} catch (ResponseException $e) { + echo 'Transaction Inquiry Validation Error: ' . $e->getErrorDetails(); } catch (\Exception $e) { - echo 'Transaction inquiry failed: ' . $e->getMessage(); + echo 'Transaction Inquiry Validation Error: ' . $e->getMessage(); } diff --git a/examples/Request.php b/examples/Request.php index 1f51a50..fb063c1 100644 --- a/examples/Request.php +++ b/examples/Request.php @@ -30,6 +30,7 @@ $request->mobile = '09220949640'; // Optional $request->email = 'test@example.com'; // Optional $request->currency = 'IRR'; // Optional IRR Or IRT (default IRR) +$request->referrer_id = 'GYKCZDF'; // Optional IRR Or IRT (default IRR) $request->cardPan = '5894631122689482'; // Optional $request->wages = [ [ @@ -50,8 +51,8 @@ header('Location:'. $url); } catch (ResponseException $e) { + echo 'Error in payment request: ' . $e->getMessage(); var_dump($e->getErrorDetails()); - } catch (\Exception $e) { - var_dump($e->getMessage()); - } + echo 'Payment Error: ' . $e->getMessage(); +} diff --git a/examples/Reverse.php b/examples/Reverse.php index 2f5cd1d..2596bb1 100644 --- a/examples/Reverse.php +++ b/examples/Reverse.php @@ -5,6 +5,7 @@ use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\ReverseRequest; +use ZarinPal\Sdk\HttpClient\Exception\ResponseException; $options = new Options([ 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', @@ -20,6 +21,11 @@ $response = $paymentGateway->reverse($reverseRequest); echo "Transaction Reversed: " . $response->code . "\n"; echo "Transaction Reversed: " . $response->message . "\n"; + } catch (ResponseException $e) { + echo 'Transaction reversal failed due to API error: ' . $e->getMessage() . "\n"; + if ($e->getErrorDetails()) { + echo 'Error Details: ' . json_encode($e->getErrorDetails()) . "\n"; + } } catch (\Exception $e) { - echo 'Transaction reversal failed: ' . $e->getMessage(); + echo 'Transaction reversal failed: ' . $e->getMessage() . "\n"; } diff --git a/examples/Transaction.php b/examples/Transaction.php index 4d3c25a..11371f2 100644 --- a/examples/Transaction.php +++ b/examples/Transaction.php @@ -27,8 +27,6 @@ $transactions = $transactionService->getTransactions($transactionRequest); - die(var_dump($transactions)); - $transactionArray = []; foreach ($transactions as $transaction) { $transactionArray[] = [ @@ -41,8 +39,6 @@ } echo json_encode($transactionArray, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); -} catch (ResponseException $e) { - echo "GraphQL Error: " . $e->getMessage(); -} catch (Exception $e) { - echo "General Error: " . $e->getMessage(); + } catch (Exception $e) { + echo "General Error: " . $e->getMessage(); } diff --git a/examples/Verify.php b/examples/Verify.php index d77824b..8792290 100644 --- a/examples/Verify.php +++ b/examples/Verify.php @@ -7,7 +7,7 @@ use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\VerifyRequest; - +use ZarinPal\Sdk\HttpClient\Exception\ResponseException; $clientBuilder = new ClientBuilder(); $clientBuilder->addPlugin(new HeaderDefaultsPlugin([ @@ -49,11 +49,13 @@ echo "Transaction failed with code: " . $response->code; } + } catch (ResponseException $e) { + echo 'Payment Verification Failed: ' . $e->getErrorDetails(); } catch (\Exception $e) { - echo 'Payment verification failed: ' . $e->getMessage(); + echo 'Payment Error: ' . $e->getMessage(); } } else { - echo 'No matching transaction found for this authority code.'; + echo 'No Matching Transaction Found For This Authority Code.'; } } else { echo 'Transaction was cancelled or failed.'; diff --git a/examples/unVerified.php b/examples/unVerified.php index 7ac83ce..9f5be83 100644 --- a/examples/unVerified.php +++ b/examples/unVerified.php @@ -5,6 +5,8 @@ use ZarinPal\Sdk\Options; use ZarinPal\Sdk\ZarinPal; use ZarinPal\Sdk\Endpoint\PaymentGateway\RequestTypes\UnverifiedRequest; +use ZarinPal\Sdk\HttpClient\Exception\ResponseException; + $options = new Options([ 'merchant_id' => '67887a6d-e2f8-4de2-86b1-8db27bc171b5', @@ -36,6 +38,11 @@ echo "Failed to retrieve unverified transactions. Code: " . $response->code . "\n"; echo "Message: " . $response->message . "\n"; } +} catch (ResponseException $e) { + echo 'Unverified inquiry failed: ' . $e->getMessage() . "\n"; + if ($e->getErrorDetails()) { + echo 'Error Details: ' . json_encode($e->getErrorDetails()) . "\n"; + } } catch (\Exception $e) { echo 'Unverified inquiry failed: ' . $e->getMessage(); } \ No newline at end of file diff --git a/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php b/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php index 689905c..43f7a12 100644 --- a/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php +++ b/src/Endpoint/PaymentGateway/RequestTypes/RequestRequest.php @@ -16,6 +16,7 @@ class RequestRequest public string $callback_url; public ?string $mobile = null; public ?string $email = null; + public ?string $referrer_id = null; public ?string $currency = null; public ?array $wages = null; public ?string $cardPan = null; @@ -44,6 +45,7 @@ final public function toString(): string "metadata" => [ "mobile" => $this->mobile, "email" => $this->email, + "referrer_id" => $this->referrer_id, ] ]; From 9a118e3d9650a56c57b0e5b06d30b6bea25cce5b Mon Sep 17 00:00:00 2001 From: ar4min <00001212aa@gmail.com> Date: Mon, 7 Oct 2024 10:30:40 +0330 Subject: [PATCH 23/23] Add BaseGraphQl Service --- .env.example | 19 +++++ examples/Request.php | 11 ++- src/Endpoint/GraphQL/BaseGraphQLService.php | 83 +++++++++++++++++++ src/Endpoint/GraphQL/RefundService.php | 77 +---------------- src/Endpoint/GraphQL/TransactionService.php | 76 +---------------- .../PaymentGateway/PaymentGateway.php | 4 +- src/Validator.php | 2 +- src/ZarinPal.php | 4 +- 8 files changed, 117 insertions(+), 159 deletions(-) create mode 100644 .env.example create mode 100644 src/Endpoint/GraphQL/BaseGraphQLService.php diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c4c573f --- /dev/null +++ b/.env.example @@ -0,0 +1,19 @@ +# ZarinPal SDK Configuration + +# Base URL for production +ZARINPAL_BASE_URL=https://payment.zarinpal.com + +# Base URL for sandbox/testing +ZARINPAL_SANDBOX_BASE_URL=https://sandbox.zarinpal.com + +# Merchant ID for ZarinPal +ZARINPAL_MERCHANT_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + +# GraphQL URL for ZarinPal +ZARINPAL_GRAPHQL_URL=https://next.zarinpal.com/api/v4/graphql/ + +# Access token for authentication +ZARINPAL_ACCESS_TOKEN= + +# Set to true to use the sandbox environment +ZARINPAL_SANDBOX=false diff --git a/examples/Request.php b/examples/Request.php index fb063c1..4f4347b 100644 --- a/examples/Request.php +++ b/examples/Request.php @@ -26,20 +26,20 @@ $request = new RequestRequest(); $request->amount = 10000; //Minimum amount 10000 IRR $request->description = 'Payment for order 12345'; -$request->callback_url = 'https://your-site/examples/verify.php'; -$request->mobile = '09220949640'; // Optional +$request->callback_url = 'https://your-site.test/examples/verify.php'; +$request->mobile = '09120987654'; // Optional $request->email = 'test@example.com'; // Optional $request->currency = 'IRR'; // Optional IRR Or IRT (default IRR) $request->referrer_id = 'GYKCZDF'; // Optional IRR Or IRT (default IRR) -$request->cardPan = '5894631122689482'; // Optional +$request->cardPan = '5894631122689480'; // Optional $request->wages = [ [ - 'iban' => 'IR130570028780010957775103', + 'iban' => 'IR130570028780010957775102', 'amount' =>5000, 'description' => 'تسهیم سود فروش' ], [ - 'iban' => 'IR670170000000352965862009', + 'iban' => 'IR670170000000352965862005', 'amount' => 5000, 'description' => 'تسهیم سود فروش به شخص دوم' ] @@ -51,7 +51,6 @@ header('Location:'. $url); } catch (ResponseException $e) { - echo 'Error in payment request: ' . $e->getMessage(); var_dump($e->getErrorDetails()); } catch (\Exception $e) { echo 'Payment Error: ' . $e->getMessage(); diff --git a/src/Endpoint/GraphQL/BaseGraphQLService.php b/src/Endpoint/GraphQL/BaseGraphQLService.php new file mode 100644 index 0000000..44ddaf0 --- /dev/null +++ b/src/Endpoint/GraphQL/BaseGraphQLService.php @@ -0,0 +1,83 @@ +clientBuilder = $clientBuilder; + $this->options = $options; + $this->graphqlUrl = $options->getGraphqlUrl(); + } + + protected function httpHandler(string $uri, string $body): array + { + try { + $httpClient = $this->clientBuilder->getHttpClient(); + $response = $httpClient->post($uri, [ + 'User-Agent' => ZarinPal::USER_AGENT, + 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), + 'Content-Type' => 'application/json', + ], $body); + + $this->checkHttpError($response); + + $responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); + + } catch (JsonException $e) { + throw new ResponseException('JSON parsing error: ' . $e->getMessage(), $e->getCode(), null, ['details' => $e->getMessage()]); + } catch (ResponseException $e) { + throw new ResponseException('Response error: ' . $e->getMessage(), $e->getCode(), null, $e->getErrorDetails()); + } + + return $this->checkGraphQLError($responseData); + } + + protected function checkHttpError(ResponseInterface $response): void + { + $statusCode = $response->getStatusCode(); + if ($statusCode !== 200) { + $body = $response->getBody()->getContents(); + $parsedBody = json_decode($body, true); + + $errorData = [ + 'data' => [], + 'errors' => [ + 'message' => $response->getReasonPhrase(), + 'code' => $statusCode, + 'details' => $parsedBody ?? [] + ] + ]; + + throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData); + } + } + + protected function checkGraphQLError(array $response): array + { + if (isset($response['errors']) || empty($response['data'])) { + $errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1]; + throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']); + } + + return $response; + } + + protected function getClassName(): string + { + return basename(str_replace('\\', '/', static::class)); + } +} + diff --git a/src/Endpoint/GraphQL/RefundService.php b/src/Endpoint/GraphQL/RefundService.php index f3887d8..1a8c134 100644 --- a/src/Endpoint/GraphQL/RefundService.php +++ b/src/Endpoint/GraphQL/RefundService.php @@ -3,25 +3,15 @@ namespace ZarinPal\Sdk\Endpoint\GraphQL; use ZarinPal\Sdk\ClientBuilder; -use ZarinPal\Sdk\Options; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest; use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\RefundResponse; -use ZarinPal\Sdk\HttpClient\Exception\ResponseException; -use Psr\Http\Message\ResponseInterface; -use JsonException; -use Exception; +use ZarinPal\Sdk\Options; -class RefundService +class RefundService extends BaseGraphQLService { - private ClientBuilder $clientBuilder; - private Options $options; - private string $graphqlUrl; - public function __construct(ClientBuilder $clientBuilder, Options $options) { - $this->clientBuilder = $clientBuilder; - $this->options = $options; - $this->graphqlUrl = $options->getGraphqlUrl(); + parent::__construct($clientBuilder, $options); } public function refund(RefundRequest $request): RefundResponse @@ -32,65 +22,4 @@ public function refund(RefundRequest $request): RefundResponse return new RefundResponse($response['data']['resource']); } - - private function httpHandler(string $uri, string $body): array - { - try { - $httpClient = $this->clientBuilder->getHttpClient(); - - $response = $httpClient->post($uri, [ - 'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION), - 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), - 'Content-Type' => 'application/json', - ], $body); - - $this->checkHttpError($response); - - $responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); - - } catch (JsonException $e) { - throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]); - } catch (ResponseException $e) { - throw $e; - } catch (Exception $e) { - throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]); - } - - return $this->checkGraphQLError($responseData); - } - - private function checkHttpError(ResponseInterface $response): void - { - $statusCode = $response->getStatusCode(); - if ($statusCode !== 200) { - $body = $response->getBody()->getContents(); - $parsedBody = json_decode($body, true); - - $errorData = [ - 'data' => [], - 'errors' => [ - 'message' => $response->getReasonPhrase(), - 'code' => $statusCode, - 'details' => $parsedBody ?? [] - ] - ]; - - throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData); - } - } - - private function checkGraphQLError(array $response): array - { - if (isset($response['errors']) || empty($response['data'])) { - $errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1]; - throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']); - } - - return $response; - } - - private function getClassName(): string - { - return basename(str_replace('\\', '/', __CLASS__)); - } } diff --git a/src/Endpoint/GraphQL/TransactionService.php b/src/Endpoint/GraphQL/TransactionService.php index e8b8d56..de3ef95 100644 --- a/src/Endpoint/GraphQL/TransactionService.php +++ b/src/Endpoint/GraphQL/TransactionService.php @@ -5,23 +5,13 @@ use ZarinPal\Sdk\ClientBuilder; use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\TransactionListRequest; use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\TransactionListResponse; -use ZarinPal\Sdk\HttpClient\Exception\ResponseException; use ZarinPal\Sdk\Options; -use Psr\Http\Message\ResponseInterface; -use JsonException; -use Exception; -class TransactionService +class TransactionService extends BaseGraphQLService { - private ClientBuilder $clientBuilder; - private Options $options; - private string $graphqlUrl; - public function __construct(ClientBuilder $clientBuilder, Options $options) { - $this->clientBuilder = $clientBuilder; - $this->options = $options; - $this->graphqlUrl = $options->getGraphqlUrl(); + parent::__construct($clientBuilder, $options); } public function getTransactions(TransactionListRequest $request): array @@ -37,66 +27,4 @@ public function getTransactions(TransactionListRequest $request): array return $transactions; } - - private function httpHandler(string $uri, string $body): array - { - try { - $httpClient = $this->clientBuilder->getHttpClient(); - $response = $httpClient->post($uri, [ - 'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION), - 'Authorization' => 'Bearer ' . $this->options->getAccessToken(), - 'Content-Type' => 'application/json', - ], $body); - - $responseContent = $response->getBody()->getContents(); - $this->checkHttpError($response); - - $responseData = json_decode($responseContent, true, 512, JSON_THROW_ON_ERROR); - - } catch (JsonException $e) { - throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]); - } catch (ResponseException $e) { - throw $e; - } catch (Exception $e) { - throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]); - } - - return $this->checkGraphQLError($responseData); - } - - - private function checkHttpError(ResponseInterface $response): void - { - $statusCode = $response->getStatusCode(); - if ($statusCode !== 200) { - $body = $response->getBody()->getContents(); - $parsedBody = json_decode($body, true); - - $errorData = [ - 'data' => [], - 'errors' => [ - 'message' => $response->getReasonPhrase(), - 'code' => $statusCode, - 'details' => $parsedBody ?? [] - ] - ]; - - throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData); - } - } - - private function checkGraphQLError(array $response): array - { - if (isset($response['errors']) || empty($response['data'])) { - $errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1]; - throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']); - } - - return $response; - } - - private function getClassName(): string - { - return basename(str_replace('\\', '/', __CLASS__)); - } } diff --git a/src/Endpoint/PaymentGateway/PaymentGateway.php b/src/Endpoint/PaymentGateway/PaymentGateway.php index 3a12140..7049368 100644 --- a/src/Endpoint/PaymentGateway/PaymentGateway.php +++ b/src/Endpoint/PaymentGateway/PaymentGateway.php @@ -94,9 +94,7 @@ private function httpHandler(string $uri, string $body): array } catch (JsonException $e) { throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]); } catch (ResponseException $e) { - throw $e; - } catch (Exception $e) { - throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]); + throw new ResponseException('Response error: ' . $e->getMessage(), $e->getCode(), null, $e->getErrorDetails()); } return $this->checkPaymentGatewayError($response); diff --git a/src/Validator.php b/src/Validator.php index 56a74e2..86bbe94 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -26,7 +26,7 @@ public static function validateAuthority(string $authority): void } } - public static function validateAmount(int $amount, int $minAmount = 1): void + public static function validateAmount(int $amount, int $minAmount = 1000): void { if ($amount < $minAmount) { throw new InvalidArgumentException("Amount must be at least {$minAmount}."); diff --git a/src/ZarinPal.php b/src/ZarinPal.php index 3e510a7..8ea981e 100644 --- a/src/ZarinPal.php +++ b/src/ZarinPal.php @@ -15,6 +15,8 @@ final class ZarinPal private Options $options; private HttpMethodsClientInterface $httpClient; + public const USER_AGENT = 'ZarinPalSdk/v.1.0 (php ' . PHP_VERSION . ')'; + public function __construct(Options $options = null) { $this->options = $options ?? new Options(); @@ -23,7 +25,7 @@ public function __construct(Options $options = null) $this->clientBuilder->addPlugin( new HeaderDefaultsPlugin( [ - 'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION), + 'User-Agent' => self::USER_AGENT, 'Content-Type' => 'application/json', 'Accept' => 'application/json', ]