Passed
Push — main ( 2930ba...c89e4d )
by MyFatoorah
09:50
created

MyFatoorah::setVcCode()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 16
rs 9.9666
1
<?php
2
3
namespace MyFatoorah\Library;
4
5
use Exception;
6
7
/**
8
 * MyFatoorah is responsible for handling calling MyFatoorah API endpoints.
9
 * Also, It has necessary library functions that help in providing the correct parameters used endpoints.
10
 *
11
 * MyFatoorah offers a seamless business experience by offering a technology put together by our tech team.
12
 * It enables smooth business operations involving sales activity, product invoicing, shipping, and payment processing.
13
 * MyFatoorah invoicing and payment gateway solution trigger your business to greater success at all levels in the new age world of commerce. Leverage your sales and payments at all e-commerce platforms (ERPs, CRMs, CMSs) with transparent and slick applications that are well-integrated into social media and telecom services. For every closing sale click, you make a business function gets done for you, along with generating factual reports and statistics to fine-tune your business plan with no-barrier low-cost. Our technology experts have designed the best GCC E-commerce solutions for the native financial instruments (Debit Cards, Credit Cards, etc.) supporting online sales and payments, for events, shopping, mall, and associated services.
14
 *
15
 * Created by MyFatoorah http://www.myfatoorah.com/
16
 * Developed By [email protected]
17
 * Date: 31/03/2024
18
 * Time: 12:00
19
 *
20
 * API Documentation on https://myfatoorah.readme.io/docs
21
 * Library Documentation and Download link on https://myfatoorah.readme.io/docs/php-library
22
 *
23
 * @author    MyFatoorah <[email protected]>
24
 * @copyright MyFatoorah, All rights reserved
25
 * @license   GNU General Public License v3.0
26
 */
