1 | <?php |
||
2 | |||
3 | namespace Sebdesign\VivaPayments; |
||
4 | |||
5 | use GuzzleHttp\Client as GuzzleClient; |
||
6 | use GuzzleHttp\Psr7\Uri; |
||
7 | use GuzzleHttp\RequestOptions; |
||
8 | use Psr\Http\Message\ResponseInterface; |
||
9 | use Psr\Http\Message\UriInterface; |
||
10 | use Sebdesign\VivaPayments\Enums\Environment; |
||
11 | |||
12 | class Client |
||
13 | { |
||
14 | /** |
||
15 | * Demo environment URL. |
||
16 | */ |
||
17 | public const DEMO_URL = 'https://demo.vivapayments.com'; |
||
18 | |||
19 | /** |
||
20 | * Production environment URL. |
||
21 | */ |
||
22 | public const PRODUCTION_URL = 'https://www.vivapayments.com'; |
||
23 | |||
24 | /** |
||
25 | * Demo environment accounts URL. |
||
26 | */ |
||
27 | public const DEMO_ACCOUNTS_URL = 'https://demo-accounts.vivapayments.com'; |
||
28 | |||
29 | /** |
||
30 | * Production environment accounts URL. |
||
31 | */ |
||
32 | public const PRODUCTION_ACCOUNTS_URL = 'https://accounts.vivapayments.com'; |
||
33 | |||
34 | /** |
||
35 | * Demo environment URL. |
||
36 | */ |
||
37 | public const DEMO_API_URL = 'https://demo-api.vivapayments.com'; |
||
38 | |||
39 | /** |
||
40 | * Production environment URL. |
||
41 | */ |
||
42 | public const PRODUCTION_API_URL = 'https://api.vivapayments.com'; |
||
43 | |||
44 | protected string $token; |
||
45 | |||
46 | 20 | public function __construct( |
|
47 | public readonly GuzzleClient $client, |
||
48 | protected Environment $environment, |
||
49 | protected string $merchantId, |
||
50 | protected string $apiKey, |
||
51 | protected string $clientId, |
||
52 | protected string $clientSecret, |
||
53 | ) { |
||
54 | } |
||
55 | |||
56 | /** |
||
57 | * Request OAuth access tokens. |
||
58 | */ |
||
59 | 6 | public function oauth(): OAuth |
|
60 | { |
||
61 | 6 | return new OAuth($this, $this->clientId, $this->clientSecret); |
|
62 | } |
||
63 | |||
64 | /** |
||
65 | * Create card tokens. |
||
66 | */ |
||
67 | 3 | public function cards(): Card |
|
68 | { |
||
69 | 3 | return new Card($this); |
|
70 | } |
||
71 | |||
72 | /** |
||
73 | * Create payment orders. |
||
74 | */ |
||
75 | 3 | public function orders(): Order |
|
76 | { |
||
77 | 3 | return new Order($this); |
|
78 | } |
||
79 | |||
80 | /** |
||
81 | * Retrieve and create recurring transactions. |
||
82 | */ |
||
83 | 3 | public function transactions(): Transaction |
|
84 | { |
||
85 | 3 | return new Transaction($this); |
|
86 | } |
||
87 | |||
88 | /** |
||
89 | * Verity webhooks. |
||
90 | */ |
||
91 | 3 | public function webhooks(): Webhook |
|
92 | { |
||
93 | 3 | return new Webhook($this); |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * Make a GET request. |
||
98 | * |
||
99 | * @param array<string,mixed> $options |
||
100 | * @return array<mixed> |
||
101 | */ |
||
102 | 12 | public function get(string $url, array $options = []): array |
|
103 | { |
||
104 | 12 | $response = $this->client->get($url, $options); |
|
105 | |||
106 | 12 | return $this->getBody($response); |
|
107 | } |
||
108 | |||
109 | /** |
||
110 | * Make a POST request. |
||
111 | * |
||
112 | * @param array<string,mixed> $options |
||
113 | * @return array<mixed> |
||
114 | */ |
||
115 | 6 | public function post(string $url, array $options = []): array |
|
116 | { |
||
117 | 6 | $response = $this->client->post($url, $options); |
|
118 | |||
119 | 6 | return $this->getBody($response); |
|
120 | } |
||
121 | |||
122 | /** |
||
123 | * Get the response body. |
||
124 | * |
||
125 | * @return array<mixed> |
||
126 | * |
||
127 | * @throws \Sebdesign\VivaPayments\VivaException |
||
128 | */ |
||
129 | 18 | protected function getBody(ResponseInterface $response): array |
|
130 | { |
||
131 | 18 | $body = (string) $response->getBody(); |
|
132 | |||
133 | 18 | $decoded = json_decode( |
|
134 | json: $body, |
||
135 | associative: true, |
||
136 | depth: 512, |
||
137 | 18 | flags: JSON_BIGINT_AS_STRING | JSON_THROW_ON_ERROR, |
|
138 | ); |
||
139 | |||
140 | 18 | if (! is_array($decoded)) { |
|
141 | 3 | throw new VivaException('Invalid response', 0); |
|
142 | } |
||
143 | |||
144 | 15 | if (isset($decoded['ErrorCode']) && $decoded['ErrorCode'] !== 0) { |
|
145 | 3 | throw new VivaException($decoded['ErrorText'], $decoded['ErrorCode']); |
|
146 | } |
||
147 | |||
148 | 12 | return $decoded; |
|
149 | } |
||
150 | |||
151 | /** |
||
152 | * Get the URL. |
||
153 | */ |
||
154 | 6 | public function getUrl(): UriInterface |
|
155 | { |
||
156 | 6 | return new Uri(match ($this->environment) { |
|
157 | 2 | Environment::Production => self::PRODUCTION_URL, |
|
158 | 2 | Environment::Demo => self::DEMO_URL, |
|
159 | }); |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * Get the accounts URL. |
||
164 | */ |
||
165 | 9 | public function getAccountsUrl(): UriInterface |
|
166 | { |
||
167 | 9 | return new Uri(match ($this->environment) { |
|
168 | 3 | Environment::Production => self::PRODUCTION_ACCOUNTS_URL, |
|
169 | 3 | Environment::Demo => self::DEMO_ACCOUNTS_URL, |
|
170 | }); |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Get the API URL. |
||
175 | */ |
||
176 | 6 | public function getApiUrl(): UriInterface |
|
177 | { |
||
178 | 6 | return new Uri(match ($this->environment) { |
|
179 | 2 | Environment::Production => self::PRODUCTION_API_URL, |
|
180 | 2 | Environment::Demo => self::DEMO_API_URL, |
|
181 | }); |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Authenticate using basic auth. |
||
186 | * |
||
187 | * @return array{auth:array{string,string}} |
||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||
188 | */ |
||
189 | 6 | public function authenticateWithBasicAuth(): array |
|
190 | { |
||
191 | return [ |
||
192 | 6 | RequestOptions::AUTH => [$this->merchantId, $this->apiKey], |
|
193 | ]; |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Authenticate using the bearer token as an authorization header. |
||
198 | * |
||
199 | * @return array{headers:array{Authorization:string}}; |
||
200 | */ |
||
201 | 3 | public function authenticateWithBearerToken(): array |
|
202 | { |
||
203 | 3 | $token = $this->token ??= $this->oauth()->requestToken()->access_token; |
|
204 | |||
205 | return [ |
||
206 | 1 | RequestOptions::HEADERS => [ |
|
207 | 3 | 'Authorization' => "Bearer {$token}", |
|
208 | ], |
||
209 | ]; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Use the production or demo environment. |
||
214 | */ |
||
215 | 18 | public function withEnvironment(Environment|string $environment): self |
|
216 | { |
||
217 | 18 | $this->environment = is_string($environment) ? Environment::from($environment) : $environment; |
|
218 | |||
219 | 18 | return $this; |
|
220 | } |
||
221 | |||
222 | /** |
||
223 | * Use the given Merchant ID and API key for basic authentication. |
||
224 | * |
||
225 | * @see https://developer.vivawallet.com/getting-started/find-your-account-credentials/merchant-id-and-api-key/ |
||
226 | */ |
||
227 | 3 | public function withBasicAuthCredentials( |
|
228 | #[\SensitiveParameter] string $merchantId, |
||
229 | #[\SensitiveParameter] string $apiKey, |
||
230 | ): self { |
||
231 | 3 | $this->merchantId = $merchantId; |
|
232 | 3 | $this->apiKey = $apiKey; |
|
233 | |||
234 | 3 | return $this; |
|
235 | } |
||
236 | |||
237 | /** |
||
238 | * Use the given client credentials to authenticate with OAuth 2.0. |
||
239 | * |
||
240 | * @see https://developer.vivawallet.com/getting-started/find-your-account-credentials/client-smart-checkout-credentials/ |
||
241 | */ |
||
242 | 3 | public function withOAuthCredentials( |
|
243 | #[\SensitiveParameter] string $clientId, |
||
244 | #[\SensitiveParameter] string $clientSecret, |
||
245 | ): self { |
||
246 | 3 | $this->clientId = $clientId; |
|
247 | 3 | $this->clientSecret = $clientSecret; |
|
248 | |||
249 | 3 | return $this; |
|
250 | } |
||
251 | |||
252 | /** |
||
253 | * Use the given access token to authenticate with OAuth 2.0. |
||
254 | */ |
||
255 | 3 | public function withToken(#[\SensitiveParameter] string $token): self |
|
256 | { |
||
257 | 3 | $this->token = $token; |
|
258 | |||
259 | 3 | return $this; |
|
260 | } |
||
261 | } |
||
262 |