Skip to content

Commit 9a118e3

Browse files
committed
Add BaseGraphQl Service
1 parent e334872 commit 9a118e3

File tree

8 files changed

+117
-159
lines changed

8 files changed

+117
-159
lines changed

.env.example

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# ZarinPal SDK Configuration
2+
3+
# Base URL for production
4+
ZARINPAL_BASE_URL=https://payment.zarinpal.com
5+
6+
# Base URL for sandbox/testing
7+
ZARINPAL_SANDBOX_BASE_URL=https://sandbox.zarinpal.com
8+
9+
# Merchant ID for ZarinPal
10+
ZARINPAL_MERCHANT_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
11+
12+
# GraphQL URL for ZarinPal
13+
ZARINPAL_GRAPHQL_URL=https://next.zarinpal.com/api/v4/graphql/
14+
15+
# Access token for authentication
16+
ZARINPAL_ACCESS_TOKEN=
17+
18+
# Set to true to use the sandbox environment
19+
ZARINPAL_SANDBOX=false

examples/Request.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,20 @@
2626
$request = new RequestRequest();
2727
$request->amount = 10000; //Minimum amount 10000 IRR
2828
$request->description = 'Payment for order 12345';
29-
$request->callback_url = 'https://your-site/examples/verify.php';
30-
$request->mobile = '09220949640'; // Optional
29+
$request->callback_url = 'https://your-site.test/examples/verify.php';
30+
$request->mobile = '09120987654'; // Optional
3131
$request->email = 'test@example.com'; // Optional
3232
$request->currency = 'IRR'; // Optional IRR Or IRT (default IRR)
3333
$request->referrer_id = 'GYKCZDF'; // Optional IRR Or IRT (default IRR)
34-
$request->cardPan = '5894631122689482'; // Optional
34+
$request->cardPan = '5894631122689480'; // Optional
3535
$request->wages = [
3636
[
37-
'iban' => 'IR130570028780010957775103',
37+
'iban' => 'IR130570028780010957775102',
3838
'amount' =>5000,
3939
'description' => 'تسهیم سود فروش'
4040
],
4141
[
42-
'iban' => 'IR670170000000352965862009',
42+
'iban' => 'IR670170000000352965862005',
4343
'amount' => 5000,
4444
'description' => 'تسهیم سود فروش به شخص دوم'
4545
]
@@ -51,7 +51,6 @@
5151
header('Location:'. $url);
5252

5353
} catch (ResponseException $e) {
54-
echo 'Error in payment request: ' . $e->getMessage();
5554
var_dump($e->getErrorDetails());
5655
} catch (\Exception $e) {
5756
echo 'Payment Error: ' . $e->getMessage();
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
namespace ZarinPal\Sdk\Endpoint\GraphQL;
4+
5+
use ZarinPal\Sdk\ClientBuilder;
6+
use ZarinPal\Sdk\Options;
7+
use ZarinPal\Sdk\HttpClient\Exception\ResponseException;
8+
use Psr\Http\Message\ResponseInterface;
9+
use JsonException;
10+
use ZarinPal\Sdk\ZarinPal;
11+
12+
class BaseGraphQLService
13+
{
14+
protected ClientBuilder $clientBuilder;
15+
protected Options $options;
16+
protected string $graphqlUrl;
17+
18+
public function __construct(ClientBuilder $clientBuilder, Options $options)
19+
{
20+
$this->clientBuilder = $clientBuilder;
21+
$this->options = $options;
22+
$this->graphqlUrl = $options->getGraphqlUrl();
23+
}
24+
25+
protected function httpHandler(string $uri, string $body): array
26+
{
27+
try {
28+
$httpClient = $this->clientBuilder->getHttpClient();
29+
$response = $httpClient->post($uri, [
30+
'User-Agent' => ZarinPal::USER_AGENT,
31+
'Authorization' => 'Bearer ' . $this->options->getAccessToken(),
32+
'Content-Type' => 'application/json',
33+
], $body);
34+
35+
$this->checkHttpError($response);
36+
37+
$responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
38+
39+
} catch (JsonException $e) {
40+
throw new ResponseException('JSON parsing error: ' . $e->getMessage(), $e->getCode(), null, ['details' => $e->getMessage()]);
41+
} catch (ResponseException $e) {
42+
throw new ResponseException('Response error: ' . $e->getMessage(), $e->getCode(), null, $e->getErrorDetails());
43+
}
44+
45+
return $this->checkGraphQLError($responseData);
46+
}
47+
48+
protected function checkHttpError(ResponseInterface $response): void
49+
{
50+
$statusCode = $response->getStatusCode();
51+
if ($statusCode !== 200) {
52+
$body = $response->getBody()->getContents();
53+
$parsedBody = json_decode($body, true);
54+
55+
$errorData = [
56+
'data' => [],
57+
'errors' => [
58+
'message' => $response->getReasonPhrase(),
59+
'code' => $statusCode,
60+
'details' => $parsedBody ?? []
61+
]
62+
];
63+
64+
throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData);
65+
}
66+
}
67+
68+
protected function checkGraphQLError(array $response): array
69+
{
70+
if (isset($response['errors']) || empty($response['data'])) {
71+
$errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1];
72+
throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']);
73+
}
74+
75+
return $response;
76+
}
77+
78+
protected function getClassName(): string
79+
{
80+
return basename(str_replace('\\', '/', static::class));
81+
}
82+
}
83+