27
class MyFatoorah extends MyFatoorahHelper
28
{
29
30
    /**
31
     * The configuration used to connect to MyFatoorah test/live API server
32
     *
33
     * @var array
34
     */
35
    protected $config = [];
36
37
    /**
38
     * The URL used to connect to MyFatoorah test/live API server
39
     *
40
     * @var string
41
     */
42
    protected $apiURL = '';
43
44
    /**
45
     * The MyFatoorah PHP Library version
46
     *
47
     * @var string
48
     */
49
    protected $version = '2.2';
50
51
    //-----------------------------------------------------------------------------------------------------------------------------------------
52
53
    /**
54
     * Constructor that initiates a new MyFatoorah API process
55
     *
56
     * @param array $config It has the required keys (apiKey, isTest, and vcCode) to process a MyFatoorah API request.
57
     */
58
    public function __construct($config)
59
    {
60
61
        $mfCountries = self::getMFCountries();
62
63
        $this->setApiKey($config);
64
        $this->setIsTest($config);
65
        $this->setVcCode($config);
66
67
        $this->config['loggerObj']  = empty($config['loggerObj']) ? null : $config['loggerObj'];
68
        $this->config['loggerFunc'] = empty($config['loggerFunc']) ? null : $config['loggerFunc'];
69
70
        //to use logger as static
71
        self::$loggerObj  = $this->config['loggerObj'];
72
        self::$loggerFunc = $this->config['loggerFunc'];
73
74
        $code         = $this->config['vcCode'];
75
        $this->apiURL = $this->config['isTest'] ? $mfCountries[$code]['testv2'] : $mfCountries[$code]['v2'];
76
    }
77
78
    /**
79
     * Get the API URL
80
     * The URL used to connect to MyFatoorah test/live API server
81
     *
82
     * @return string
83
     */
84
    public function getApiURL()
85
    {
86
        return $this->apiURL;
87
    }
88
89
    //-----------------------------------------------------------------------------------------------------------------------------------------
90
91
    /**
92
     * Set the API token Key
93
     * The API Token Key is the authentication which identify a user that is using the app.
94
     * To generate one follow instruction here https://myfatoorah.readme.io/docs/live-token
95
     *
96
     * @param array $config It has the required keys (apiKey, isTest, and vcCode) to process a MyFatoorah API request.
97
     *
98
     * @return void
99
     *
100
     * @throws Exception
101
     */
102
    protected function setApiKey($config)
103
    {
104
        if (empty($config['apiKey'])) {
105
            throw new Exception('Config array must have the "apiKey" key.');
106
        }
107
108
        $config['apiKey'] = trim($config['apiKey']);
109
        if (empty($config['apiKey'])) {
110
            throw new Exception('The "apiKey" key is required and must be a string.');
111
        }
112
113
        $this->config['apiKey'] = $config['apiKey'];
114
    }
115
116
    //-----------------------------------------------------------------------------------------------------------------------------------------
117
118
    /**
119
     * Set the test mode. Set it to false for live mode
120
     *
121
     * @param array $config It has the required keys (apiKey, isTest, and vcCode) to process a MyFatoorah API request.
122
     *
123
     * @return void
124
     *
125
     * @throws Exception
126
     */
127
    protected function setIsTest($config)
128
    {
129
        if (!isset($config['isTest'])) {
130
            throw new Exception('Config array must have the "isTest" key.');
131
        }
132
133
        if (!is_bool($config['isTest'])) {
134
            throw new Exception('The "isTest" key must be boolean.');
135
        }
136
137
        $this->config['isTest'] = $config['isTest'];
138
    }
139
140
    //-----------------------------------------------------------------------------------------------------------------------------------------
141
142
    /**
143
     * Set the vendor country code of the MyFatoorah account
144
     *
145
     * @param array $config It has the required keys (apiKey, isTest, and vcCode) to process a MyFatoorah API request.
146
     *
147
     * @return void
148
     *
149
     * @throws Exception
150
     */
151
    protected function setVcCode($config)
152
    {
153
        $config['vcCode'] = $config['vcCode'] ?? $config['countryCode'] ?? '';
154
        if (empty($config['vcCode'])) {
155
            throw new Exception('Config array must have the "vcCode" key.');
156
        }
157
158
        $mfCountries    = self::getMFCountries();
159
        $countriesCodes = array_keys($mfCountries);
160
161
        $config['vcCode'] = strtoupper($config['vcCode']);
162
        if (!in_array($config['vcCode'], $countriesCodes)) {
163
            throw new Exception('The "vcCode" key must be one of (' . implode(', ', $countriesCodes) . ').');
164
        }
165
166
        $this->config['vcCode'] = $config['vcCode'];
167
    }
168
169
    //-----------------------------------------------------------------------------------------------------------------------------------------
170
171
    /**
172
     * It calls the MyFatoorah API endpoint request and handles the MyFatoorah API endpoint response.
173
     *
174
     * @param string          $url        MyFatoorah API endpoint URL
175
     * @param array|null      $postFields POST request parameters array. It should be set to null if the request is GET.
176
     * @param int|string|null $orderId    The order id or the payment id of the process, used for the events logging.
177
     * @param string|null     $function   The requester function name, used for the events logging. ex:__FUNCTION__.
178
     *
179
     * @return mixed       The response object as the result of a successful calling to the API.
180
     *
181
     * @throws Exception    Throw exception if there is any curl/validation error in the MyFatoorah API endpoint URL.
182
     */
183
    public function callAPI($url, $postFields = null, $orderId = null, $function = null)
184
    {
185
186
        //to prevent json_encode adding lots of decimal digits
187
        ini_set('precision', '14');
188
        ini_set('serialize_precision', '-1');
189
190
        $request = isset($postFields) ? 'POST' : 'GET';
191
        $fields  = empty($postFields) ? json_encode($postFields, JSON_FORCE_OBJECT) : json_encode($postFields);
192
193
        $msgLog = "Order #$orderId ----- $function";
194
        $this->log("$msgLog - Request: $fields");
195
196
        //***************************************
197
        //call url
198
        //***************************************
199
        $curl = curl_init($url);
200
201
        $option = [
202
            CURLOPT_CUSTOMREQUEST  => $request,
203
            CURLOPT_POSTFIELDS     => $fields,
204
            CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $this->config['apiKey'], 'Content-Type: application/json'],
205
            CURLOPT_RETURNTRANSFER => true
206
        ];
207
208
        curl_setopt_array($curl, $option);
209
210
        $res = curl_exec($curl);
211
        $err = curl_error($curl);
212
213
        curl_close($curl);
214
215
        //example set a local ip to host apitest.myfatoorah.com
216
        if ($err) {
217
            $this->log("$msgLog - cURL Error: $err");
218
            throw new Exception($err);
219
        }
220
221
        $this->log("$msgLog - Response: $res");
222
223
        $json = json_decode((string) $res);
224
225
        //***************************************
226
        //check for errors
227
        //***************************************
228
        //Check for the reponse errors
229
        $error = self::getAPIError($json, (string) $res);
230
        if ($error) {
231
            $this->log("$msgLog - Error: $error");
232
            throw new Exception($error);
233
        }
234
235
        //***************************************
236
        //Success
237
        //***************************************
238
        return $json;
239
    }
240
241
    //-----------------------------------------------------------------------------------------------------------------------------------------
