├── .gitignore
├── .idea
├── composerJson.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
├── modules.xml
├── paystack-mirror.iml
├── php.xml
├── symfony2.xml
├── vcs.xml
└── workspace.xml
├── LICENSE
├── README.md
├── composer.json
├── composer.lock
├── docs
├── logo.png
└── pages
│ ├── bulk-charges.md
│ └── charges.md
├── phpunit.xml
└── src
├── Actions
├── Action.php
├── BulkCharges
│ ├── FetchBulkChargeBatch.php
│ ├── FetchChargesBatch.php
│ ├── InitializeBulkCharge.php
│ ├── ListBulkChargeBatches.php
│ ├── PauseBulkChargeBatch.php
│ └── ResumeBulkChargeBatch.php
├── Charges
│ ├── CheckPendingCharge.php
│ ├── InitializeCharge.php
│ ├── SubmitBirthdayToCharge.php
│ ├── SubmitOtpToCharge.php
│ ├── SubmitPhoneToCharge.php
│ ├── SubmitPinToCharge.php
│ └── TokenizePaymentInstrument.php
├── ControlPanel
│ ├── FetchPaymentSessionTimeout.php
│ └── UpdatePaymentSessionTimeout.php
├── Customers
│ ├── CreateCustomer.php
│ ├── DeactivateCustomerAuthorization.php
│ ├── FetchCustomer.php
│ ├── ListCustomers.php
│ ├── UpdateCustomer.php
│ └── WhiteOrBlackListCustomer.php
├── Invoices
│ ├── ArchiveInvoice.php
│ ├── CreateInvoice.php
│ ├── FinalizeInvoiceDraft.php
│ ├── InvoiceTotals.php
│ ├── ListInvoices.php
│ ├── MarkAsPaidInvoice.php
│ ├── SendInvoiceNotification.php
│ ├── UpdateInvoice.php
│ ├── VerifyInvoice.php
│ └── ViewInvoice.php
├── Miscellaneous
│ ├── CheckBalance.php
│ └── ListBanks.php
├── Pages
│ ├── CheckAvailablePageSlug.php
│ ├── CreatePage.php
│ ├── FetchPage.php
│ ├── ListPages.php
│ └── UpdatePage.php
├── Plans
│ ├── CreatePlan.php
│ ├── FetchPlan.php
│ ├── ListPlans.php
│ └── UpdatePlan.php
├── Refunds
│ ├── CreateRefund.php
│ ├── FetchRefund.php
│ └── ListRefunds.php
├── Settlements
│ └── FetchSettlements.php
├── SubAccounts
│ ├── CreateSubAccount.php
│ ├── FetchSubAccount.php
│ ├── ListSubAccounts.php
│ └── UpdateSubAccount.php
├── Subscriptions
│ ├── CreateSubscription.php
│ ├── DisableSubscription.php
│ ├── EnableSubscription.php
│ ├── FetchSubscription.php
│ └── ListSubscriptions.php
├── Transactions
│ ├── ChargeAuthorization.php
│ ├── CheckAuthorization.php
│ ├── DeactivateAuthorization.php
│ ├── ExportTransactions.php
│ ├── FetchTransaction.php
│ ├── InitializeTransaction.php
│ ├── ListTransactions.php
│ ├── TransactionTotals.php
│ ├── VerifyTransaction.php
│ └── ViewTransactionTimeline.php
├── TransferRecipients
│ ├── CreateTransferRecipient.php
│ ├── DeleteTransferRecipient.php
│ ├── ListTransferRecipients.php
│ └── UpdateTransferRecipient.php
├── Transfers
│ ├── FetchTransfer.php
│ ├── FinalizeTransfer.php
│ ├── InitializeTransfer.php
│ └── InitiateBulkTransfer.php
├── TransfersControl
│ ├── DisableTransferOtp.php
│ ├── EnableTransferOtp.php
│ ├── FinalizeDisableTransferOtp.php
│ └── ResendTransferOtp.php
└── Verifications
│ ├── ResolveAccountNumber.php
│ ├── ResolveBvn.php
│ ├── ResolveCardBin.php
│ └── ResolvePhoneNumber.php
├── Events
├── ActionEvent.php
├── Event.php
├── EventInterface.php
└── SubscriptionCreated.php
├── Exceptions
└── PaystackMirrorException.php
├── PaystackMirror.php
├── Services
├── CurlCacheService.php
├── CurlHttpResponseService.php
├── CurlService.php
├── ParamsBuilder.php
└── RequestHandlerService.php
├── Traits
├── HasBulkChargeBatchIdOrCode.php
├── HasBvn.php
├── HasCardBin.php
├── HasIdOrCustomerCode.php
├── HasIdOrPlanCode.php
├── HasIdOrReference.php
├── HasIdOrSlug.php
├── HasIdOrSubscriptionCode.php
├── HasInvoiceIdOrCode.php
└── HasRecipientCodeOrId.php
└── helpers.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 |
--------------------------------------------------------------------------------
/.idea/composerJson.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/paystack-mirror.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/.idea/php.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/.idea/symfony2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | $PROJECT_DIR$/composer.json
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | $data
35 | ActionContract
36 | $param
37 |
38 |
39 | $param
40 | Action
41 | $pqueryParams
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 | 1554981895595
226 |
227 |
228 | 1554981895595
229 |
230 |
231 |
232 |
233 |
234 | 1555417727577
235 |
236 |
237 |
238 | 1555417727577
239 |
240 |
241 | 1555418131139
242 |
243 |
244 |
245 | 1555418131139
246 |
247 |
248 | 1555418204903
249 |
250 |
251 |
252 | 1555418204903
253 |
254 |
255 | 1555418291339
256 |
257 |
258 |
259 | 1555418291339
260 |
261 |
262 | 1555418391463
263 |
264 |
265 |
266 | 1555418391463
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | The missing Paystack PHP Library.
4 | ___
5 | ## Overview
6 | Paystack Mirror is a clean, simple and fluent php library for paystack payment gateway. This library is birthed out of the fact that I needed something flexible than what is in existance for myself and the php community.
7 |
8 | ### What was wrong with the existing one?
9 | The official paystack library for php is the yabacon/paystack-php on github. It's cool. Supports almost all paystack end-points and some other cool features like a dedicated Fee class, MetaDataBuilder class and Event handler class. Many people have been using the library but I wanted something that can give people freedom over what they do. I wanted something that supports multiple accounts at once. It's why I decided to work on this library.
10 |
11 | ### What is unique about the library?
12 | 1. The conversion of paystack end-points to full fledged extendable php classes.
13 | 2. Supports for multiple accounts
14 | 3. Clean and better event handler class
15 | 4. Fluent Params Builder class
16 | 5. Nigerian money conversion e.g 1k => 1,000 naira and 1,000 naira => 100000 kobo and even (millions(xM), billions(xB), trillions(xT)) to kobo e.t.c.
17 |
18 | ## Server Requirements
19 | > PHP version ^7.1.3 requirement was done intentionally. Reason been that it's safer, better and faster than 5.6 and 7.0. So, if you have been using php version less than that, kindly upgrade before using this library.
20 | * php ^7.1.3
21 | * cURL extension enabled
22 | * OpenSSL extension enabled
23 |
24 | > This library has suppports for all Paystack end-points which we refer to as **Actions**. _Let's take a look at the available actions._
25 |
26 | ## List of actions groups
27 | Below are actions groups supported by the library in alphabetical order.
28 |
29 | 1. [BULK CHARGES](docs/pages/bulk-charges.md)
30 | 2. [CHARGES](docs/pages/charges.md)
31 | 3. CONTROL PANEL
32 | 4. CUSTOMERS
33 | 5. INVOICES
34 | 6. MISCELLANEOUS
35 | 7. PAGES
36 | 8. PLANS
37 | 9. REFUNDS
38 | 10. SETTLEMENTS
39 | 11. SUB-ACCOUNTS
40 | 12. SUBSCRIPTIONS
41 | 13. TRANSACTIONS
42 | 14. TRANSFER RECIPIENTS
43 | 15. TRANSFERS
44 | 16. TRANSFERS CONTROL
45 | 17. VERIFICATIONS
46 |
47 | >**Note:** To see the list of all actions under each action groups available on this library, kindly [Click Here](https://github.com/coderatio/paystack-mirror/tree/master/src/Actions).
48 |
49 | > Arrangements are on the way to list all of them like the first two above.
50 |
51 | ## Installation
52 | ```
53 | composer require coderatio/paystack-mirror
54 | ```
55 |
56 | ## Usage
57 | ### With Single Paystack Account
58 |
59 | _Method One_
60 | ```php
61 |
62 | require 'venodr/autoload.php';
63 |
64 | use Coderatio\PaystackMirror\PaystackMirror;
65 | use Coderatio\PaystackMirror\Actions\Transactions\ListTransactions;
66 |
67 | $queryParams = new ParamsBuilder();
68 | $queryParams->perPage = 10;
69 |
70 | $result = PaystackMirror::run($secretKey, new ListTransactions($queryParams));
71 |
72 | echo $result->getResponse();
73 |
74 | ```
75 |
76 | _Method Two_
77 | ```php
78 |
79 | require 'venodr/autoload.php';
80 |
81 | use Coderatio\PaystackMirror\PaystackMirror;
82 | use Coderatio\PaystackMirror\Actions\Transactions\ListTransactions;
83 |
84 | $queryParams = new ParamsBuilder();
85 | $queryParams->perPage = 10;
86 |
87 | $result = PaystackMirror::run($secretKey, ListTransactions::class, $queryParams);
88 |
89 | echo $result->getResponse();
90 |
91 | ```
92 |
93 | _Method Three_
94 | ```php
95 |
96 | require 'venodr/autoload.php';
97 |
98 | use Coderatio\PaystackMirror\PaystackMirror;
99 | use Coderatio\PaystackMirror\Actions\Transactions\ListTransactions;
100 |
101 | $queryParams = new ParamsBuilder();
102 | $queryParams->perPage = 10;
103 |
104 | $result = PaystackMirror::setKey($secretKey)->mirror(new ListTransactions($queryParams));
105 |
106 | echo $result->getResponse();
107 |
108 | ```
109 |
110 | _Method Four_
111 | ```php
112 |
113 | require 'venodr/autoload.php';
114 |
115 | use Coderatio\PaystackMirror\PaystackMirror;
116 | use Coderatio\PaystackMirror\Actions\Transactions\ListTransactions;
117 |
118 | $queryParams = new ParamsBuilder();
119 | $queryParams->perPage = 10;
120 |
121 | $result = PaystackMirror::setKey($secretKey)->mirror(ListTransactions::class, $queryParams);
122 |
123 | echo $result->getResponse();
124 |
125 | ```
126 | >**Notice:** By default, `->getResponse()` returns a json object. But, you can chain `->asArray()` to convert the response to php `array` or `->asObject()` to conver the response to php `object` at runtime.
127 |
128 | ### With Multiple Paystack Accounts
129 | With this library, you can mirror single action on multiple paystack accounts. This is super cool for multitenants applications or firms with multiple paystack accounts.
130 |
131 | Let's see how to do it.
132 | ```php
133 |
134 | // Let's use ParamsBuilder to build our data to be sent to paystack.
135 |
136 | // First account
137 | $firstAccountParams = new ParamsBuilder();
138 | $firstAccountParams->first_name = 'Josiah';
139 | $firstAccountParams->last_name = 'Yahaya';
140 | $firstAccountParams->email = 'example1@email.com';
141 | $firstAccountParams->amount = short_naira_to_kobo('25.5k');
142 | $firstAccountParams->reference = PaystackMirror::generateReference();
143 |
144 | $firstAccount = new ParamsBuilder();
145 | $firstAccount->key = $firstAccountKey;
146 | $firstAccount->data = $firstAccountParams;
147 |
148 | // Second account
149 | $secondAccountParams = new ParamsBuilder();
150 | $secondAccountParams->first_name = 'Ovye';
151 | $secondAccountParams->last_name = 'Yahaya';
152 | $secondAccountParams->email = 'example2@email.com';
153 | $secondAccountParams->amount = short_naira_to_kobo('10k');
154 | $secondAccountParams->reference = PaystackMirror::generateReference();
155 |
156 | $secondAccount = new ParamsBuilder();
157 | $secondAccount->key = $secondAccountKey;
158 | $secondAccount->data = $firstAccountParams;
159 |
160 | $results = PaystackMirror::setAccounts([$firstAccount, $secondAccount])
161 | ->mirrorMultipleAccountsOn(new InitializeTransaction());
162 |
163 | // OR
164 |
165 | $results = PaystackMirror::setAccounts([$firstAccount, $secondAccount])
166 | ->mirrorMultipleAccountsOn(InitializeTransaction::class);
167 |
168 | foreach ($results as $result) {
169 | // Do something with $result.
170 |
171 | ...
172 |
173 | // The $result variable holds two main object properties;
174 | // $result->account which holds an account key and $result->response which holds the response for an account.
175 | // The best thing to do is to dump the $result variable to see what's contain there in.
176 | }
177 | ```
178 |
179 | You can overwrite all the accounts data by providing your params on the action. When that is done, the library will use the parameters supplied on the action for all the accounts instead e.g
180 | ```php
181 |
182 | $actionParams = new ParamsBuilder();
183 | $actionParams->email = 'johndoe@email.com';
184 | $actionParams->amount = naira_to_kobo('1,000');
185 | $actionParams->reference = PaystackMirror::generateReference();
186 |
187 | $results = PaystackMirror::setAccounts([$firstAccount, $secondAccount])
188 | ->mirrorMultipleAccountsOn(new InitializeTransaction($actionParams));
189 |
190 | // OR
191 |
192 | $results = PaystackMirror::setAccounts([$firstAccount, $secondAccount])
193 | ->mirrorMultipleAccountsOn(InitializeTransaction::class, $actionParams);
194 |
195 | ```
196 | >**Quick Note:** All the query or body params used on paystack api documentation site are all available in this library. The only different is, they must be sent as an array or as `ParamBuilder::class` object.
197 |
198 | ## Create your action
199 | One good thing about this library is the ability to plug and play actions. You can replace existing actions by creating yours.
200 |
201 | ```php
202 | post($this->url, $this->getData());
218 | }
219 | }
220 |
221 | ```
222 |
223 | >Please note that `$this->data` property returns an array. If you want to send parameters as json to paystack, use `$this->getData()`.
224 |
225 | ## Webhook Event Handling
226 | This library ships with a fluent Event handling class to be used at your webhook url set on your paystack dashboard. See example below on how to listen to different events.
227 |
228 | ```php
229 | 'sk_testxxxxxxxxxxxxx',
236 | 'live' => 'sk_live_xxxxxxxxxxxxxx'
237 | ];
238 |
239 | $eventData = Event::capture()->thenValidate(string $secretKey or array $secretKeys)
240 | ->thenListenOn('subscription.create')->thenGetData();
241 |
242 | // Do something with the $eventData
243 |
244 | ```
245 | ## Create a separate event class
246 | With this library, you can write a separate event class for a single event. For example, the `subscription.create` event can be created like this:
247 | ```php
248 | thenValidate($keys)
257 | ->thenListenOn('subscription.create');
258 | }
259 | }
260 |
261 | ```
262 |
263 | This can then be used like this:
264 |
265 | ```php
266 | thenGetData();
271 |
272 | // Or
273 |
274 | $event = SubscriptionCreated::validate($key)->thenGetEvent();
275 |
276 | ```
277 | Here, you can see that we are just implementing the `ActionEvent::class` interface and extending the `Event::class` on the `::validate()` method.
278 |
279 | ## Addons
280 | The library has a few of in-built functionalities to do somethings quicker and better. Let's take a look at them:
281 |
282 | #### 1. Nairas to kobo
283 | Since paystack accepts amount in kobo only, there should be a quick way to do that. Below are helper functions to help you out.
284 | ```php
285 | **Note:** The `short_naira_to_kobo()` helper function, supports only `k` as thousands, `m` as millions, `b` as billions and `t` as trillions notations.
300 |
301 | #### 2. Reference Generator
302 | You can easily generate especially, transaction reference easily by doing this:
303 |
304 | ```php
305 | [Josiah Ovye Yahaya](https://twitter.com/josiahoyahaya).
327 |
328 | ## Collaborators
329 | 1. [Josiah O. Yahaya](http://github.com/coderatio)
330 | 2. [Ndubuisi Onyemenam](http://github.com/prondubuisi)
331 |
332 | ## Licence
333 | This project is built and used with `GPL.3.0` licence.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "coderatio/paystack-mirror",
3 | "description": "An actionable PHP library for Paystack Api",
4 | "type": "library",
5 | "homepage": "https://github.com/coderatio/paystack-mirror",
6 | "authors": [
7 | {
8 | "name": "Josiah Ovye Yahaya",
9 | "email": "hello@josiah.com.ng",
10 | "homepage": "http://josiah.com.ng",
11 | "role": "Developer"
12 | }
13 | ],
14 | "autoload": {
15 | "classmap": [
16 | "src"
17 | ],
18 | "psr-4": {
19 | "Coderatio\\PaystackMirror\\": "src"
20 | },
21 | "files": [
22 | "src/helpers.php"
23 | ]
24 | },
25 | "require-dev": {
26 | "phpunit/phpunit": "7.5.x-dev"
27 | },
28 | "license": "GPL-3.0",
29 | "minimum-stability": "dev",
30 | "require": {
31 | "php": ">=7.1"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/docs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderatio/paystack-mirror/96cfc35867babfa32b7e23dcec28c27c000bc91d/docs/logo.png
--------------------------------------------------------------------------------
/docs/pages/bulk-charges.md:
--------------------------------------------------------------------------------
1 | # BULK CHARGES
2 | ## InitializeBulkCharge
3 | ```php
4 | // Class
5 |
6 | Coderatio\PaystackMirror\Actions\BulkCharges\InitializeBulkCharge::class
7 |
8 | ```
9 | Send an array of objects with authorization codes and amount in kobo so paystack can process transactions as a batch.
10 |
11 | **Body Params**
12 | * **authorization** - Authorization code
13 | * **amount** - Amount
14 |
15 | ## ListBulkChargeBatches
16 | ```php
17 | // Class
18 |
19 | Coderatio\PaystackMirror\Actions\ListBulkChargeBatches::class
20 |
21 | ```
22 | This lists all bulk charge batches created by the integration. Statuses can be active, paused, or complete.
23 |
24 | **Query Params**
25 | * **perPage** - Specify how many records you want to retrieve per page
26 | * **page** - Specify exactly what page you want to retrieve
27 |
28 | ## FetchBulkChargeBatch
29 | ```php
30 | // Class
31 |
32 | Coderatio\PaystackMirror\Actions\BulkCharges\FetchBulkChargeBatch::class
33 |
34 | ```
35 | This action retrieves a specific batch code. It also returns useful information on its progress by way of the `total_charges` and `pending_charges` attributes.
36 |
37 | **Path Params**
38 |
39 | * **id_or_code** (required) - An ID or code for the transfer whose details you want to retrieve.
40 |
41 | ## FetchChargesBatch
42 | ```php
43 | // Class
44 |
45 | Coderatio\PaystackMirror\Actions\BulkCharges\FetchChargesBatch::class
46 |
47 | ```
48 | This action retrieves the charges associated with a specified batch code. Pagination parameters are available. You can also filter by status. Charge statuses can be `pending`, `success` or `failed`.
49 |
50 | **Path Params**
51 |
52 | * **id_or_code** (required) - An ID or code for the batch whose charges you want to retrieve.
53 |
54 | **Query Params**
55 |
56 | * **status** - pending, success or failed
57 | * **perPage**
58 | * **page**
59 |
60 | _This params should be sent as one though._
61 |
62 | ## PauseBulkChargeBatch
63 | ```php
64 | // Class
65 |
66 | Coderatio\PaystackMirror\Actions\BulkCharges\PauseBulkChargeBatch::class
67 |
68 | ```
69 | Use this action to pause processing a batch
70 |
71 | **Path Params**
72 |
73 | * **batch_code** (required)
74 |
75 | ## ResumeBulkChargeBatch
76 | ```php
77 | // Class
78 | Coderatio\PaystackMirror\Actions\BulkCharges\ResumeBulkChargeBatch::class
79 |
80 | ```
81 | Use this action to resume processing a batch
82 |
83 | **Path Params**
84 |
85 | * **batch_code** (required)
86 |
87 | [Read more here...](https://developers.paystack.co/v1.0/reference#initiate-bulk-charge)
88 | ___
--------------------------------------------------------------------------------
/docs/pages/charges.md:
--------------------------------------------------------------------------------
1 | #CHARGES
2 | ```php
3 | Coderatio\PaystackMirror\Actions\Charges\...
4 | ```
5 |
6 | | Action | Description | Request type |
7 | | ------------- |:-------------:| -----:|
8 | | `TokenizePaymentInstrument` | Send an array of objects with authorization codes and amount in kobo so paystack can process transactions as a batch. | `POST` |
9 | | `InitializeCharge` | Send card details or bank details or authorization code to start a charge. Simple guide to charging cards directly | `POST` |
10 | | `SubmitPinToCharge` | Submit a pin to charge from | `POST` |
11 | | `SubmitOtpToCharge` | Submit OTP to complete a charge | `POST` |
12 | | `SubmitPhoneToCharge` | Submit Phone when requested | `POST` |
13 | | `SubmitBirthdayToCharge` | Submit Birthday when requested | `POST` |
14 | | `CheckPendingCharge` | When you get `pending` as a charge status, wait 30 seconds or more, then make a check to see if its status has changed. Don't call too early as you may get a lot more pending than you should. | `GET` |
15 |
16 | [Read more here...](https://developers.paystack.co/v1.0/reference#charge)
17 | ___
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | ./tests
14 |
15 |
16 | ./tests/Unit
17 |
18 |
19 |
20 | ./tests/Feature
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Actions/Action.php:
--------------------------------------------------------------------------------
1 | data = $data;
36 | }
37 |
38 | if ($data instanceof ParamsBuilder) {
39 | $this->data = $this->data->get();
40 | }
41 | }
42 |
43 | /**
44 | * Set a new end-point for this action
45 | *
46 | * @param $url
47 | * @return $this
48 | */
49 | public function setUrl($url): self
50 | {
51 | $this->url = $url;
52 |
53 | return $this;
54 | }
55 |
56 | /**
57 | * Set the query or body params to be sent to paystack on this action
58 | *
59 | * @param iterable $data
60 | * @return $this
61 | */
62 | public function setData(iterable $data): self
63 | {
64 | $this->data = $data;
65 |
66 | return $this;
67 | }
68 |
69 | /**
70 | * Set the type of http request used for this action
71 | *
72 | * @param string $type
73 | * @return $this
74 | */
75 | public function setRequestType(string $type): self
76 | {
77 | $this->requestType = $type;
78 |
79 | return $this;
80 | }
81 |
82 | /**
83 | * Get the type of http request used on this action
84 | *
85 | * @return string
86 | */
87 | public function getRequestType(): string
88 | {
89 | return $this->requestType;
90 | }
91 |
92 | /**
93 | * Get the action query or body params
94 | *
95 | * @return false|string
96 | */
97 | public function getData()
98 | {
99 | return json_encode($this->data);
100 | }
101 |
102 | /**
103 | * Get the action endpoint
104 | *
105 | * @return string
106 | */
107 | public function getUrl(): string
108 | {
109 | return $this->url;
110 | }
111 |
112 | /**
113 | * Append to query params
114 | *
115 | * @param $key
116 | * @param $value
117 | * @return $this
118 | */
119 | public function set($key, $value): self
120 | {
121 | $this->data[$key] = $value;
122 |
123 | return $this;
124 | }
125 |
126 | /**
127 | * Prepare action execution.
128 | *
129 | * @param CurlService $curlService
130 | * @return void
131 | */
132 | abstract public function handle(CurlService $curlService) : void;
133 | }
134 |
--------------------------------------------------------------------------------
/src/Actions/BulkCharges/FetchBulkChargeBatch.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'bulkcharge/' . $this->getBulkChargeBatchIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/BulkCharges/FetchChargesBatch.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . "bulkcharge/{$this->getBulkChargeBatchIdOrCode()}/charges";
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/BulkCharges/InitializeBulkCharge.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/BulkCharges/ListBulkChargeBatches.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/BulkCharges/PauseBulkChargeBatch.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'bulkcharge/pause/' . $this->getBulkChargeBatchIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/BulkCharges/ResumeBulkChargeBatch.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'bulkcharge/resume/' . $this->getBulkChargeBatchIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Charges/CheckPendingCharge.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'charge/' . $this->getIdOrReference();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Charges/InitializeCharge.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Charges/SubmitBirthdayToCharge.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Charges/SubmitOtpToCharge.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Charges/SubmitPhoneToCharge.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Charges/SubmitPinToCharge.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Charges/TokenizePaymentInstrument.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/ControlPanel/FetchPaymentSessionTimeout.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/ControlPanel/UpdatePaymentSessionTimeout.php:
--------------------------------------------------------------------------------
1 | data)) {
24 | $data['timeout'] = $this->data;
25 | }
26 |
27 | $this->data = $data;
28 |
29 | $curlService->put($this->url, $this->getData());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Actions/Customers/CreateCustomer.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Customers/DeactivateCustomerAuthorization.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Customers/FetchCustomer.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'customer/' . $this->getIdOrCustomerCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Customers/ListCustomers.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Customers/UpdateCustomer.php:
--------------------------------------------------------------------------------
1 | put($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'customer/' . $this->getIdOrCustomerCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Customers/WhiteOrBlackListCustomer.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/ArchiveInvoice.php:
--------------------------------------------------------------------------------
1 | post($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'invoice/archive/' . $this->getInvoiceIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/CreateInvoice.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/FinalizeInvoiceDraft.php:
--------------------------------------------------------------------------------
1 | post($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'paymentrequest/finalize/' . $this->getInvoiceIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/InvoiceTotals.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/ListInvoices.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/MarkAsPaidInvoice.php:
--------------------------------------------------------------------------------
1 | post($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'paymentrequest/mark_as_paid/' . $this->getInvoiceIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/SendInvoiceNotification.php:
--------------------------------------------------------------------------------
1 | post($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'paymentrequest/notify/' . $this->getInvoiceIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/UpdateInvoice.php:
--------------------------------------------------------------------------------
1 | put($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'paymentrequest/' . $this->getInvoiceIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/VerifyInvoice.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'paymentrequest/verify/' . $this->getInvoiceIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Invoices/ViewInvoice.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'paymentrequest/' . $this->getInvoiceIdOrCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Miscellaneous/CheckBalance.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Miscellaneous/ListBanks.php:
--------------------------------------------------------------------------------
1 | get($this->url);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Actions/Pages/CheckAvailablePageSlug.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'page/check_slug_availability/' . $this->getIdOrSlug();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Pages/CreatePage.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Pages/FetchPage.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'page/' . $this->getIdOrSlug();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Pages/ListPages.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Pages/UpdatePage.php:
--------------------------------------------------------------------------------
1 | put($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'page/' . $this->getIdOrSlug();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Plans/CreatePlan.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Plans/FetchPlan.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'plan/' . $this->getIdOrPlanCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Plans/ListPlans.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Plans/UpdatePlan.php:
--------------------------------------------------------------------------------
1 | put($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'plan/' . $this->getIdOrPlanCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Refunds/CreateRefund.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Actions/Refunds/FetchRefund.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | /**
26 | * @return string
27 | */
28 | public function getUrl(): string
29 | {
30 | return $this->url . 'refund/' . $this->getIdOrReference();
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Actions/Refunds/ListRefunds.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Actions/Settlements/FetchSettlements.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/SubAccounts/CreateSubAccount.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Actions/SubAccounts/FetchSubAccount.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl() : string
26 | {
27 | return $this->url . 'subaccount/' . $this->getIdOrSlug();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/SubAccounts/ListSubAccounts.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/SubAccounts/UpdateSubAccount.php:
--------------------------------------------------------------------------------
1 | put($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'subaccount/' . $this->getIdOrSlug();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Subscriptions/CreateSubscription.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Subscriptions/DisableSubscription.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Subscriptions/EnableSubscription.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Subscriptions/FetchSubscription.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'subscription/' . $this->getIdOrSubscriptionCode();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Subscriptions/ListSubscriptions.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/ChargeAuthorization.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/CheckAuthorization.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/DeactivateAuthorization.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/ExportTransactions.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/FetchTransaction.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'transaction/' . $this->getIdOrSlug();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/InitializeTransaction.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/ListTransactions.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/TransactionTotals.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/VerifyTransaction.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
22 | }
23 |
24 | public function getUrl(): string
25 | {
26 | return $this->url . "transaction/verify/{$this->getIdOrReference()}";
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Actions/Transactions/ViewTransactionTimeline.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 |
28 | return $this->url . 'transaction/timeline/' . $this->getIdOrReference();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Actions/TransferRecipients/CreateTransferRecipient.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/TransferRecipients/DeleteTransferRecipient.php:
--------------------------------------------------------------------------------
1 | delete($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'transferrecipient/' . $this->getRecipientCodeOrId();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/TransferRecipients/ListTransferRecipients.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/TransferRecipients/UpdateTransferRecipient.php:
--------------------------------------------------------------------------------
1 | put($this->getUrl(), $this->getData());
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'transferrecipient/' . $this->getRecipientCodeOrId();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Actions/Transfers/FetchTransfer.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transfers/FinalizeTransfer.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transfers/InitializeTransfer.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/Transfers/InitiateBulkTransfer.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/TransfersControl/DisableTransferOtp.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/TransfersControl/EnableTransferOtp.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/TransfersControl/FinalizeDisableTransferOtp.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Actions/TransfersControl/ResendTransferOtp.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 |
24 | public function getData()
25 | {
26 | $data = [];
27 |
28 | if (is_array($this->data) && !isset($this->data['reason'])) {
29 | $this->data['reason'] = 'transfer';
30 | }
31 |
32 | if (is_string($this->data)) {
33 | $data['transfer_code'] = $this->data;
34 | $data['reason'] = 'transfer';
35 | }
36 |
37 | $this->data = $data;
38 |
39 | return parent::getData();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Actions/Verifications/ResolveAccountNumber.php:
--------------------------------------------------------------------------------
1 | get($this->url, $this->data);
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Actions/Verifications/ResolveBvn.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'bank/resolve_bvn/' . $this->getBvn();
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Actions/Verifications/ResolveCardBin.php:
--------------------------------------------------------------------------------
1 | get($this->getUrl(), $this->data);
23 | }
24 |
25 | public function getUrl(): string
26 | {
27 | return $this->url . 'decision/bin/' . $this->getCardBin();
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Actions/Verifications/ResolvePhoneNumber.php:
--------------------------------------------------------------------------------
1 | post($this->url, $this->getData());
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Events/ActionEvent.php:
--------------------------------------------------------------------------------
1 | simulatedData()->asJson())->contents;
29 |
30 | //$input ;
31 | $event->rawContents = @file_get_contents('php://input');
32 | //$event->simulatedData()->headers['HTTP_X_PAYSTACK_SIGNATURE']
33 | $event->signature = ($_SERVER[self::PAYSTACK_SIGNATURE_KEY] ?? '');
34 | $event->getObject();
35 |
36 | return $event;
37 | }
38 |
39 | /**
40 | * Validate or check for valid Paystack secret key or keys.
41 | *
42 | * @param string|array $keyOrKeys
43 | * @return $this
44 | */
45 | public function thenValidate($keyOrKeys): self
46 | {
47 | if (is_array($keyOrKeys)) {
48 | foreach ($keyOrKeys as $key) {
49 | if ($this->isValidSignature($key)) {
50 | $this->isValidOwner = true;
51 | }
52 | }
53 | }
54 |
55 | if (!is_array($keyOrKeys) && $this->isValidSignature($keyOrKeys)) {
56 | $this->isValidOwner = true;
57 | }
58 |
59 | return $this;
60 | }
61 |
62 | /**
63 | * Load only data for an an event.
64 | *
65 | * @param $event
66 | * @return Event
67 | */
68 | public function thenListenOn($event): self
69 | {
70 | if (!$this->eventObject || !property_exists($this->eventObject, 'data')) {
71 | $this->data = [];
72 | }
73 |
74 | if ($this->isValidOwner && $event == $this->eventObject->event) {
75 | $this->data = $this->getObject()->data;
76 | }
77 |
78 | return $this;
79 | }
80 |
81 | /**
82 | * Get the event object or property from an event object
83 | *
84 | * @param string $property
85 | * @return object|bool|string
86 | */
87 | public function thenGetEvent($property = '')
88 | {
89 | if (!empty($this->data)) {
90 | if (!empty($property) && property_exists($this->eventObject, $property)) {
91 | return $this->eventObject->{$property};
92 | }
93 |
94 | return $this->getObject();
95 | }
96 |
97 | return false;
98 | }
99 |
100 | /**
101 | * Get the data object or property from an event object
102 | *
103 | * @param string $property
104 | * @return object|bool|string
105 | */
106 | public function thenGetData($property = '')
107 | {
108 | if (!empty($this->data)) {
109 | if (!empty($property) && property_exists($this->eventObject->data, $property)) {
110 | return $this->eventObject->data->{$property};
111 | }
112 |
113 | return $this->eventObject->data;
114 | }
115 |
116 | return false;
117 | }
118 |
119 | /**
120 | * Forwards the event data to another webhook.
121 | *
122 | * @param $url
123 | * @param array $moreHeaders
124 | * @param string $method
125 | * @return mixed
126 | * @throws Exception
127 | */
128 | public function thenForwardTo($url, array $moreHeaders = [], $method = 'POST')
129 | {
130 | if (!filter_var($url, FILTER_VALIDATE_URL)) {
131 | return false;
132 | }
133 |
134 | if (!empty($this->data)) {
135 | $method = mb_strtolower($method);
136 |
137 | $curlService = new CurlService();
138 | $requestHeaders = $moreHeaders;
139 | $requestHeaders['X-Paystack-Signature'] = $this->signature;
140 | $requestHeaders['HTTP_X_PAYSTACK_SIGNATURE'] = $this->signature;
141 | $requestHeaders['Content-Type'] = 'application/json';
142 | $curlService->appendRequestHeaders($requestHeaders);
143 |
144 | return $curlService->$method($url, [
145 | 'event' => $this->eventObject->event,
146 | 'data' => json_encode($this->eventObject->data)
147 | ]);
148 | }
149 |
150 | return false;
151 | }
152 |
153 | /**
154 | * Get the event content as object
155 | *
156 | * @return mixed
157 | */
158 | protected function getObject()
159 | {
160 | return $this->eventObject = json_decode($this->rawContents);
161 | }
162 |
163 | /**
164 | * Check if the request has a valid signature
165 | *
166 | * @param $key
167 | * @return bool
168 | */
169 | protected function isValidSignature($key): bool
170 | {
171 | return $this->signature === hash_hmac('sha512', $this->rawContents, $key);
172 | }
173 |
174 | protected function simulatedData()
175 | {
176 | $data = '
177 | {
178 | "event": "subscription.create",
179 | "data": {
180 | "domain": "test",
181 | "status": "active",
182 | "subscription_code": "SUB_vsyqdmlzble3uii",
183 | "amount": 50000,
184 | "cron_expression": "0 0 28 * *",
185 | "next_payment_date": "2016-05-19T07:00:00.000Z",
186 | "open_invoice": null,
187 | "createdAt": "2016-03-20T00:23:24.000Z",
188 | "plan": {
189 | "name": "Monthly retainer",
190 | "plan_code": "PLN_gx2wn530m0i3w3m",
191 | "description": null,
192 | "amount": 50000,
193 | "interval": "monthly",
194 | "send_invoices": true,
195 | "send_sms": true,
196 | "currency": "NGN"
197 | },
198 | "authorization": {
199 | "authorization_code": "AUTH_96xphygz",
200 | "bin": "539983",
201 | "last4": "7357",
202 | "exp_month": "10",
203 | "exp_year": "2017",
204 | "card_type": "MASTERCARD DEBIT",
205 | "bank": "GTBANK",
206 | "country_code": "NG",
207 | "brand": "MASTERCARD"
208 | },
209 | "customer": {
210 | "first_name": "BoJack",
211 | "last_name": "Horseman",
212 | "email": "bojack@horsinaround.com",
213 | "customer_code": "CUS_xnxdt6s1zg1f4nx",
214 | "phone": "",
215 | "metadata": {},
216 | "risk_action": "default"
217 | },
218 | "created_at": "2016-10-01T10:59:59.000Z"
219 | }
220 | }';
221 |
222 | $curlService = new \Coderatio\PaystackMirror\Services\CurlService();
223 | try {
224 | $curlService->post('http://paystack-mirror.test/events.php', ['contents' => $data]);
225 | } catch (Exception $e) {
226 | }
227 | return $curlService->getResponse();
228 | }
229 |
230 | }
--------------------------------------------------------------------------------
/src/Events/EventInterface.php:
--------------------------------------------------------------------------------
1 | thenValidate($keys)
12 | ->thenListenOn('subscription.create');
13 | }
14 | }
--------------------------------------------------------------------------------
/src/Exceptions/PaystackMirrorException.php:
--------------------------------------------------------------------------------
1 | get();
94 | }
95 |
96 | return array_map(function ($accountDetails) use ($action, $parentData) {
97 | if ($accountDetails instanceof ParamsBuilder) {
98 | $accountDetails = $accountDetails->get();
99 | }
100 |
101 | if (isset($accountDetails['key']) || isset($accountDetails['secret'])) {
102 |
103 | $data = $accountDetails['data'] ?? [];
104 |
105 | if (!empty($data) && $data instanceof ParamsBuilder) {
106 | $data = $data->get();
107 | }
108 |
109 | $key = $accountDetails['key'] ?? $accountDetails['secret'] ?? '';
110 |
111 | if (!empty($parentData)) {
112 | if ($parentData instanceof ParamsBuilder) {
113 | $parentData = $parentData->get();
114 | }
115 |
116 | $data = $parentData;
117 | }
118 |
119 | $request = static::run($key, static::parsedAction($action, $data), $data);
120 |
121 | return (object)[
122 | 'account' => $key,
123 | 'response' => $request->getResponse()
124 | ];
125 | }
126 |
127 | return (object)[];
128 |
129 | }, $accountsDetails);
130 | }
131 |
132 | /**
133 | * Set Paystack secret key
134 | *
135 | * @param $secretKey
136 | * @return PaystackMirror
137 | */
138 | public static function setKey($secretKey): PaystackMirror
139 | {
140 | static::$secretKey = $secretKey;
141 |
142 | return new self();
143 | }
144 |
145 | /**
146 | * Set multiple Paystack accounts secret keys
147 | *
148 | * @param $accountsDetails
149 | * @return PaystackMirror
150 | */
151 | public static function setAccounts($accountsDetails): PaystackMirror
152 | {
153 | static::$accountsDetails = $accountsDetails;
154 |
155 | return new self();
156 | }
157 |
158 | /**
159 | * This function works as the run method but takes
160 | * only an action to mirror.
161 | *
162 | * @param mixed $action
163 | * @param array $data
164 | * @return PaystackMirror
165 | * @throws PaystackMirrorException
166 | */
167 | public function mirror($action, $data = []): PaystackMirror
168 | {
169 | return static::run(static::$secretKey, $action, $data);
170 | }
171 |
172 | /**
173 | * Mirror Paystack mirror on multiple accounts.
174 | *
175 | * @param $action
176 | * @param array $data
177 | * @return array
178 | */
179 | public function mirrorMultipleAccountsOn($action, $data = []): array
180 | {
181 | return static::runMultipleAccounts(static::$accountsDetails, $action, $data);
182 | }
183 |
184 | /**
185 | * This function returns the response from an action
186 | *
187 | * @return CurlHttpResponseService
188 | */
189 | public function getResponse() : CurlHttpResponseService
190 | {
191 | return static::$response;
192 | }
193 |
194 | /**
195 | * Converts Nigerian Naira to Kobo Coin
196 | *
197 | * @param mixed $nairaAmount
198 | * @return int
199 | */
200 | public static function nairaToKobo($nairaAmount): int
201 | {
202 | return static::getCleanedAmount($nairaAmount) * 100;
203 |
204 | }
205 |
206 | /**
207 | * Converts Nigerian Kobo Coin to Naira
208 | *
209 | * @param mixed $koboAmount
210 | * @return int
211 | */
212 | public static function koboToNaira($koboAmount): int
213 | {
214 | return static::getCleanedAmount($koboAmount) / 100;
215 | }
216 |
217 | /**
218 | * Generates a random reference.
219 | *
220 | * @return string|null
221 | */
222 | public static function generateReference(): ?string
223 | {
224 | return mb_strtolower('PM_' . crypt(str_shuffle('PAYSTACK_MIRROR_REF'), 'rf'));
225 | }
226 |
227 | /**
228 | * Creates a simple ISO 8601 dates.
229 | *
230 | * @param string $date
231 | * @return string
232 | * @throws Exception
233 | */
234 | public static function createISO8601Date($date = ''): string
235 | {
236 | if (empty($date)) {
237 | $date = date('Y-m-d h:i:s');
238 | }
239 |
240 | return (new DateTime($date))->format(DateTime::ATOM);
241 | }
242 |
243 | /**
244 | * @param $shortNaira
245 | * @return float|int
246 | * @throws PaystackMirrorException
247 | */
248 | public static function shortNairaToKobo($shortNaira)
249 | {
250 | $moneyNotations = [
251 | 'k' => 100000,
252 | 'm' => 100000000,
253 | 'b' => 100000000000,
254 | 't' => 100000000000000,
255 | ];
256 |
257 | foreach($moneyNotations as $shortNotation => $conversionRate) {
258 | $shortNaira = str_replace([',', '/', '|', ':', ';', ' '], '', trim($shortNaira));
259 | $explodedData = explode($shortNotation, mb_strtolower($shortNaira));
260 |
261 | if (isset($explodedData[1])) {
262 | return ($conversionRate * $explodedData[0]);
263 | }
264 | }
265 |
266 | throw new PaystackMirrorException('Invalid format provided: You should enter something like 1K or 1M or 1B or 1T.');
267 | }
268 |
269 | /**
270 | * Convert action to object if $action::class used and
271 | * pass in data provided.
272 | *
273 | * @param $action
274 | * @param $data
275 | * @return Action $action
276 | */
277 | protected static function parsedAction($action, $data): Action
278 | {
279 | if ($data instanceof ParamsBuilder) {
280 | $data = $data->get();
281 | }
282 |
283 | if (is_string($action)) {
284 | $action = new $action($data);
285 | }
286 |
287 | if (!empty($data)) {
288 | new $action($data);
289 | }
290 |
291 | return $action;
292 | }
293 |
294 | /**
295 | * Stop execution if the action is not valid
296 | *
297 | * @param $action
298 | * @return PaystackMirror
299 | * @throws PaystackMirrorException
300 | */
301 | protected static function abortIfNotValidAction($action): PaystackMirror
302 | {
303 | if (!(new $action() ?? !is_string($action)) instanceof Action) {
304 | $actionClassName = get_class($action);
305 |
306 | throw new PaystackMirrorException(
307 | "[{$actionClassName}], must be an instance of " . Action::class
308 | );
309 | }
310 |
311 | return new self();
312 | }
313 |
314 | private static function getCleanedAmount($amount)
315 | {
316 | return str_replace([',', '.', '/', '|', ':', ';', ' '], '', trim($amount));
317 | }
318 | }
319 |
--------------------------------------------------------------------------------
/src/Services/CurlCacheService.php:
--------------------------------------------------------------------------------
1 | true), 'module_cache'=>'repository');
13 | * $ret = $c->get('http://www.google.com');
14 | *
15 | * @copyright Coderatio
16 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
17 | */
18 | class CurlCacheService
19 | {
20 | /** @var string */
21 | public $dir = '';
22 |
23 | /**
24 | *
25 | * @param string @module which module is using curl_cache
26 | *
27 | */
28 | public function __construct()
29 | {
30 |
31 | $this->dir = '/tmp/';
32 |
33 | if (!file_exists($this->dir) && !mkdir($concurrentDirectory = $this->dir, 0700, true) && !is_dir($concurrentDirectory)) {
34 | throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
35 | }
36 |
37 | $this->ttl = 1200;
38 | }
39 |
40 | /**
41 | * Get cached value
42 | *
43 | * @param mixed $param
44 | * @return bool|string
45 | */
46 | public function get($param)
47 | {
48 | $this->cleanup($this->ttl);
49 | $filename = 'u_' . md5(serialize($param));
50 | if (file_exists($this->dir . $filename)) {
51 | $lasttime = filemtime($this->dir . $filename);
52 |
53 | if (time() - $lasttime > $this->ttl) {
54 | return false;
55 | }
56 |
57 | $fp = fopen($this->dir . $filename, 'rb');
58 | $size = filesize($this->dir . $filename);
59 | $content = fread($fp, $size);
60 |
61 | return unserialize($content);
62 | }
63 |
64 | return false;
65 | }
66 |
67 | /**
68 | * Set cache value
69 | *
70 | * @param mixed $param
71 | * @param mixed $val
72 | */
73 | public function set($param, $val): void
74 | {
75 | $filename = 'u_' . md5(serialize($param));
76 | $fp = fopen($this->dir . $filename, 'wb');
77 | fwrite($fp, serialize($val));
78 | fclose($fp);
79 | }
80 |
81 | /**
82 | * Remove cache files
83 | *
84 | * @param int $expire The number os seconds before expiry
85 | */
86 | public function cleanup($expire): void
87 | {
88 | if ($dir = opendir($this->dir)) {
89 | while (false !== ($file = readdir($dir))) {
90 | if ($file !== '.' && $file !== '..' && !is_dir($file)) {
91 | $lasttime = @filemtime($this->dir . $file);
92 | if (time() - $lasttime > $expire) {
93 | @unlink($this->dir . $file);
94 | }
95 | }
96 | }
97 | }
98 | }
99 |
100 | /**
101 | * delete current user's cache file
102 | *
103 | */
104 | public function refresh(): void
105 | {
106 | if ($dir = opendir($this->dir)) {
107 | while (false !== ($file = readdir($dir))) {
108 | if ($file !== '.' && $file !== '..' && !is_dir($file) && strpos($file, 'u_') !== false) {
109 | @unlink($this->dir . $file);
110 | }
111 | }
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/Services/CurlHttpResponseService.php:
--------------------------------------------------------------------------------
1 | statusCode = $statusCode;
16 | $this->headers = $headers;
17 | $this->text = $text;
18 | }
19 |
20 | public function __toString()
21 | {
22 | return $this->text;
23 | }
24 |
25 | public function asJson(): string
26 | {
27 | header('Content-Type: application/json');
28 |
29 | return $this->text;
30 | }
31 |
32 | public function asObject()
33 | {
34 | return json_decode($this->text);
35 | }
36 |
37 | public function asArray(): array
38 | {
39 | return (array) $this->asObject();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Services/CurlService.php:
--------------------------------------------------------------------------------
1 | initializeCurlOptions();
64 | if (!empty($options['debug'])) {
65 | $this->debug = true;
66 | }
67 | if (!empty($options['cookie'])) {
68 | if ($options['cookie'] === true) {
69 | $this->cookiePath = 'curl_cookie.txt';
70 | } else {
71 | $this->cookiePath = $options['cookie'];
72 | }
73 | }
74 | if (!empty($options['cache']) && class_exists('CurlCacheService')) {
75 | $this->cacheInstance = new CurlCacheService();
76 | }
77 | }
78 |
79 | /**
80 | * HTTP GET method
81 | *
82 | * @param string $url
83 | * @param array $params
84 | * @param array $curlOptions
85 | * @return object
86 | * @throws Exception
87 | */
88 | public function get($url, $params = [], $curlOptions = [])
89 | {
90 | $curlOptions['CURLOPT_HTTPGET'] = 1;
91 |
92 | if (!empty($params)) {
93 | $url .= (strpos($url, '?') !== false) ? '&' : '?';
94 | $url .= http_build_query($params, '', '&');
95 | }
96 |
97 | return $this->request($url, $curlOptions);
98 | }
99 |
100 | /**
101 | * HTTP POST method
102 | *
103 | * @param string $url
104 | * @param array|string $params
105 | * @param array $curlOptions
106 | * @return object
107 | * @throws Exception
108 | */
109 | public function post($url, $params = '', $curlOptions = array())
110 | {
111 | if (is_array($params)) {
112 | $params = $this->makePostFields($params);
113 | }
114 |
115 | $curlOptions['CURLOPT_POST'] = 1;
116 | $curlOptions['CURLOPT_POSTFIELDS'] = $params;
117 |
118 | return $this->request($url, $curlOptions);
119 | }
120 |
121 | /**
122 | * HTTP PUT method
123 | *
124 | * @param string $url
125 | * @param array $params
126 | * @param array $curlOptions
127 | * @return object
128 | * @throws Exception
129 | */
130 | public function put($url, $params = [], $curlOptions = [])
131 | {
132 | if (is_array($params)) {
133 | $params = $this->makePostFields($params);
134 | }
135 |
136 | $curlOptions['CURLOPT_RETURNTRANSFER'] = true;
137 | $curlOptions['CURLOPT_CUSTOMREQUEST'] = 'PUT';
138 | $curlOptions['CURLOPT_POSTFIELDS'] = $params;
139 |
140 | return $this->request($url, $curlOptions);
141 | }
142 |
143 | /**
144 | * HTTP DELETE method
145 | *
146 | * @param string $url
147 | * @param array $params
148 | * @param array $curlOptions
149 | * @return object
150 | * @throws PaystackMirrorException
151 | */
152 | public function delete($url, $params = [], $curlOptions = [])
153 | {
154 | $curlOptions['CURLOPT_CUSTOMREQUEST'] = 'DELETE';
155 | $params = $this->makePostFields($params);
156 | $curlOptions['CURLOPT_POSTFIELDS'] = $params;
157 |
158 | if (!isset($curlOptions['CURLOPT_USERPWD'])) {
159 | $curlOptions['CURLOPT_USERPWD'] = self::DEFAULT_USERPWD;
160 | }
161 |
162 | return $this->request($url, $curlOptions);
163 | }
164 |
165 | /**
166 | * HTTP TRACE method
167 | *
168 | * @param string $url
169 | * @param array $curlOptions
170 | * @return object
171 | * @throws Exception
172 | */
173 | public function trace($url, $curlOptions = array())
174 | {
175 | $curlOptions['CURLOPT_CUSTOMREQUEST'] = 'TRACE';
176 |
177 | return $this->request($url, $curlOptions);
178 | }
179 |
180 | /**
181 | * HTTP OPTIONS method
182 | *
183 | * @param string $url
184 | * @param array $curlOptions
185 | * @return object
186 | * @throws Exception
187 | */
188 | public function options($url, $curlOptions = array())
189 | {
190 | $curlOptions['CURLOPT_CUSTOMREQUEST'] = 'OPTIONS';
191 |
192 | return $this->request($url, $curlOptions);
193 | }
194 |
195 | /**
196 | * HTTP HEAD method
197 | *
198 | * @param string $url
199 | * @param array $curlOptions
200 | * @return object
201 | * @throws PaystackMirrorException
202 | * @see request()
203 | */
204 | public function head($url, $curlOptions = [])
205 | {
206 | $curlOptions['CURLOPT_HTTPGET'] = 0;
207 | $curlOptions['CURLOPT_HEADER'] = 1;
208 | $curlOptions['CURLOPT_NOBODY'] = 1;
209 |
210 | return $this->request($url, $curlOptions);
211 | }
212 |
213 | /**
214 | * Download multiple files in parallel
215 | *
216 | * Calls {@link multi()} with specific download headers
217 | *
218 | *
219 | * $c = new CurlService();
220 | * $c->download(array(
221 | * array('url'=>'http://localhost/', 'file'=>fopen('a', 'wb')),
222 | * array('url'=>'http://localhost/20/', 'file'=>fopen('b', 'wb'))
223 | * ));
224 | *
225 | *
226 | * @param array $requests An array of files to request
227 | * @param array $options An array of options to set
228 | * @return array An array of results
229 | */
230 | public function download($requests, $options = array()): array
231 | {
232 | $options['CURLOPT_BINARYTRANSFER'] = 1;
233 | $options['RETURNTRANSFER'] = false;
234 |
235 | return $this->multi($requests, $options);
236 | }
237 |
238 | /**
239 | * Reset Cookie
240 | */
241 | public function purgeCookies(): void
242 | {
243 | if (!empty($this->cookiePath) && is_file($this->cookiePath)) {
244 | $fp = fopen($this->cookiePath, 'wb');
245 | if (!empty($fp)) {
246 | fwrite($fp, '');
247 | fclose($fp);
248 | }
249 | }
250 | }
251 |
252 | /**
253 | * Set curl option
254 | *
255 | * @param string $name
256 | * @param string $value
257 | */
258 | public function addCurlOption($name, $value): void
259 | {
260 | if (stripos($name, 'CURLOPT_') === false) {
261 | $name = strtoupper('CURLOPT_' . $name);
262 | }
263 |
264 | $this->curlOptions[$name] = $value;
265 | }
266 |
267 | /**
268 | * Set curl options
269 | *
270 | * @param array $curlOptions If array is null, this function will
271 | * reset the options to default value.
272 | */
273 | public function addCurlOptions($curlOptions = array()): void
274 | {
275 | if (is_array($curlOptions)) {
276 | foreach ($curlOptions as $name => $val) {
277 | $this->addCurlOption($name, $val);
278 | }
279 | }
280 | }
281 |
282 | /**
283 | * Reset http method
284 | *
285 | */
286 | public function resetCurlOptions(): void
287 | {
288 | unset(
289 | $this->curlOptions['CURLOPT_HTTPGET'],
290 | $this->curlOptions['CURLOPT_POST'],
291 | $this->curlOptions['CURLOPT_POSTFIELDS'],
292 | $this->curlOptions['CURLOPT_PUT'],
293 | $this->curlOptions['CURLOPT_INFILE'],
294 | $this->curlOptions['CURLOPT_INFILESIZE'],
295 | $this->curlOptions['CURLOPT_CUSTOMREQUEST']
296 | );
297 | }
298 |
299 | /**
300 | * Append to existing headers.
301 | *
302 | * @param $key
303 | * @param $value
304 | */
305 | public function appendRequestHeader($key, $value): void
306 | {
307 | $this->requestHeaders[] = [(string)$key, (string)$value];
308 | }
309 |
310 | /**
311 | * Set HTTP Request Header
312 | *
313 | * @param array $headers
314 | */
315 | public function appendRequestHeaders(array $headers): void
316 | {
317 | foreach ($headers as $header) {
318 | $this->appendRequestHeader($header[0], $header[1]);
319 | }
320 | }
321 |
322 | /**
323 | * Send request headers.
324 | *
325 | * @param array $headers
326 | */
327 | public function setRequestHeaders(array $headers): void
328 | {
329 | $this->requestHeaders = $headers;
330 | }
331 |
332 | /**
333 | * Set HTTP Response Header
334 | */
335 | public function getResponseHeaders(): array
336 | {
337 | return $this->responseHeaders;
338 | }
339 |
340 | /**
341 | * Get all request headers.
342 | *
343 | * @return array
344 | */
345 | public function getRequestHeaders(): array
346 | {
347 | return $this->requestHeaders;
348 | }
349 |
350 | /*
351 | * Multiple HTTP Requests
352 | * This function could run multi-requests in parallel.
353 | *
354 | * @param array $requests An array of files to request
355 | * @param array $options An array of options to set
356 | * @return array An array of results
357 | */
358 | protected function multi($requests, $options = array()): array
359 | {
360 | $count = count($requests);
361 | $handles = array();
362 | $results = array();
363 | $main = curl_multi_init();
364 |
365 | for ($i = 0; $i < $count; $i++) {
366 | $url = $requests[$i];
367 | foreach ($url as $n => $v) {
368 | $options[$n] = $url[$n];
369 | }
370 | $handles[$i] = curl_init($url['url']);
371 | // Clean up
372 | $this->resetCurlOptions();
373 | $this->prepareRequest($handles[$i], $options);
374 | curl_multi_add_handle($main, $handles[$i]);
375 | }
376 |
377 | $running = 0;
378 |
379 | do {
380 | curl_multi_exec($main, $running);
381 | } while ($running > 0);
382 |
383 | foreach ($handles as $handle) {
384 | if (!empty($options['CURLOPT_RETURNTRANSFER'])) {
385 | $results[] = true;
386 | } else {
387 | $results[] = curl_multi_getcontent($handle);
388 | }
389 |
390 | curl_multi_remove_handle($main, $handle);
391 | }
392 |
393 | curl_multi_close($main);
394 |
395 | return $results;
396 | }
397 |
398 | /**
399 | * Single HTTP Request
400 | *
401 | * @param string $url The URL to request
402 | * @param array $curlOptions
403 | * @return object
404 | * @throws PaystackMirrorException
405 | */
406 | protected function request($url, $curlOptions = array())
407 | {
408 | // create curl instance
409 | $curl = curl_init($url);
410 | $curlOptions['url'] = $url;
411 | $this->resetCurlOptions();
412 | $this->prepareRequest($curl, $curlOptions);
413 |
414 | if ($this->cacheInstance && $httpbody = $this->cacheInstance->get($this->curlOptions)) {
415 | return $httpbody;
416 | }
417 |
418 | $httpbody = curl_exec($curl);
419 |
420 | if ($this->cacheInstance) {
421 | $this->cacheInstance->set($this->curlOptions, $httpbody);
422 | }
423 |
424 | $this->info = curl_getinfo($curl);
425 | $this->error = curl_error($curl);
426 |
427 | if ($this->debug) {
428 | paystack_mirror_dump($this->info);
429 | paystack_mirror_dump($this->error);
430 | }
431 |
432 | curl_close($curl);
433 |
434 | $response = new CurlHttpResponseService($this->info['http_code'], $this->responseHeaders, $httpbody);
435 |
436 | $this->response = $response;
437 |
438 | if (!empty($this->error)) {
439 | throw new PaystackMirrorException($this->error);
440 | }
441 |
442 | return $response;
443 | }
444 |
445 | /**
446 | * Transform a PHP array into POST parameter
447 | *
448 | * @param array $postdata
449 | * @return array containing all POST parameters (1 row = 1 POST parameter)
450 | */
451 | public function makePostFields($postdata): array
452 | {
453 | if (!is_array($postdata) && !self::isCurlFile($postdata)) {
454 | $postdata = (array)$postdata;
455 | }
456 |
457 | $postFields = [];
458 |
459 | foreach ($postdata as $name => $value) {
460 | $name = urlencode($name);
461 | if (is_object($value) && !self::isCurlFile($value)) {
462 | $value = (array)$value;
463 | }
464 | if (is_array($value) && !self::isCurlFile($value)) {
465 | $postFields = $this->makeArrayField($name, $value, $postFields);
466 | } else {
467 | $postFields[$name] = $value;
468 | }
469 | }
470 |
471 | return $postFields;
472 | }
473 |
474 | /**
475 | * Get cURL info
476 | *
477 | * @return mixed
478 | */
479 | public function getInfo()
480 | {
481 | return $this->info;
482 | }
483 |
484 | /**
485 | * Prepare a file to upload via cURL
486 | *
487 | * @param $filepath
488 | * @param string $filename
489 | * @param string $mimetype
490 | * @return string
491 | */
492 | public static function makeUploadFile($filepath, $filename = '', $mimetype = ''): string
493 | {
494 | return curl_file_create($filepath, $filename, $mimetype);
495 | }
496 |
497 | /**
498 | * Get cURL response
499 | *
500 | * @return mixed
501 | */
502 | public function getResponse()
503 | {
504 | return $this->response;
505 | }
506 |
507 | /**
508 | * Resets the CURL options that have already been set
509 | */
510 | private function initializeCurlOptions(): void
511 | {
512 | $this->curlOptions = [
513 | 'CURLOPT_USERAGENT' => 'cURL',
514 | // True to include the header in the output
515 | 'CURLOPT_HEADER' => 0,
516 | // True to Exclude the body from the output
517 | 'CURLOPT_NOBODY' => 0,
518 | // TRUE to follow any "Location: " header that the server
519 | // sends as part of the HTTP header (note this is recursive,
520 | // PHP will follow as many "Location: " headers that it is sent,
521 | // unless CURLOPT_MAXREDIRS is set).
522 | //$this->curlOptions['CURLOPT_FOLLOWLOCATION'] = 1;
523 | 'CURLOPT_MAXREDIRS' => 10,
524 | 'CURLOPT_ENCODING' => '',
525 | // TRUE to return the transfer as a string of the return
526 | // value of curl_exec() instead of outputting it out directly.
527 | 'CURLOPT_RETURNTRANSFER' => 1,
528 | 'CURLOPT_BINARYTRANSFER' => 0,
529 | 'CURLOPT_SSL_VERIFYPEER' => 0,
530 | 'CURLOPT_SSL_VERIFYHOST' => 2,
531 | 'CURLOPT_CONNECTTIMEOUT' => 30,
532 | ];
533 | }
534 |
535 | /**
536 | * Recursive function formating an array in POST parameter
537 | *
538 | * @param $fieldname
539 | * @param $arrayData
540 | * @param $postFields
541 | * @return array
542 | */
543 | private function makeArrayField($fieldname, $arrayData, $postFields): array
544 | {
545 | foreach ($arrayData as $key => $value) {
546 | $key = urlencode($key);
547 | if (is_object($value)) {
548 | $value = (array)$value;
549 | }
550 | if (is_array($value)) { //the value is an array, call the function recursively
551 | $newfieldname = $fieldname . "[$key]";
552 | $postFields = $this->makeArrayField($newfieldname, $value, $postFields);
553 | } else {
554 | $postFields[] = $fieldname . "[$key]=" . urlencode($value);
555 | }
556 | }
557 |
558 | return $postFields;
559 | }
560 |
561 | /**
562 | * private callback function
563 | * Formatting HTTP Response Header
564 | *
565 | * @param $curl resource
566 | * @param string $header
567 | * @return int The strlen of the header
568 | */
569 | private function handleResponseHeaders($curl, $header): int
570 | {
571 | if ($curl && strlen((string)$header) > 2) {
572 | [$key, $value] = explode(' ', rtrim($header, "\r\n"), 2);
573 | $key = rtrim($key, ':');
574 | if (!empty($this->responseHeaders[$key])) {
575 | if (is_array($this->responseHeaders[$key])) {
576 | $this->responseHeaders[$key][] = $value;
577 | } else {
578 | $tmp = $this->responseHeaders[$key];
579 | $this->responseHeaders[$key] = array();
580 | $this->responseHeaders[$key][] = $tmp;
581 | $this->responseHeaders[$key][] = $value;
582 |
583 | }
584 | } else {
585 | $this->responseHeaders[$key] = $value;
586 | }
587 | }
588 |
589 | return strlen($header);
590 | }
591 |
592 | /**
593 | * Set options for individual curl instance
594 | *
595 | * @param $curl resource
596 | * @param $curlOptions
597 | * @return resource The curl handle
598 | */
599 | private function prepareRequest($curl, $curlOptions)
600 | {
601 | // set cookie
602 | if (!empty($this->cookiePath) || !empty($curlOptions['cookie'])) {
603 | $this->addCurlOption('cookiejar', $this->cookiePath);
604 | $this->addCurlOption('cookiefile', $this->cookiePath);
605 | }
606 |
607 | // set proxy
608 | if (!empty($this->proxy) || !empty($curlOptions['proxy'])) {
609 | $this->addCurlOptions($this->proxy);
610 | }
611 |
612 | $this->addCurlOptions($curlOptions);
613 | // set headers
614 | if (empty($this->requestHeaders)) {
615 | $this->appendRequestHeaders(array(
616 | ['User-Agent', $this->curlOptions['CURLOPT_USERAGENT']],
617 | ['Accept-Charset', 'UTF-8']
618 | ));
619 | }
620 |
621 | self::applyCurlOption($curl, $this->curlOptions);
622 | curl_setopt($curl, CURLOPT_HEADERFUNCTION, [&$this, 'handleResponseHeaders']);
623 | curl_setopt($curl, CURLOPT_HTTPHEADER, self::prepareRequestHeaders($this->requestHeaders));
624 |
625 | if ($this->debug) {
626 | paystack_mirror_dump($this->curlOptions);
627 | paystack_mirror_dump($this->requestHeaders);
628 | }
629 | return $curl;
630 | }
631 |
632 | private static function applyCurlOption($curl, $curlOptions): void
633 | {
634 | // Apply curl options
635 | foreach ($curlOptions as $name => $value) {
636 | if (is_string($name)) {
637 | curl_setopt($curl, constant(strtoupper($name)), $value);
638 | }
639 | }
640 | }
641 |
642 | private static function prepareRequestHeaders($headers): array
643 | {
644 | $processedHeaders = [];
645 |
646 | foreach ($headers as $header) {
647 | $processedHeaders[] = $header[0] . ': ' . $header[1];
648 | }
649 |
650 | return $processedHeaders;
651 | }
652 |
653 | private static function isCurlFile($field): bool
654 | {
655 | return is_object($field) ? $field instanceof CURLFile : false;
656 | }
657 |
658 | }
659 |
660 |
661 |
--------------------------------------------------------------------------------
/src/Services/ParamsBuilder.php:
--------------------------------------------------------------------------------
1 | properties)) {
14 | return $this->properties[$property];
15 | }
16 |
17 | return null;
18 | }
19 |
20 | public function __set($propertyName, $propertyValue)
21 | {
22 | $this->properties[$propertyName] = $propertyValue;
23 | }
24 |
25 | public function __isset($propertyName)
26 | {
27 | return $this->properties[$propertyName] ? $propertyName : null;
28 | }
29 |
30 | public function get(): array
31 | {
32 | return (array) $this->properties;
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Services/RequestHandlerService.php:
--------------------------------------------------------------------------------
1 | appendRequestHeaders([
16 | ['Authorization', 'Bearer ' . $secretKey],
17 | ['Content-Type', 'application/json']
18 | ]);
19 |
20 | $action->handle($curlService);
21 |
22 | return $curlService->getResponse();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Traits/HasBulkChargeBatchIdOrCode.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['batch_code'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['batch_code'], $this->data['id'])) {
26 | $this->data['batch_code'] = null;
27 | }
28 |
29 | return $this->data['batch_code'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Traits/HasBvn.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['bvn'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['bvn'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | return $this->data['bvn'] ?? null;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Traits/HasCardBin.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['bin'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['bin'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | return $this->data['bin'] ?? null;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Traits/HasIdOrCustomerCode.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['customer_code'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['customer_code'], $this->data['id'])) {
26 | $this->data['customer_code'] = null;
27 | }
28 |
29 | return $this->data['customer_code'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Traits/HasIdOrPlanCode.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['plan_code'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['plan_code'], $this->data['id'])) {
26 | $this->data['plan_code'] = null;
27 | }
28 |
29 | return $this->data['plan_code'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Traits/HasIdOrReference.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['reference'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['reference'], $this->data['id'])) {
26 | $this->data['reference'] = null;
27 | }
28 |
29 | return $this->data['reference'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Traits/HasIdOrSlug.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['slug'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['slug'], $this->data['id'])) {
26 | $this->data['slug'] = null;
27 | }
28 |
29 | return $this->data['slug'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Traits/HasIdOrSubscriptionCode.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['subscription_code'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['subscription_code'], $this->data['id'])) {
26 | $this->data['subscription_code'] = null;
27 | }
28 |
29 | return $this->data['subscription_code'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Traits/HasInvoiceIdOrCode.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['request_code'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['request_code'], $this->data['id'])) {
26 | $this->data['request_code'] = null;
27 | }
28 |
29 | return $this->data['request_code'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Traits/HasRecipientCodeOrId.php:
--------------------------------------------------------------------------------
1 | data)) {
14 | $data['id'] = $this->data;
15 | }
16 |
17 | if (is_string($this->data)) {
18 | $data['recipient_code'] = $this->data;
19 | }
20 |
21 | if (!empty($data)) {
22 | $this->data = $data;
23 | }
24 |
25 | if (isset($this->data['recipient_code'], $this->data['id'])) {
26 | $this->data['recipient_code'] = null;
27 | }
28 |
29 | return $this->data['recipient_code'] ?? $this->data['id'] ?? null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/helpers.php:
--------------------------------------------------------------------------------
1 | ');
38 | echo '';
39 | }
40 | }
41 |
42 | if (!function_exists('paystack_mirror_dd'))
43 | {
44 | function paystack_mirror_dd($data) {
45 | paystack_mirror_dump($data);
46 | die();
47 | }
48 | }
--------------------------------------------------------------------------------