Completed
Pull Request — master (#6)
by Stefan
02:28
created

Api::parseResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Karser\PayumSaferpay;
4
5
use Http\Message\MessageFactory;
6
use Karser\PayumSaferpay\Exception\SaferpayHttpException;
7
use Payum\Core\Bridge\Spl\ArrayObject;
8
use Payum\Core\Exception\InvalidArgumentException;
9
use Payum\Core\HttpClientInterface;
10
11
class Api
12
{
13
    const SPEC_VERSION = '1.10';
14
    const PAYMENT_PAGE_INIT_PATH = '/Payment/v1/PaymentPage/Initialize';
15
    const PAYMENT_PAGE_ASSERT_PATH = '/Payment/v1/PaymentPage/Assert';
16
    const TRANSACTION_INIT_PATH = '/Payment/v1/Transaction/Initialize';
17
    const TRANSACTION_AUTHORIZE_PATH = '/Payment/v1/Transaction/Authorize';
18
    const TRANSACTION_AUTHORIZE_REFERENCED_PATH = '/Payment/v1/Transaction/AuthorizeReferenced';
19
    const TRANSACTION_CAPTURE_PATH = '/Payment/v1/Transaction/Capture';
20
    const TRANSACTION_REFUND_PATH = '/Payment/v1/Transaction/Refund';
21
    const ALIAS_INSERT_PATH = '/Payment/v1/Alias/Insert';
22
    const ALIAS_ASSERT_INSERT_PATH = '/Payment/v1/Alias/AssertInsert';
23
    const ALIAS_DELETE_PATH = '/Payment/v1/Alias/Delete';
24
25
    /**
26
     * @var HttpClientInterface
27
     */
28
    protected $client;
29
30
    /**
31
     * @var MessageFactory
32
     */
33
    protected $messageFactory;
34
35
    /**
36
     * @var array
37
     */
38
    protected $options = array(
39
        'username' => null,
40
        'password' => null,
41
        'customerId' => null,
42
        'terminalId' => null,
43
        'sandbox' => null,
44
        'interface' => null,
45
        'optionalParameters' => null,
46
    );
47
48
    /**
49
     * @param array               $options
50
     * @param HttpClientInterface $client
51
     * @param MessageFactory      $messageFactory
52 34
     */
53
    public function __construct(array $options, HttpClientInterface $client, MessageFactory $messageFactory)
54 34
    {
55 34
        $options = ArrayObject::ensureArrayObject($options);
56 34
        $options->defaults($this->options);
57 34
        $options->validateNotEmpty([
58
            'username', 'password', 'customerId', 'terminalId',
59 33
        ]);
60
        if (!is_bool($options['sandbox'])) {
61
            throw new InvalidArgumentException('The boolean sandbox option must be set.');
62
        }
63 33
64 33
        $this->options = $options;
0 ignored issues
show
Documentation Bug introduced by
It seems like $options of type object<Payum\Core\Bridge\Spl\ArrayObject> is incompatible with the declared type array of property $options.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
65 33
        $this->client = $client;
66 33
        $this->messageFactory = $messageFactory;
67
    }
68
69
    /**
70
     * @param string $path
71
     * @param array $fields
72
     *
73 30
     * @return array
74
     */
75
    protected function doRequest($path, array $fields)
76 30
    {
77 30
        $headers = [
78 30
            'Authorization' => 'Basic ' . base64_encode($this->options['username'] . ':' . $this->options['password']),
79
            'Accept' => 'application/json',
80 30
            'Content-Type' => 'application/json',
81
        ];
82 30
        $fields = array_merge([
83 30
            'RequestHeader' => [
84 30
                'SpecVersion' => self::SPEC_VERSION,
85 30
                'CustomerId' => $this->options['customerId'],
86
                'RequestId' => uniqid(),
87
                'RetryIndicator' => 0,
88
            ],
89 30
        ], $fields);
90 30
91 30
        $request = $this->messageFactory->createRequest(
92
            'POST',
93 30
            $this->getApiEndpoint() . $path,
94
            $headers,
95
            json_encode($fields)
96 30
        );
97
98 30
        $response = $this->client->send($request);
99 2
100
        if (!($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) {
101
            throw SaferpayHttpException::factory($request, $response);
102 29
        }
103 29
104
        return $this->parseResponse(
105
            $response->getBody()->getContents()
106
        );
107 29
    }
108
109 29
    private function parseResponse($content)
110
    {
111
        return json_decode($content, true);
112 13
    }
113
114
    public function initTransaction(array $model): array
115 13
    {
116 13
        $payload = [
117
            'TerminalId' => $this->options['terminalId'],
118
            'Payment' => $model['Payment'],
119
            'Payer' => $model['Payer'] ?? [
120 13
                'LanguageCode' => 'en',
121
            ],
122 13
            'ReturnUrls' => $model['ReturnUrls'],
123
        ];
124
125
        $payload = $this->addOptionalInterfaceParams(Constants::INTERFACE_TRANSACTION, $payload);
126
127 13
        $paymentMeans = $model['PaymentMeans'] ?? null;
128 3
129
        if (null !== $paymentMeans) {
130 13
            $payload['PaymentMeans'] = $paymentMeans;
131
        }
132
133 6
        return $this->doRequest(self::TRANSACTION_INIT_PATH, $payload);
134
    }
135
136 6
    public function initPaymentPage(array $model): array
137 6
    {
138
        $payload = [
139
            'TerminalId' => $this->options['terminalId'],
140
            'Payment' => $model['Payment'],
141 6
            'Payer' => $model['Payer'] ?? [
142
                'LanguageCode' => 'en',
143 6
            ],
144
            'ReturnUrls' => $model['ReturnUrls'],
145
        ];
146
147
        $payload = $this->addOptionalInterfaceParams(Constants::INTERFACE_PAYMENT_PAGE, $payload);
148 6
149 6
        $notification = $model['Notification'] ?? null;
150
151 6
        if (null !== $notification) {
152
            $payload['Notification'] = $notification;
153
        }
154 9
155
        return $this->doRequest(self::PAYMENT_PAGE_INIT_PATH, $payload);
156
    }
157 9
158
    public function authorizeTransaction(string $token, ?string $condition = null, ?array $alias = null): array
159 9
    {
160 2
        $payload = [
161
            'Token' => $token,
162 9
        ];
163 2
        if (null !== $condition) {
164
            $payload['Condition'] = $condition;
165 9
        }
166
        if (null !== $alias) {
167
            $payload['RegisterAlias'] = array_merge(['IdGenerator' => Constants::ALIAS_ID_GENERATOR_RANDOM], $alias);
168 3
        }
169
        return $this->doRequest(self::TRANSACTION_AUTHORIZE_PATH, $payload);
170
    }
171 3
172 3
    public function authorizeReferencedTransaction(array $payment, string $transactionReferenceId): array
173 3
    {
174
        $payload = [
175 3
            'TerminalId' => $this->options['terminalId'],
176
            'Payment' => $payment,
177
            'TransactionReference' => ['TransactionId' => $transactionReferenceId],
178 12
        ];
179
        return $this->doRequest(self::TRANSACTION_AUTHORIZE_REFERENCED_PATH, $payload);
180
    }
181
182 12
    public function captureTransaction(string $transactionId): array
183
    {
184
        $payload = [
185 12
            'TransactionReference' => [
186
                'TransactionId' => $transactionId,
187
            ],
188 2
        ];
189
        return $this->doRequest(self::TRANSACTION_CAPTURE_PATH, $payload);
190
    }
191 2
192
    public function refundTransaction(array $refund, string $captureId): array
193 2
    {
194
        $payload = [
195
            'Refund' => $refund,
196 2
            'CaptureReference' => [
197
                'CaptureId' => $captureId,
198
            ],
199 4
        ];
200
        return $this->doRequest(self::TRANSACTION_REFUND_PATH, $payload);
201
    }
202 4
203
    public function assertPaymentPage(string $token): array
204 4
    {
205
        $payload = [
206
            'Token' => $token,
207 4
        ];
208
        return $this->doRequest(self::PAYMENT_PAGE_ASSERT_PATH, $payload);
209
    }
210 4
211 4
    public function insertAlias(array $returnUrls, array $alias, string $type): array
212 4
    {
213 4
        $payload = [
214
            'RegisterAlias' => $alias,
215 4
            'Type' => $type ?? Constants::ALIAS_TYPE_CARD,
216
            'ReturnUrls' => $returnUrls,
217
            'LanguageCode' => 'en',
218 4
        ];
219
        return $this->doRequest(self::ALIAS_INSERT_PATH, $payload);
220
    }
221 4
222
    public function assertInsertAlias(string $token): array
223 4
    {
224
        $payload = [
225
            'Token' => $token,
226 2
        ];
227
        return $this->doRequest(self::ALIAS_ASSERT_INSERT_PATH, $payload);
228
    }
229 2
230
    public function deleteAlias(string $id): array
231 2
    {
232
        $payload = [
233
            'AliasId' => $id,
234
        ];
235
        return $this->doRequest(self::ALIAS_DELETE_PATH, $payload);
236
    }
237 32
238
    /**
239 32
     * @return string
240
     */
241
    public function getApiEndpoint()
242
    {
243
        return $this->options['sandbox'] ? 'https://test.saferpay.com/api' : 'https://www.saferpay.com/api';
244
    }
245 11
246
    /**
247 11
     * @return string
248
     */
249
    public function getCaptureStrategy()
250
    {
251 11
        if (isset($this->options['interface']) && is_string($this->options['interface'])) {
252
            return $this->options['interface'];
253
        }
254
255
        return Constants::INTERFACE_TRANSACTION;
256
    }
257
258
    protected function addOptionalInterfaceParams(string $interface, array $payload): array
259
    {
260
        $allowedOptions = [
261
            Constants::INTERFACE_PAYMENT_PAGE => [
262
                'config_set',
263
                'payment_methods',
264
                'wallets',
265
                'notification_merchant_email',
266
                'notification_payer_email',
267
                'styling_css_url',
268
                'styling_content_security_enabled',
269
                'styling_theme',
270
            ],
271
            Constants::INTERFACE_TRANSACTION => [
272
                'config_set',
273
                'payment_methods',
274
                'styling_css_url', // deprecated
275
                'styling_content_security_enabled',
276
                'styling_theme',
277
            ]
278
        ];
279
280
        $optionalInterfaceOptions = $this->options['optionalParameters'] ?? [];
281
282
        foreach ($optionalInterfaceOptions as $optionName => $optionValue) {
283
284
            if (empty($optionValue)) {
285
                continue;
286
            }
287
288
            if (!in_array($optionName, $allowedOptions[$interface])) {
289
                continue;
290
            }
291
292
            switch($optionName) {
293
                case 'config_set':
294
                    $payload['ConfigSet'] = (string) $optionValue;
295
                    break;
296
                case 'payment_methods':
297
                    if (is_string($optionValue) && strpos($optionValue, ',') !== false) {
298
                        $optionValue = explode(',', $optionValue);
299
                    }
300
301
                    $payload['PaymentMethods'] = (array) $optionValue;
302
                    break;
303
                case 'wallets':
304
                    $payload['Wallets'] = explode(',', $optionValue);
305
                    break;
306
                case 'notification_merchant_email':
307
                    $payload['Notification'] = $payload['Notification'] ?? [];
308
                    $payload['Notification']['MerchantEmails'] = explode(',', $optionValue);
309
                    break;
310
                case 'notification_payer_email':
311
                    $payload['Notification'] = $payload['Notification'] ?? [];
312
                    $payload['Notification']['PayerEmail'] = (string) $optionValue;
313
                    break;
314
                case 'styling_css_url':
315
                    $payload['Styling'] = $payload['Styling'] ?? [];
316
                    $payload['Styling']['CssUrl'] = $optionValue;
317
                    break;
318
                case 'styling_content_security_enabled':
319
                    $payload['Styling'] = $payload['Styling'] ?? [];
320
                    $payload['Styling']['ContentSecurityEnabled'] = $optionValue;
321
                    break;
322
                case 'styling_theme':
323
                    $payload['Styling'] = $payload['Styling'] ?? [];
324
                    $payload['Styling']['Theme'] = $optionValue;
325
                    break;
326
            }
327
        }
328
329
        return $payload;
330
    }
331
}
332