242
243
    /**
244
     * Handle Endpoint Errors Function
245
     *
246
     * @param mixed  $json MyFatoorah response JSON object.
247
     * @param string $res  MyFatoorah response string.
248
     *
249
     * @return string
250
     */
251
    protected static function getAPIError($json, $res)
252
    {
253
254
        $isSuccess = $json->IsSuccess ?? false;
255
        if ($isSuccess) {
256
            return '';
257
        }
258
259
        //Check for the HTML errors
260
        $hErr = self::getHtmlErrors($res);
261
        if ($hErr) {
262
            return $hErr;
263
        }
264
265
        //Check for the JSON errors
266
        if (is_string($json)) {
267
            return $json;
268
        }
269
270
        if (empty($json)) {
271
            return (!empty($res) ? $res : 'Kindly review your MyFatoorah admin configuration due to a wrong entry.');
272
        }
273
274
        return self::getJsonErrors($json);
275
    }
276
277
    //-----------------------------------------------------------------------------------------------------------------------------------------
278
279
    /**
280
     * Check for the HTML (response model) errors
281
     *
282
     * @param string $res MyFatoorah response string.
283
     *
284
     * @return string
285
     */
286
    protected static function getHtmlErrors($res)
287
    {
288
        //to avoid blocked IP like:
289
        //<html>
290
        //<head><title>403 Forbidden</title></head>
291
        //<body>
292
        //<center><h1>403 Forbidden</h1></center><hr><center>Microsoft-Azure-Application-Gateway/v2</center>
293
        //</body>
294
        //</html>
295
        //and, skip apple register <YourDomainName> tag error
296
        $stripHtml = strip_tags($res);
297
        if ($res != $stripHtml && stripos($stripHtml, 'apple-developer-merchantid-domain-association') !== false) {
298
            return trim(preg_replace('/\s+/', ' ', $stripHtml));
299
        }
300
        return '';
301
    }
302
303
    //-----------------------------------------------------------------------------------------------------------------------------------------
304
305
    /**
306
     * Check for the json (response model) errors
307
     *
308
     * @param mixed $json MyFatoorah response JSON object.
309
     *
310
     * @return string
311
     */
312
    protected static function getJsonErrors($json)
313
    {
314
315
        $errorsVar = isset($json->ValidationErrors) ? 'ValidationErrors' : 'FieldsErrors';
316
        if (isset($json->$errorsVar)) {
317
            $blogDatas = array_column($json->$errorsVar, 'Error', 'Name');
318
319
            $mapFun = function ($k, $v) {
320
                return "$k: $v";
321
            };
322
            $errArr = array_map($mapFun, array_keys($blogDatas), array_values($blogDatas));
323
324
            return implode(', ', $errArr);
325
            //return implode(', ', array_column($json->ValidationErrors, 'Error'));
326
        }
327
328
        if (isset($json->Data->ErrorMessage)) {
329
            return $json->Data->ErrorMessage;
330
        }
331
332
        //if not, get the message.
333
        //sometimes Error value of ValidationErrors is null, so either get the "Name" key or get the "Message"
334
        //example {
335
        //"IsSuccess":false,
336
        //"Message":"Invalid data",
337
        //"ValidationErrors":[{"Name":"invoiceCreate.InvoiceItems","Error":""}],
338
        //"Data":null
339
        //}
340
        //example {
341
        //"Message":
342
        //"No HTTP resource was found that matches the request URI 'https://apitest.myfatoorah.com/v2/SendPayment222'.",
343
        //"MessageDetail":
344
        //"No route providing a controller name was found to match request URI 
345
        //'https://apitest.myfatoorah.com/v2/SendPayment222'"
346
        //}
347
348
        return empty($json->Message) ? '' : $json->Message;
349
    }
350
351
    //-----------------------------------------------------------------------------------------------------------------------------------------
352
353
    /**
354
     * Log the events
355
     *
356
     * @param string $msg It is the string message that will be written in the log file.
357
     */
358
    public static function log($msg)
359
    {
360
361
        $loggerObj  = self::$loggerObj;
362
        $loggerFunc = self::$loggerFunc;
363
364
        if (empty($loggerObj)) {
365
            return;
366
        }
367
368
        if (is_string($loggerObj)) {
369
            error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - ' . $msg, 3, $loggerObj);
370
        } elseif (method_exists($loggerObj, $loggerFunc)) {
371
            $loggerObj->{$loggerFunc}($msg);
372
        }
373
    }
374
375
    //-----------------------------------------------------------------------------------------------------------------------------------------
376
}
377