Payment   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 368
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 87
c 2
b 0
f 0
dl 0
loc 368
rs 9.76
wmc 33

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getDefaultConfigPath() 0 3 1
A __construct() 0 5 2
A purchase() 0 22 3
A amount() 0 5 1
A resetCallbackUrl() 0 5 1
A config() 0 13 3
A callbackUrl() 0 5 1
A invoice() 0 5 1
A getDriverInstance() 0 7 2
A validateInvoice() 0 4 2
A verify() 0 19 2
A transactionId() 0 5 1
A detail() 0 5 1
A pay() 0 18 2
A loadDefaultConfig() 0 3 1
A getFreshDriverInstance() 0 10 2
A via() 0 8 1
A validateDriver() 0 18 6
1
<?php
2
3
namespace Shetabit\Multipay;
4
5
use Shetabit\Multipay\Contracts\DriverInterface;
6
use Shetabit\Multipay\Contracts\ReceiptInterface;
7
use Shetabit\Multipay\Exceptions\DriverNotFoundException;
8
use Shetabit\Multipay\Exceptions\TimeoutException;
9
use Shetabit\Multipay\Exceptions\InvoiceNotFoundException;
10
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
11
use Shetabit\Multipay\Traits\HasPaymentEvents;
12
use Shetabit\Multipay\Traits\InteractsWithRedirectionForm;
13
14
class Payment
15
{
16
    use InteractsWithRedirectionForm;
17
    use HasPaymentEvents;
18
19
    /**
20
     * Payment Configuration.
21
     *
22
     * @var array
23
     */
24
    protected $config;
25
26
    /**
27
     * Payment Driver Settings.
28
     *
29
     * @var array
30
     */
31
    protected $settings;
32
33
    /**
34
     * callbackUrl
35
     *
36
     * @var string
37
     */
38
    protected $callbackUrl;
39
40
    /**
41
     * Payment Driver Name.
42
     *
43
     * @var string
44
     */
45
    protected $driver;
46
47
    /**
48
     * Payment Driver Instance.
49
     *
50
     * @var object
51
     */
52
    protected $driverInstance;
53
54
    /**
55
     * @var Invoice
56
     */
57
    protected $invoice;
58
59
    /**
60
     * PaymentManager constructor.
61
     *
62
     * @param array $config
63
     *
64
     * @throws \Exception
65
     */
66
    public function __construct(array $config = [])
67
    {
68
        $this->config = empty($config) ? $this->loadDefaultConfig() : $config;
69
        $this->invoice(new Invoice());
70
        $this->via($this->config['default']);
71
    }
72
73
    /**
74
     * Retrieve Default config's path.
75
     *
76
     * @return string
77
     */
78
    public static function getDefaultConfigPath() : string
79
    {
80
        return dirname(__DIR__).'/config/payment.php';
81
    }
82
83
    /**
84
     * Set custom configs
85
     * we can use this method when we want to use dynamic configs
86
     *
87
     * @param $key
88
     * @param $value|null
89
     *
90
     * @return $this
91
     */
92
    public function config($key, $value = null)
93
    {
94
        $configs = [];
95
96
        $key = is_array($key) ? $key : [$key => $value];
97
98
        foreach ($key as $k => $v) {
99
            $configs[$k] = $v;
100
        }
101
102
        $this->settings = array_merge($this->settings, $configs);
103
104
        return $this;
105
    }
106
107
    /**
108
     * Set callbackUrl.
109
     *
110
     * @param $url|null
111
     * @return $this
112
     */
113
    public function callbackUrl($url = null)
114
    {
115
        $this->config('callbackUrl', $url);
116
117
        return $this;
118
    }
119
120
    /**
121
     * Reset the callbackUrl to its original that exists in configs.
122
     *
123
     * @return $this
124
     */
125
    public function resetCallbackUrl()
126
    {
127
        $this->callbackUrl();
128
129
        return $this;
130
    }
131
132
    /**
133
     * Set payment amount.
134
     *
135
     * @param $amount
136
     * @return $this
137
     * @throws \Exception
138
     */
139
    public function amount($amount)
140
    {
141
        $this->invoice->amount($amount);
142
143
        return $this;
144
    }
145
146
    /**
147
     * Set a piece of data to the details.
148
     *
149
     * @param $key
150
     *
151
     * @param $value|null
152
     *
153
     * @return $this
154
     */
155
    public function detail($key, $value = null)
156
    {
157
        $this->invoice->detail($key, $value);
158
159
        return $this;
160
    }
161
162
    /**
163
     * Set transaction's id
164
     *
165
     * @param $id
166
     *
167
     * @return $this
168
     */
169
    public function transactionId($id)
170
    {
171
        $this->invoice->transactionId($id);
172
173
        return $this;
174
    }
175
176
    /**
177
     * Change the driver on the fly.
178
     *
179
     * @param $driver
180
     *
181
     * @return $this
182
     *
183
     * @throws \Exception
184
     */
185
    public function via($driver)
186
    {
187
        $this->driver = $driver;
188
        $this->validateDriver();
189
        $this->invoice->via($driver);
190
        $this->settings = array_merge($this->loadDefaultConfig()['drivers'][$driver] ?? [], $this->config['drivers'][$driver]);
191
192
        return $this;
193
    }
194
195
    /**
196
     * Purchase the invoice
197
     *
198
     * @param Invoice $invoice|null
199
     * @param $finalizeCallback|null
200
     *
201
     * @return $this
202
     *
203
     * @throws \Exception
204
     */
205
    public function purchase(Invoice $invoice = null, $finalizeCallback = null)
206
    {
207
        if ($invoice) { // create new invoice
208
            $this->invoice($invoice);
209
        }
210
211
        $this->driverInstance = $this->getFreshDriverInstance();
212
213
        //purchase the invoice
214
        $transactionId = $this->driverInstance->purchase();
215
        if ($finalizeCallback) {
216
            call_user_func_array($finalizeCallback, [$this->driverInstance, $transactionId]);
217
        }
218
219
        // dispatch event
220
        $this->dispatchEvent(
221
            'purchase',
222
            $this->driverInstance,
223
            $this->driverInstance->getInvoice()
224
        );
225
226
        return $this;
227
    }
228
229
    /**
230
     * Pay the purchased invoice.
231
     *
232
     * @param $initializeCallback|null
233
     *
234
     * @return mixed
235
     *
236
     * @throws \Exception
237
     */
238
    public function pay($initializeCallback = null)
239
    {
240
        $this->driverInstance = $this->getDriverInstance();
241
242
        if ($initializeCallback) {
243
            call_user_func($initializeCallback, $this->driverInstance);
244
        }
245
246
        $this->validateInvoice();
247
248
        // dispatch event
249
        $this->dispatchEvent(
250
            'pay',
251
            $this->driverInstance,
252
            $this->driverInstance->getInvoice()
253
        );
254
255
        return $this->driverInstance->pay();
256
    }
257
258
    /**
259
     * Verifies the payment
260
     *
261
     * @param $finalizeCallback|null
262
     *
263
     * @return ReceiptInterface
264
     *
265
     * @throws InvoiceNotFoundException
266
     * @throws PurchaseFailedException
267
     * @throws TimeoutException
268
     */
269
    public function verify($finalizeCallback = null) : ReceiptInterface
270
    {
271
        $this->driverInstance = $this->getDriverInstance();
272
        $this->validateInvoice();
273
        $receipt = $this->driverInstance->verify();
274
275
        if (!empty($finalizeCallback)) {
276
            call_user_func($finalizeCallback, $receipt, $this->driverInstance);
277
        }
278
279
        // dispatch event
280
        $this->dispatchEvent(
281
            'verify',
282
            $receipt,
283
            $this->driverInstance,
284
            $this->driverInstance->getInvoice()
285
        );
286
287
        return $receipt;
288
    }
289
290
    /**
291
     * Retrieve default config.
292
     *
293
     * @return array
294
     */
295
    protected function loadDefaultConfig() : array
296
    {
297
        return require(static::getDefaultConfigPath());
298
    }
299
300
    /**
301
     * Set invoice instance.
302
     *
303
     * @param Invoice $invoice
304
     *
305
     * @return self
306
     */
307
    protected function invoice(Invoice $invoice)
308
    {
309
        $this->invoice = $invoice;
310
311
        return $this;
312
    }
313
314
    /**
315
     * Retrieve current driver instance or generate new one.
316
     *
317
     * @return mixed
318
     * @throws \Exception
319
     */
320
    protected function getDriverInstance()
321
    {
322
        if (!empty($this->driverInstance)) {
323
            return $this->driverInstance;
324
        }
325
326
        return $this->getFreshDriverInstance();
327
    }
328
329
    /**
330
     * Get new driver instance
331
     *
332
     * @return mixed
333
     * @throws \Exception
334
     */
335
    protected function getFreshDriverInstance()
336
    {
337
        $this->validateDriver();
338
        $class = $this->config['map'][$this->driver];
339
340
        if (!empty($this->callbackUrl)) { // use custom callbackUrl if exists
341
            $this->settings['callbackUrl'] = $this->callbackUrl;
342
        }
343
344
        return new $class($this->invoice, $this->settings);
345
    }
346
347
    /**
348
     * Validate Invoice.
349
     *
350
     * @throws InvoiceNotFoundException
351
     */
352
    protected function validateInvoice()
353
    {
354
        if (empty($this->invoice)) {
355
            throw new InvoiceNotFoundException('Invoice not selected or does not exist.');
356
        }
357
    }
358
359
    /**
360
     * Validate driver.
361
     *
362
     * @throws \Exception
363
     */
364
    protected function validateDriver()
365
    {
366
        if (empty($this->driver)) {
367
            throw new DriverNotFoundException('Driver not selected or default driver does not exist.');
368
        }
369
370
        if (empty($this->config['drivers'][$this->driver]) || empty($this->config['map'][$this->driver])) {
371
            throw new DriverNotFoundException('Driver not found in config file. Try updating the package.');
372
        }
373
374
        if (!class_exists($this->config['map'][$this->driver])) {
375
            throw new DriverNotFoundException('Driver source not found. Please update the package.');
376
        }
377
378
        $reflect = new \ReflectionClass($this->config['map'][$this->driver]);
379
380
        if (!$reflect->implementsInterface(DriverInterface::class)) {
381
            throw new \Exception("Driver must be an instance of Contracts\DriverInterface.");
382
        }
383
    }
384
}
385