GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#6)
by Stefan
02:29
created

Api   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 327
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 93.41%

Importance

Changes 0
Metric Value
dl 0
loc 327
ccs 85
cts 91
cp 0.9341
rs 9.2
c 0
b 0
f 0
wmc 40
lcom 1
cbo 7

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 2
A doRequest() 0 33 3
A parseResponse() 0 4 1
A initTransaction() 0 21 2
A initPaymentPage() 0 21 2
A authorizeTransaction() 0 13 3
A authorizeReferencedTransaction() 0 9 1
A captureTransaction() 0 9 1
A refundTransaction() 0 10 1
A assertPaymentPage() 0 7 1
A insertAlias() 0 10 1
A assertInsertAlias() 0 7 1
A deleteAlias() 0 7 1
A getApiEndpoint() 0 4 2
A getCaptureStrategy() 0 8 3
C addOptionalInterfaceParams() 0 78 15

How to fix   Complexity   

Complex Class

Complex classes like Api often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Api, and based on these observations, apply Extract Interface, too.

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