src/Endpoint/GraphQL/RefundService.php

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,15 @@
33
namespace ZarinPal\Sdk\Endpoint\GraphQL;
44

55
use ZarinPal\Sdk\ClientBuilder;
6-
use ZarinPal\Sdk\Options;
76
use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\RefundRequest;
87
use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\RefundResponse;
9-
use ZarinPal\Sdk\HttpClient\Exception\ResponseException;
10-
use Psr\Http\Message\ResponseInterface;
11-
use JsonException;
12-
use Exception;
8+
use ZarinPal\Sdk\Options;
139

14-
class RefundService
10+
class RefundService extends BaseGraphQLService
1511
{
16-
private ClientBuilder $clientBuilder;
17-
private Options $options;
18-
private string $graphqlUrl;
19-
2012
public function __construct(ClientBuilder $clientBuilder, Options $options)
2113
{
22-
$this->clientBuilder = $clientBuilder;
23-
$this->options = $options;
24-
$this->graphqlUrl = $options->getGraphqlUrl();
14+
parent::__construct($clientBuilder, $options);
2515
}
2616

2717
public function refund(RefundRequest $request): RefundResponse
@@ -32,65 +22,4 @@ public function refund(RefundRequest $request): RefundResponse
3222

3323
return new RefundResponse($response['data']['resource']);
3424
}
35-
36-
private function httpHandler(string $uri, string $body): array
37-
{
38-
try {
39-
$httpClient = $this->clientBuilder->getHttpClient();
40-
41-
$response = $httpClient->post($uri, [
42-
'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION),
43-
'Authorization' => 'Bearer ' . $this->options->getAccessToken(),
44-
'Content-Type' => 'application/json',
45-
], $body);
46-
47-
$this->checkHttpError($response);
48-
49-
$responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
50-
51-
} catch (JsonException $e) {
52-
throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]);
53-
} catch (ResponseException $e) {
54-
throw $e;
55-
} catch (Exception $e) {
56-
throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]);
57-
}
58-
59-
return $this->checkGraphQLError($responseData);
60-
}
61-
62-
private function checkHttpError(ResponseInterface $response): void
63-
{
64-
$statusCode = $response->getStatusCode();
65-
if ($statusCode !== 200) {
66-
$body = $response->getBody()->getContents();
67-
$parsedBody = json_decode($body, true);
68-
69-
$errorData = [
70-
'data' => [],
71-
'errors' => [
72-
'message' => $response->getReasonPhrase(),
73-
'code' => $statusCode,
74-
'details' => $parsedBody ?? []
75-
]
76-
];
77-
78-
throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData);
79-
}
80-
}
81-
82-
private function checkGraphQLError(array $response): array
83-
{
84-
if (isset($response['errors']) || empty($response['data'])) {
85-
$errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1];
86-
throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']);
87-
}
88-
89-
return $response;
90-
}
91-
92-
private function getClassName(): string
93-
{
94-
return basename(str_replace('\\', '/', __CLASS__));
95-
}
9625
}

src/Endpoint/GraphQL/TransactionService.php

Lines changed: 2 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,13 @@
55
use ZarinPal\Sdk\ClientBuilder;
66
use ZarinPal\Sdk\Endpoint\GraphQL\RequestTypes\TransactionListRequest;
77
use ZarinPal\Sdk\Endpoint\GraphQL\ResponseTypes\TransactionListResponse;
8-
use ZarinPal\Sdk\HttpClient\Exception\ResponseException;
98
use ZarinPal\Sdk\Options;
10-
use Psr\Http\Message\ResponseInterface;
11-
use JsonException;
12-
use Exception;
139

