Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Payant often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Payant, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class Payant { |
||
28 | |||
29 | |||
30 | /** |
||
31 | * @var $private_key |
||
32 | */ |
||
33 | protected $private_key; |
||
34 | |||
35 | |||
36 | /** |
||
37 | * |
||
38 | * @var $base_uri |
||
39 | * |
||
40 | */ |
||
41 | protected $base_uri = 'https://api.demo.payant.ng'; |
||
42 | |||
43 | |||
44 | /** |
||
45 | * @var $client |
||
46 | * |
||
47 | */ |
||
48 | protected $client; |
||
49 | |||
50 | |||
51 | /** |
||
52 | * [__construct sets the needed variables got from Payant config file] |
||
53 | */ |
||
54 | public function __construct() |
||
55 | { |
||
56 | $this->setKey(); |
||
57 | $this->setBaseUrl(); |
||
58 | $this->setRequestOptions(); |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Get Base Url from Payant config file |
||
63 | */ |
||
64 | public function setBaseUrl() |
||
65 | { |
||
66 | if(Config::get('payant.mode') == 'LIVE') |
||
67 | { |
||
68 | $this->base_uri = "https://api.payant.ng"; |
||
69 | } |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * Get private key from Payant config file |
||
74 | */ |
||
75 | public function setKey() |
||
76 | { |
||
77 | $this->private_key = Config::get('payant.private_key'); |
||
78 | } |
||
79 | |||
80 | |||
81 | /** |
||
82 | * Set options for making the Client request |
||
83 | */ |
||
84 | private function setRequestOptions() |
||
85 | { |
||
86 | $authorization_string = 'Bearer '. $this->private_key; |
||
87 | |||
88 | //Set up Guzzle |
||
89 | $this->client = new Client( [ |
||
90 | 'base_uri' => $this->base_uri, |
||
91 | 'protocols' => ['https'], |
||
92 | 'headers' => [ |
||
93 | 'Authorization' => $authorization_string, |
||
94 | 'Content-Type' => 'application/json', |
||
95 | 'Accept' => 'application/json' |
||
96 | ] |
||
97 | ]); |
||
98 | } |
||
99 | |||
100 | |||
101 | /** |
||
102 | * [getStates Get States in a country (Nigeria)] |
||
103 | * @return [object] [list of banks and their respective bank_ids] |
||
104 | */ |
||
105 | public function getBanks(){ |
||
106 | return $this->sendRequest('get', '/banks'); |
||
107 | } |
||
108 | |||
109 | |||
110 | |||
111 | /** |
||
112 | * [resolveAccount description] |
||
113 | * @param array $client_data [description] |
||
114 | * Required fields - 'settlement_bank', 'account_number' |
||
115 | */ |
||
116 | public function resolveAccount( array $client_data){ |
||
117 | // Mandatory fields |
||
118 | $required_values = ['settlement_bank', 'account_number']; |
||
119 | |||
120 | if(!array_keys_exist($client_data, $required_values)){ |
||
121 | throw new RequiredValuesMissing("Missing required values :("); |
||
122 | } |
||
123 | |||
124 | $url = '/resolve-account'; |
||
125 | |||
126 | return $this->sendRequest('post', $url, ['form_params' => $client_data]); |
||
127 | } |
||
128 | |||
129 | |||
130 | |||
131 | |||
132 | /** |
||
133 | * [addClient description] |
||
134 | * @param array $client_data [description] |
||
135 | * Required fields - 'first_name', 'last_name', 'email', 'phone' |
||
136 | * Optional - 'address', 'company_name', 'type', 'settlement_bank', 'account_number' |
||
137 | */ |
||
138 | public function addClient( array $client_data){ |
||
139 | // Mandatory fields |
||
140 | $required_values = ['first_name', 'last_name', 'email', 'phone']; |
||
141 | |||
142 | if(!array_keys_exist($client_data, $required_values)){ |
||
143 | throw new RequiredValuesMissing("Missing required values :("); |
||
144 | } |
||
145 | |||
146 | $url = '/clients'; |
||
147 | |||
148 | return $this->sendRequest('post', $url, ['form_params' => $client_data]); |
||
149 | } |
||
150 | |||
151 | |||
152 | |||
153 | |||
154 | /** |
||
155 | * [getClient Get client Details] |
||
156 | * @param [string] $client_id |
||
157 | * @return [object] |
||
158 | */ |
||
159 | public function getClient($client_id = null){ |
||
160 | if(!$client_id){ |
||
161 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid Client Id"); |
||
162 | } |
||
163 | |||
164 | $url = "/clients/{$client_id}"; |
||
165 | |||
166 | return $this->sendRequest('get', $url); |
||
167 | } |
||
168 | |||
169 | |||
170 | |||
171 | |||
172 | |||
173 | /** |
||
174 | * [editClient - Edit Existing Client] |
||
175 | * @param [string] $client_id |
||
176 | * @param [array] $client_data |
||
177 | * Required fields - 'first_name', 'last_name', 'email', 'phone' |
||
178 | * Optional - 'address', 'company_name', 'type', 'settlement_bank', 'account_number' |
||
179 | */ |
||
180 | public function editClient( $client_id, array $client_data){ |
||
181 | if(!$client_id){ |
||
182 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid Client Id"); |
||
183 | } |
||
184 | |||
185 | $url = "/clients/{$client_id}"; |
||
186 | |||
187 | // Mandatory fields |
||
188 | $required_values = ['first_name', 'last_name', 'email', 'phone']; |
||
189 | |||
190 | if(!array_keys_exist($client_data, $required_values)){ |
||
191 | throw new RequiredValuesMissing("Missing required values :("); |
||
192 | } |
||
193 | |||
194 | return $this->sendRequest('put', $url, ['form_params' => $client_data]); |
||
195 | } |
||
196 | |||
197 | |||
198 | |||
199 | |||
200 | |||
201 | /** |
||
202 | * [deleteClient] |
||
203 | * @param [string] $client_id [description] |
||
204 | */ |
||
205 | public function deleteClient($client_id = null){ |
||
206 | if(!$client_id){ |
||
207 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid Client Id"); |
||
208 | } |
||
209 | |||
210 | $url = "/clients/{$client_id}"; |
||
211 | |||
212 | return $this->sendRequest('delete', $url); |
||
213 | } |
||
214 | |||
215 | |||
216 | |||
217 | |||
218 | |||
219 | /** |
||
220 | * [addInvoice description] |
||
221 | * @param [string] $client_id [Optional - if client_data is supplied] |
||
222 | * @param array|null $client_data [Optional - if client_id is supplied] |
||
223 | * Required Keys - 'first_name', 'last_name', 'email', 'phone' |
||
224 | * Optional - 'address', 'company_name', 'lga', 'state' |
||
225 | * @param [string] $due_date [Mandatory, Format - DD/MM/YYYY] |
||
226 | * @param [string] $fee_bearer [Mandatory] |
||
227 | * @param array $items [Mandatory] |
||
228 | */ |
||
229 | public function addInvoice($client_id, array $client_data, $due_date, $fee_bearer, array $items){ |
||
230 | // Mandatory Client fields |
||
231 | $required_client_values = ['first_name', 'last_name', 'email', 'phone']; |
||
232 | |||
233 | |||
234 | // Vaild fee_bearer types: 'account' and 'client' |
||
235 | $valid_fee_bearers = ['account', 'client']; |
||
236 | |||
237 | |||
238 | // Either the client Id is supplied or a new client data is provided |
||
239 | if(!$client_id && !array_keys_exist($client_data, $required_client_values)){ |
||
240 | throw new RequiredValuesMissing("Missing required values :( - Provide client_id or client_data"); |
||
241 | } |
||
242 | |||
243 | if(!$due_date){ |
||
244 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid Due Date"); |
||
245 | } |
||
246 | |||
247 | if(!$fee_bearer){ |
||
248 | throw new IsNull("Error Processing Request - Null Fee Bearer"); |
||
249 | }elseif (!in_array($fee_bearer, $valid_fee_bearers)) { |
||
250 | throw new InvalidFeeBearer("Invalid Fee Bearer - Use either 'account' or 'client'"); |
||
251 | } |
||
252 | |||
253 | if(!is_array($items)){ |
||
254 | throw new IsInvalid("Error Processing Request - Invalid Items"); |
||
255 | } |
||
256 | |||
257 | $url = "/invoices"; |
||
258 | |||
259 | $post_data = [ |
||
260 | 'due_date' => $due_date, |
||
261 | 'fee_bearer' => $fee_bearer, |
||
262 | 'items' => $items |
||
263 | ]; |
||
264 | |||
265 | ($client_id) ? $post_data['client_id'] = $client_id : null; |
||
266 | ($client_data) ? $post_data['client'] = $client_data : null; |
||
267 | |||
268 | return $this->sendRequest('post', $url, ['form_params' => $post_data]); |
||
269 | } |
||
270 | |||
271 | |||
272 | |||
273 | |||
274 | /** |
||
275 | * [getInvoice ] |
||
276 | * @param [string] $reference_code [Mandatory - Invoice Reference Code] |
||
277 | * @return [object] |
||
278 | */ |
||
279 | public function getInvoice($reference_code){ |
||
280 | if(!$reference_code){ |
||
281 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid reference_code"); |
||
282 | } |
||
283 | |||
284 | $url = "/invoices/{$reference_code}"; |
||
285 | |||
286 | return $this->sendRequest('get', $url); |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * [sendInvoice] |
||
291 | * @param [type] $reference_code [Mandatory - Invoice Reference Code] |
||
292 | * @return [object] |
||
293 | */ |
||
294 | public function sendInvoice($reference_code = null){ |
||
295 | if(!$reference_code){ |
||
296 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid reference_code"); |
||
297 | } |
||
298 | |||
299 | $url = "/invoices/send/{$reference_code}"; |
||
300 | |||
301 | return $this->sendRequest('get', $url); |
||
302 | } |
||
303 | |||
304 | |||
305 | |||
306 | |||
307 | |||
308 | /** |
||
309 | * [getInvoiceHistory] |
||
310 | * @param [string] $period [Mandatory || Valid Options ["today", "week", "month", "30", "90", "year", "custom"]] |
||
311 | * @param [string] $start [Format - DD/MM/YYYY] |
||
312 | * @param [string] $end [Format - DD/MM/YYYY] |
||
313 | * @return [object] |
||
314 | */ |
||
315 | public function getInvoiceHistory($period, $start = null, $end = null){ |
||
316 | if(!$period){ |
||
317 | throw new RequiredValueMissing("Error Processing Request - period Missing"); |
||
318 | } |
||
319 | |||
320 | //Validate Period |
||
321 | $valid_period_options = ["today", "week", "month", "30", "90", "year", "custom"]; |
||
322 | |||
323 | if (!in_array($period, $valid_period_options)) { |
||
324 | throw new IsInvalid("Invalid Period - Available options: today, week, month, 30, 90, year or custom"); |
||
325 | } |
||
326 | |||
327 | $post_data = [ |
||
328 | 'period' => $period |
||
329 | ]; |
||
330 | |||
331 | if ($period == 'custom'){ |
||
332 | if (!$start || !$end){ |
||
333 | throw new IsNull("Invalid custom Start or End date"); |
||
334 | } |
||
335 | $post_data['start'] = $start; |
||
336 | $post_data['end'] = $end; |
||
337 | } |
||
338 | |||
339 | $url = "/invoices/history"; |
||
340 | |||
341 | return $this->sendRequest('post', $url, ['form_params' => $post_data]); |
||
342 | } |
||
343 | |||
344 | |||
345 | |||
346 | |||
347 | |||
348 | /** |
||
349 | * [deleteInvoice] |
||
350 | * @param [string] $reference_code [Mandatory - Invoice Reference Code] |
||
351 | * @return [object] |
||
352 | */ |
||
353 | public function deleteInvoice($reference_code){ |
||
354 | if(!$reference_code){ |
||
355 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid reference_code"); |
||
356 | } |
||
357 | |||
358 | $url = "/invoices/{$reference_code}"; |
||
359 | |||
360 | return $this->sendRequest('delete', $url); |
||
361 | } |
||
362 | |||
363 | |||
364 | |||
365 | |||
366 | |||
367 | /** |
||
368 | * [addTransfer description] |
||
369 | * @param array $client_data [description] |
||
370 | * Required fields - 'first_name', 'last_name', 'email', 'phone', 'settlement_bank', 'account_number', |
||
371 | * Optional - 'address', 'company_name', 'type', |
||
372 | * @param [string] $amount [Mandatory] |
||
373 | */ |
||
374 | public function addTransfer(array $client_data, string $amount){ |
||
375 | // Mandatory Client fields |
||
376 | $required_client_values = ['first_name', 'last_name', 'email', 'phone', 'settlement_bank', 'account_number']; |
||
377 | |||
378 | if(!array_keys_exist($client_data, $required_client_values)){ |
||
379 | throw new RequiredValuesMissing("Missing required values :( - Provide client_data"); |
||
380 | } |
||
381 | |||
382 | if(!$amount){ |
||
383 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid amount"); |
||
384 | } |
||
385 | |||
386 | $url = "/transfers"; |
||
387 | |||
388 | $post_data[ |
||
389 | 'client' => $client_data, |
||
|
|||
390 | 'amount' => $amount, |
||
391 | ]; |
||
392 | |||
393 | return $this->sendRequest('post', $url, ['form_params' => $post_data]); |
||
394 | } |
||
395 | |||
396 | |||
397 | |||
398 | |||
399 | |||
400 | /** |
||
401 | * [getTransfer ] |
||
402 | * @param [string] $reference_code [Mandatory - Transfer Reference Code] |
||
403 | * @return [object] |
||
404 | */ |
||
405 | public function getTransfer($reference_code){ |
||
406 | if(!$reference_code){ |
||
407 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid reference_code"); |
||
408 | } |
||
409 | |||
410 | $url = "/transfers/{$reference_code}"; |
||
411 | |||
412 | return $this->sendRequest('get', $url); |
||
413 | } |
||
414 | |||
415 | |||
416 | |||
417 | |||
418 | |||
419 | |||
420 | /** |
||
421 | * [getTransferHistory] |
||
422 | * @param [string] $period [Mandatory || Valid Options ["today", "week", "month", "30", "90", "year", "custom"]] |
||
423 | * @param [string] $start [Format - DD/MM/YYYY] |
||
424 | * @param [string] $end [Format - DD/MM/YYYY] |
||
425 | * @return [object] |
||
426 | */ |
||
427 | public function getTransferHistory($period, $start = null, $end = null){ |
||
428 | if(!$period){ |
||
429 | throw new RequiredValueMissing("Error Processing Request - period Missing"); |
||
430 | } |
||
431 | |||
432 | //Validate Period |
||
433 | $valid_period_options = ["today", "week", "month", "30", "90", "year", "custom"]; |
||
434 | |||
435 | if (!in_array($period, $valid_period_options)) { |
||
436 | throw new IsInvalid("Invalid Period - Available options: today, week, month, 30, 90, year or custom"); |
||
437 | } |
||
438 | |||
439 | $post_data = [ |
||
440 | 'period' => $period |
||
441 | ]; |
||
442 | |||
443 | if ($period == 'custom'){ |
||
444 | if (!$start || !$end){ |
||
445 | throw new IsNull("Invalid custom Start or End date"); |
||
446 | } |
||
447 | $post_data['start'] = $start; |
||
448 | $post_data['end'] = $end; |
||
449 | } |
||
450 | |||
451 | $url = "/transfers/history"; |
||
452 | |||
453 | return $this->sendRequest('post', $url, ['form_params' => $post_data]); |
||
454 | } |
||
455 | |||
456 | |||
457 | |||
458 | |||
459 | |||
460 | /** |
||
461 | * [deleteTransfer] |
||
462 | * @param [string] $reference_code [Mandatory - Invoice Reference Code] |
||
463 | * @return [object] |
||
464 | */ |
||
465 | public function deleteTransfer($reference_code){ |
||
466 | if(!$reference_code){ |
||
467 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid reference_code"); |
||
468 | } |
||
469 | |||
470 | $url = "/transfers/{$reference_code}"; |
||
471 | |||
472 | return $this->sendRequest('delete', $url); |
||
473 | } |
||
474 | |||
475 | |||
476 | |||
477 | |||
478 | |||
479 | |||
480 | /** |
||
481 | * [addPayment] |
||
482 | * @param [string] $reference_code [Mandatory - Invoice Reference Code] |
||
483 | * @param [string] $date [Mandatory - [Format - DD/MM/YYYY]] |
||
484 | * @param [string] $amount [Mandatory] |
||
485 | * @param [string] $channel [Mandatory - valid ["Cash", "BankTransfer", "POS", "Cheque"]] |
||
486 | */ |
||
487 | public function addPayment(string $reference_code, string $date, string $amount, string $channel){ |
||
488 | if(!$reference_code){ |
||
489 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid reference_code"); |
||
490 | } |
||
491 | |||
492 | if(!$due_date){ |
||
493 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid date"); |
||
494 | } |
||
495 | |||
496 | if(!$amount){ |
||
497 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid amount"); |
||
498 | } |
||
499 | |||
500 | $valid_channels = ["Cash", "BankTransfer", "POS", "Cheque"]; |
||
501 | |||
502 | if(!$channel){ |
||
503 | throw new IsNull("Error Processing Request - Null/Invalid amount"); |
||
504 | }elseif (!in_array(ucfirst($channel), $valid_channels)) { |
||
505 | throw new IsInvalid("Invalid Channel - Cash, BankTransfer, POS or Cheque"); |
||
506 | } |
||
507 | |||
508 | $url = "/payments"; |
||
509 | |||
510 | $post_data = [ |
||
511 | 'reference_code' => $reference_code, |
||
512 | 'date' => $date, |
||
513 | 'amount' => $amount, |
||
514 | 'channel' => $channel |
||
515 | ]; |
||
516 | |||
517 | return $this->sendRequest('post', $url, ['form_params' => $post_data]); |
||
518 | } |
||
519 | |||
520 | |||
521 | |||
522 | |||
523 | |||
524 | /** |
||
525 | * [getPayment] |
||
526 | * @param [string] $reference_code [Mandatory - Invoice Reference Code] |
||
527 | */ |
||
528 | public function getPayment($reference_code){ |
||
529 | if(!$reference_code){ |
||
530 | throw new IsNullOrInvalid("Error Processing Request - Null/Invalid reference_code"); |
||
531 | } |
||
532 | |||
533 | $url = "/payments/{$reference_code}"; |
||
534 | |||
535 | return $this->sendRequest('get', $url); |
||
536 | } |
||
537 | |||
538 | |||
539 | |||
540 | |||
541 | |||
542 | /** |
||
543 | * [getPaymentHistory] |
||
544 | * @param [string] $period [Mandatory || Valid Options ["today", "week", "month", "30", "90", "year", "custom"]] |
||
545 | * @param [string] $start [Format - DD/MM/YYYY || Optional if $period !== 'custom'] |
||
546 | * @param [string] $end [Format - DD/MM/YYYY || Optional if $period !== 'custom'] |
||
547 | * @return [object] |
||
548 | */ |
||
549 | public function getPaymentHistory(string $period, string $start, string $end){ |
||
550 | if(!$period){ |
||
551 | throw new RequiredValueMissing("Error Processing Request - period Missing"); |
||
552 | } |
||
553 | |||
554 | //Validate Period |
||
555 | $valid_period_options = ["today", "week", "month", "30", "90", "year", "custom"]; |
||
556 | |||
557 | if (!in_array(strtolower($period), $valid_period_options)) { |
||
558 | throw new IsInvalid("Invalid Period - Available options: today, week, month, 30, 90, year or custom"); |
||
559 | } |
||
560 | |||
561 | $post_data = [ |
||
562 | 'period' => $period |
||
563 | ]; |
||
564 | |||
565 | if ($period == 'custom'){ |
||
566 | if (!$start || !$end){ |
||
567 | throw new IsNull("Invalid custom Start or End date"); |
||
568 | } |
||
569 | $post_data['start'] = $start; |
||
570 | $post_data['end'] = $end; |
||
571 | } |
||
572 | |||
573 | $url = "/payments/history"; |
||
574 | |||
575 | return $this->sendRequest('post', $url, ['form_params' => $post_data]); |
||
576 | } |
||
577 | |||
578 | |||
579 | |||
580 | |||
581 | |||
582 | /** |
||
583 | * [addProduct] |
||
584 | * @param string $name [Mandatory - Product's name] |
||
585 | * @param string $description [Mandatory - Product's description] |
||
586 | * @param string $unit_cost [Mandatory - Product's unit cost] |
||
587 | * @param string $type [Mandatory - Product type 'product' or 'service'] |
||
588 | */ |
||
589 | public function addProduct(string $name, string $description, string $unit_cost, string $type){ |
||
590 | if(!$name){ |
||
591 | throw new IsNull("Error Processing Request - Null/Invalid name"); |
||
592 | } |
||
593 | |||
594 | if(!$description){ |
||
595 | throw new IsNull("Error Processing Request - Null/Invalid description"); |
||
596 | } |
||
597 | |||
598 | if(!$unit_cost){ |
||
599 | throw new IsNull("Error Processing Request - Null/Invalid unit_cost"); |
||
600 | } |
||
601 | |||
602 | //Validate Product Type |
||
603 | $valid_product_type = ["product", "service"]; |
||
604 | |||
605 | if(!$type){ |
||
606 | throw new IsNull("Error Processing Request - Null/Invalid type"); |
||
607 | }elseif (!in_array(strtolower($type), $valid_product_type)) { |
||
608 | throw new IsInvalid("Invalid Type - Available options: 'product' or 'service'"); |
||
609 | } |
||
610 | |||
611 | $url = "/products"; |
||
612 | |||
613 | $post_data = [ |
||
614 | 'name' => $name, |
||
615 | 'description' => $description, |
||
616 | 'unit_cost' => $unit_cost, |
||
617 | 'type' => $type |
||
618 | ]; |
||
619 | |||
620 | return $this->sendRequest('post', $url, ['form_params' => $post_data]); |
||
621 | } |
||
622 | |||
623 | |||
624 | |||
625 | |||
626 | |||
739 |