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

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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