14-
class TransactionService
10+
class TransactionService extends BaseGraphQLService
1511
{
16-
private ClientBuilder $clientBuilder;
17-
private Options $options;
18-
private string $graphqlUrl;
19-
2012
public function __construct(ClientBuilder $clientBuilder, Options $options)
2113
{
22-
$this->clientBuilder = $clientBuilder;
23-
$this->options = $options;
24-
$this->graphqlUrl = $options->getGraphqlUrl();
14+
parent::__construct($clientBuilder, $options);
2515
}
2616

2717
public function getTransactions(TransactionListRequest $request): array
@@ -37,66 +27,4 @@ public function getTransactions(TransactionListRequest $request): array
3727

3828
return $transactions;
3929
}
40-
41-
private function httpHandler(string $uri, string $body): array
42-
{
43-
try {
44-
$httpClient = $this->clientBuilder->getHttpClient();
45-
$response = $httpClient->post($uri, [
46-
'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION),
47-
'Authorization' => 'Bearer ' . $this->options->getAccessToken(),
48-
'Content-Type' => 'application/json',
49-
], $body);
50-
51-
$responseContent = $response->getBody()->getContents();
52-
$this->checkHttpError($response);
53-
54-
$responseData = json_decode($responseContent, true, 512, JSON_THROW_ON_ERROR);
55-
56-
} catch (JsonException $e) {
57-
throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]);
58-
} catch (ResponseException $e) {
59-
throw $e;
60-
} catch (Exception $e) {
61-
throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]);
62-
}
63-
64-
return $this->checkGraphQLError($responseData);
65-
}
66-
67-
68-
private function checkHttpError(ResponseInterface $response): void
69-
{
70-
$statusCode = $response->getStatusCode();
71-
if ($statusCode !== 200) {
72-
$body = $response->getBody()->getContents();
73-
$parsedBody = json_decode($body, true);
74-
75-
$errorData = [
76-
'data' => [],
77-
'errors' => [
78-
'message' => $response->getReasonPhrase(),
79-
'code' => $statusCode,
80-
'details' => $parsedBody ?? []
81-
]
82-
];
83-
84-
throw new ResponseException($errorData['errors']['message'], $errorData['errors']['code'], null, $errorData);
85-
}
86-
}
87-
88-
private function checkGraphQLError(array $response): array
89-
{
90-
if (isset($response['errors']) || empty($response['data'])) {
91-
$errorDetails = $response['errors'] ?? ['message' => 'Unknown error', 'code' => -1];
92-
throw new ResponseException('GraphQL query error: ' . json_encode($errorDetails), $errorDetails['code']);
93-
}
94-
95-
return $response;
96-
}
97-
98-
private function getClassName(): string
99-
{
100-
return basename(str_replace('\\', '/', __CLASS__));
101-
}
10230
}

src/Endpoint/PaymentGateway/PaymentGateway.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ private function httpHandler(string $uri, string $body): array
9494
} catch (JsonException $e) {
9595
throw new ResponseException('JSON parsing error: ' . $e->getMessage(), -98, null, ['details' => $e->getMessage()]);
9696
} catch (ResponseException $e) {
97-
throw $e;
98-
} catch (Exception $e) {
99-
throw new ResponseException('Request failed: ' . $e->getMessage(), -99, null, ['details' => $e->getMessage()]);
97+
throw new ResponseException('Response error: ' . $e->getMessage(), $e->getCode(), null, $e->getErrorDetails());
10098
}
10199

102100
return $this->checkPaymentGatewayError($response);

src/Validator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static function validateAuthority(string $authority): void
2626
}
2727
}
2828

29-
public static function validateAmount(int $amount, int $minAmount = 1): void
29+
public static function validateAmount(int $amount, int $minAmount = 1000): void
3030
{
3131
if ($amount < $minAmount) {
3232
throw new InvalidArgumentException("Amount must be at least {$minAmount}.");

src/ZarinPal.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ final class ZarinPal
1515
private Options $options;
1616
private HttpMethodsClientInterface $httpClient;
1717

18+
public const USER_AGENT = 'ZarinPalSdk/v.1.0 (php ' . PHP_VERSION . ')';
19+
1820
public function __construct(Options $options = null)
1921
{
2022
$this->options = $options ?? new Options();
@@ -23,7 +25,7 @@ public function __construct(Options $options = null)
2325
$this->clientBuilder->addPlugin(
2426
new HeaderDefaultsPlugin(
2527
[
26-
'User-Agent' => sprintf('%sSdk/v.0.1 (php %s)', $this->getClassName(), PHP_VERSION),
28+
'User-Agent' => self::USER_AGENT,
2729
'Content-Type' => 'application/json',
2830
'Accept' => 'application/json',
2931
]

0 commit comments

Comments
 (0)