AbstractRequest   F
last analyzed

Complexity

Total Complexity 71

Size/Duplication

Total Lines 637
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 111
dl 0
loc 637
ccs 150
cts 150
cp 1
rs 2.7199
c 2
b 0
f 0
wmc 71

45 Methods

Rating   Name   Duplication   Size   Complexity  
A getAmountInteger() 0 6 2
A setTransactionReference() 0 3 1
A setItems() 0 7 3
A getCard() 0 3 1
A getCurrencies() 0 7 2
A initialize() 0 11 2
A getCurrencyNumeric() 0 10 3
A setCard() 0 7 3
A getTestMode() 0 3 1
A getPaymentMethod() 0 3 1
A setTransactionId() 0 3 1
A setCancelUrl() 0 3 1
A getToken() 0 3 1
A setReturnUrl() 0 3 1
A getCardReference() 0 3 1
A setToken() 0 3 1
A setDescription() 0 3 1
A send() 0 5 1
A getCurrencyDecimalPlaces() 0 10 3
B getMoney() 0 39 11
A getIssuer() 0 3 1
A getCurrency() 0 3 1
A setNotifyUrl() 0 3 1
A setPaymentMethod() 0 3 1
A setCardReference() 0 3 1
A __construct() 0 5 1
A getTransactionReference() 0 3 1
A getCancelUrl() 0 3 1
A getResponse() 0 7 2
A setCurrency() 0 6 2
A getTransactionId() 0 3 1
A setAmount() 0 3 2
A getAmount() 0 8 2
A setParameter() 0 7 2
A getDescription() 0 3 1
A setMoney() 0 7 1
A getReturnUrl() 0 3 1
A setAmountInteger() 0 3 1
A getNotifyUrl() 0 3 1
A getClientIp() 0 3 1
A getItems() 0 3 1
A formatCurrency() 0 6 1
A setTestMode() 0 3 1
A setClientIp() 0 3 1
A setIssuer() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractRequest 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.

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 AbstractRequest, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Abstract Request
4
 */
5
6
namespace Omnipay\Common\Message;
7
8
use Money\Currencies\ISOCurrencies;
9
use Money\Currency;
10
use Money\Formatter\DecimalMoneyFormatter;
11
use Money\Money;
12
use Money\Number;
13
use Money\Parser\DecimalMoneyParser;
14
use Omnipay\Common\CreditCard;
15
use Omnipay\Common\Exception\InvalidRequestException;
16
use Omnipay\Common\Exception\RuntimeException;
17
use Omnipay\Common\Helper;
18
use Omnipay\Common\Http\Client;
19
use Omnipay\Common\Http\ClientInterface;
20
use Omnipay\Common\ItemBag;
21
use Omnipay\Common\ParametersTrait;
22
use Symfony\Component\HttpFoundation\ParameterBag;
23
use Symfony\Component\HttpFoundation\Request as HttpRequest;
24
25
/**
26
 * Abstract Request
27
 *
28
 * This abstract class implements RequestInterface and defines a basic
29
 * set of functions that all Omnipay Requests are intended to include.
30
 *
31
 * Requests of this class are usually created using the createRequest
32
 * function of the gateway and then actioned using methods within this
33
 * class or a class that extends this class.
34
 *
35
 * Example -- creating a request:
36
 *
37
 * <code>
38
 *   class MyRequest extends \Omnipay\Common\Message\AbstractRequest {};
39
 *
40
 *   class MyGateway extends \Omnipay\Common\AbstractGateway {
41
 *     function myRequest($parameters) {
42
 *       $this->createRequest('MyRequest', $parameters);
43
 *     }
44
 *   }
45
 *
46
 *   // Create the gateway object
47
 *   $gw = Omnipay::create('MyGateway');
48
 *
49
 *   // Create the request object
50
 *   $myRequest = $gw->myRequest($someParameters);
51
 * </code>
52
 *
53
 * Example -- validating and sending a request:
54
 *
55
 * <code>
56
 *   try {
57
 *     $myRequest->validate();
58
 *     $myResponse = $myRequest->send();
59
 *   } catch (InvalidRequestException $e) {
60
 *     print "Something went wrong: " . $e->getMessage() . "\n";
61
 *   }
62
 *   // now do something with the $myResponse object, test for success, etc.
63
 * </code>
64
 *
65
 */
66
abstract class AbstractRequest implements RequestInterface
67
{
68
    use ParametersTrait {
69
        setParameter as traitSetParameter;
70
    }
71
72
    /**
73
     * The request client.
74
     *
75
     * @var ClientInterface
76
     */
77
    protected $httpClient;
78
79
    /**
80
     * The HTTP request object.
81
     *
82
     * @var \Symfony\Component\HttpFoundation\Request
83
     */
84
    protected $httpRequest;
85
86
    /**
87
     * An associated ResponseInterface.
88
     *
89
     * @var ResponseInterface
90
     */
91
    protected $response;
92
93
    /**
94
     * @var ISOCurrencies
95
     */
96
    protected $currencies;
97
98
    /**
99
     * @var bool
100
     */
101
    protected $zeroAmountAllowed = true;
102
103
    /**
104
     * @var bool
105
     */
106
    protected $negativeAmountAllowed = false;
107
108
    /**
109
     * Create a new Request
110
     *
111
     * @param ClientInterface $httpClient  A HTTP client to make API calls with
112
     * @param HttpRequest     $httpRequest A Symfony HTTP request object
113
     */
114 177
    public function __construct(ClientInterface $httpClient, HttpRequest $httpRequest)
115
    {
116 177
        $this->httpClient = $httpClient;
117 177
        $this->httpRequest = $httpRequest;
118 177
        $this->initialize();
119 177
    }
120
121
    /**
122
     * Initialize the object with parameters.
123
     *
124
     * If any unknown parameters passed, they will be ignored.
125
     *
126
     * @param array $parameters An associative array of parameters
127
     *
128
     * @return $this
129
     * @throws RuntimeException
130
     */
131 177
    public function initialize(array $parameters = array())
132
    {
133 177
        if (null !== $this->response) {
134 3
            throw new RuntimeException('Request cannot be modified after it has been sent!');
135
        }
136
137 177
        $this->parameters = new ParameterBag;
138
139 177
        Helper::initialize($this, $parameters);
140
141 177
        return $this;
142
    }
143
144
    /**
145
     * Set a single parameter
146
     *
147
     * @param string $key The parameter key
148
     * @param mixed $value The value to set
149
     * @return $this
150
     * @throws RuntimeException if a request parameter is modified after the request has been sent.
151
     */
152 153
    protected function setParameter($key, $value)
153
    {
154 153
        if (null !== $this->response) {
155 3
            throw new RuntimeException('Request cannot be modified after it has been sent!');
156
        }
157
158 150
        return $this->traitSetParameter($key, $value);
159
    }
160
161
    /**
162
     * Gets the test mode of the request from the gateway.
163
     *
164
     * @return boolean
165
     */
166 3
    public function getTestMode()
167
    {
168 3
        return $this->getParameter('testMode');
169
    }
170
171
    /**
172
     * Sets the test mode of the request.
173
     *
174
     * @param boolean $value True for test mode on.
175
     * @return $this
176
     */
177 12
    public function setTestMode($value)
178
    {
179 12
        return $this->setParameter('testMode', $value);
180
    }
181
182
    /**
183
     * Get the card.
184
     *
185
     * @return CreditCard
186
     */
187 6
    public function getCard()
188
    {
189 6
        return $this->getParameter('card');
190
    }
191
192
    /**
193
     * Sets the card.
194
     *
195
     * @param CreditCard $value
196
     * @return $this
197
     */
198 6
    public function setCard($value)
199
    {
200 6
        if ($value && !$value instanceof CreditCard) {
0 ignored issues
show
introduced by
$value is always a sub-type of Omnipay\Common\CreditCard.
Loading history...
201 3
            $value = new CreditCard($value);
202
        }
203
204 6
        return $this->setParameter('card', $value);
205
    }
206
207
    /**
208
     * Get the card token.
209
     *
210
     * @return string
211
     */
212 3
    public function getToken()
213
    {
214 3
        return $this->getParameter('token');
215
    }
216
217
    /**
218
     * Sets the card token.
219
     *
220
     * @param string $value
221
     * @return $this
222
     */
223 9
    public function setToken($value)
224
    {
225 9
        return $this->setParameter('token', $value);
226
    }
227
228
    /**
229
     * Get the card reference.
230
     *
231
     * @return string
232
     */
233 3
    public function getCardReference()
234
    {
235 3
        return $this->getParameter('cardReference');
236
    }
237
238
    /**
239
     * Sets the card reference.
240
     *
241
     * @param string $value
242
     * @return $this
243
     */
244 3
    public function setCardReference($value)
245
    {
246 3
        return $this->setParameter('cardReference', $value);
247
    }
248
249
    /**
250
     * @return ISOCurrencies
251
     */
252 72
    protected function getCurrencies()
253
    {
254 72
        if ($this->currencies === null) {
255 72
            $this->currencies = new ISOCurrencies();
256
        }
257
258 72
        return $this->currencies;
259
    }
260
261
    /**
262
     * @param  string|int|null $amount
263
     * @return null|Money
264
     * @throws InvalidRequestException
265
     */
266 69
    private function getMoney($amount = null)
267
    {
268 69
        $currencyCode = $this->getCurrency() ?: 'USD';
269 69
        $currency = new Currency($currencyCode);
270
271 69
        $amount = $amount !== null ? $amount : $this->getParameter('amount');
272
273 69
        if ($amount === null) {
274 6
            return null;
275 63
        } elseif ($amount instanceof Money) {
276 3
            $money = $amount;
277 60
        } elseif (is_integer($amount)) {
278 3
            $money = new Money($amount, $currency);
279
        } else {
280 57
            $moneyParser = new DecimalMoneyParser($this->getCurrencies());
281
282 57
            $number = Number::fromString($amount);
283
284
            // Check for rounding that may occur if too many significant decimal digits are supplied.
285 51
            $decimal_count = strlen($number->getFractionalPart());
286 51
            $subunit = $this->getCurrencies()->subunitFor($currency);
287 51
            if ($decimal_count > $subunit) {
288 6
                throw new InvalidRequestException('Amount precision is too high for currency.');
289
            }
290
291 45
            $money = $moneyParser->parse((string) $number, $currency);
292
        }
293
294
        // Check for a negative amount.
295 51
        if (!$this->negativeAmountAllowed && $money->isNegative()) {
296 6
            throw new InvalidRequestException('A negative amount is not allowed.');
297
        }
298
299
        // Check for a zero amount.
300 45
        if (!$this->zeroAmountAllowed && $money->isZero()) {
301 3
            throw new InvalidRequestException('A zero amount is not allowed.');
302
        }
303
304 42
        return $money;
305
    }
306
307
    /**
308
     * Validates and returns the formatted amount.
309
     *
310
     * @throws InvalidRequestException on any validation failure.
311
     * @return string The amount formatted to the correct number of decimal places for the selected currency.
312
     */
313 54
    public function getAmount()
314
    {
315 54
        $money = $this->getMoney();
316
317 33
        if ($money !== null) {
318 30
            $moneyFormatter = new DecimalMoneyFormatter($this->getCurrencies());
319
320 30
            return $moneyFormatter->format($money);
321
        }
322 3
    }
323
324
    /**
325
     * Sets the payment amount.
326
     *
327
     * @param string|null $value
328
     * @return $this
329
     */
330 57
    public function setAmount($value)
331
    {
332 57
        return $this->setParameter('amount', $value !== null ? (string) $value : null);
333
    }
334
335
    /**
336
     * Get the payment amount as an integer.
337
     *
338
     * @return integer
339
     */
340 15
    public function getAmountInteger()
341
    {
342 15
        $money = $this->getMoney();
343
344 15
        if ($money !== null) {
345 12
            return (int) $money->getAmount();
346
        }
347 3
    }
348
349
    /**
350
     * Sets the payment amount as integer.
351
     *
352
     * @param int $value
353
     * @return $this
354
     */
355 6
    public function setAmountInteger($value)
356
    {
357 6
        return $this->setParameter('amount', (int) $value);
358
    }
359
360
    /**
361
     * Sets the payment amount as integer.
362
     *
363
     * @param Money $value
364
     * @return $this
365
     */
366 3
    public function setMoney(Money $value)
367
    {
368 3
        $currency = $value->getCurrency()->getCode();
369
370 3
        $this->setCurrency($currency);
371
372 3
        return $this->setParameter('amount', $value);
373
    }
374
375
    /**
376
     * Get the payment currency code.
377
     *
378
     * @return string
379
     */
380 96
    public function getCurrency()
381
    {
382 96
        return $this->getParameter('currency');
383
    }
384
385
    /**
386
     * Sets the payment currency code.
387
     *
388
     * @param string $value
389
     * @return $this
390
     */
391 45
    public function setCurrency($value)
392
    {
393 45
        if ($value !== null) {
0 ignored issues
show
introduced by
The condition $value !== null is always true.
Loading history...
394 39
            $value = strtoupper($value);
395
        }
396 45
        return $this->setParameter('currency', $value);
397
    }
398
399
    /**
400
     * Get the payment currency number.
401
     *
402
     * @return string|null
403
     */
404 12
    public function getCurrencyNumeric()
405
    {
406 12
        if (! $this->getCurrency()) {
407 6
            return null;
408
        }
409
410 6
        $currency = new Currency($this->getCurrency());
411
412 6
        if ($this->getCurrencies()->contains($currency)) {
413 3
            return (string) $this->getCurrencies()->numericCodeFor($currency);
414
        }
415 3
    }
416
417
    /**
418
     * Get the number of decimal places in the payment currency.
419
     *
420
     * @return integer
421
     */
422 6
    public function getCurrencyDecimalPlaces()
423
    {
424 6
        if ($this->getCurrency()) {
425 3
            $currency = new Currency($this->getCurrency());
426 3
            if ($this->getCurrencies()->contains($currency)) {
427 3
                return $this->getCurrencies()->subunitFor($currency);
428
            }
429
        }
430
431 3
        return 2;
432
    }
433
434
    /**
435
     * Format an amount for the payment currency.
436
     *
437
     * @param string $amount
438
     * @return string
439
     */
440 6
    public function formatCurrency($amount)
441
    {
442 6
        $money = $this->getMoney((string) $amount);
443 6
        $formatter = new DecimalMoneyFormatter($this->getCurrencies());
444
445 6
        return $formatter->format($money);
446
    }
447
448
    /**
449
     * Get the request description.
450
     *
451
     * @return string
452
     */
453 3
    public function getDescription()
454
    {
455 3
        return $this->getParameter('description');
456
    }
457
458
    /**
459
     * Sets the request description.
460
     *
461
     * @param string $value
462
     * @return $this
463
     */
464 3
    public function setDescription($value)
465
    {
466 3
        return $this->setParameter('description', $value);
467
    }
468
469
    /**
470
     * Get the transaction ID.
471
     *
472
     * The transaction ID is the identifier generated by the merchant website.
473
     *
474
     * @return string
475
     */
476 3
    public function getTransactionId()
477
    {
478 3
        return $this->getParameter('transactionId');
479
    }
480
481
    /**
482
     * Sets the transaction ID.
483
     *
484
     * @param string $value
485
     * @return $this
486
     */
487 3
    public function setTransactionId($value)
488
    {
489 3
        return $this->setParameter('transactionId', $value);
490
    }
491
492
    /**
493
     * Get the transaction reference.
494
     *
495
     * The transaction reference is the identifier generated by the remote
496
     * payment gateway.
497
     *
498
     * @return string
499
     */
500 3
    public function getTransactionReference()
501
    {
502 3
        return $this->getParameter('transactionReference');
503
    }
504
505
    /**
506
     * Sets the transaction reference.
507
     *
508
     * @param string $value
509
     * @return $this
510
     */
511 3
    public function setTransactionReference($value)
512
    {
513 3
        return $this->setParameter('transactionReference', $value);
514
    }
515
516
    /**
517
     * A list of items in this order
518
     *
519
     * @return ItemBag|null A bag containing items in this order
520
     */
521 6
    public function getItems()
522
    {
523 6
        return $this->getParameter('items');
524
    }
525
526
    /**
527
     * Set the items in this order
528
     *
529
     * @param ItemBag|array $items An array of items in this order
530
     * @return $this
531
     */
532 6
    public function setItems($items)
533
    {
534 6
        if ($items && !$items instanceof ItemBag) {
535 3
            $items = new ItemBag($items);
536
        }
537
538 6
        return $this->setParameter('items', $items);
539
    }
540
541
    /**
542
     * Get the client IP address.
543
     *
544
     * @return string
545
     */
546 3
    public function getClientIp()
547
    {
548 3
        return $this->getParameter('clientIp');
549
    }
550
551
    /**
552
     * Sets the client IP address.
553
     *
554
     * @param string $value
555
     * @return $this
556
     */
557 3
    public function setClientIp($value)
558
    {
559 3
        return $this->setParameter('clientIp', $value);
560
    }
561
562
    /**
563
     * Get the request return URL.
564
     *
565
     * @return string
566
     */
567 3
    public function getReturnUrl()
568
    {
569 3
        return $this->getParameter('returnUrl');
570
    }
571
572
    /**
573
     * Sets the request return URL.
574
     *
575
     * @param string $value
576
     * @return $this
577
     */
578 3
    public function setReturnUrl($value)
579
    {
580 3
        return $this->setParameter('returnUrl', $value);
581
    }
582
583
    /**
584
     * Get the request cancel URL.
585
     *
586
     * @return string
587
     */
588 3
    public function getCancelUrl()
589
    {
590 3
        return $this->getParameter('cancelUrl');
591
    }
592
593
    /**
594
     * Sets the request cancel URL.
595
     *
596
     * @param string $value
597
     * @return $this
598
     */
599 3
    public function setCancelUrl($value)
600
    {
601 3
        return $this->setParameter('cancelUrl', $value);
602
    }
603
604
    /**
605
     * Get the request notify URL.
606
     *
607
     * @return string
608
     */
609 3
    public function getNotifyUrl()
610
    {
611 3
        return $this->getParameter('notifyUrl');
612
    }
613
614
    /**
615
     * Sets the request notify URL.
616
     *
617
     * @param string $value
618
     * @return $this
619
     */
620 3
    public function setNotifyUrl($value)
621
    {
622 3
        return $this->setParameter('notifyUrl', $value);
623
    }
624
625
    /**
626
     * Get the payment issuer.
627
     *
628
     * This field is used by some European gateways, and normally represents
629
     * the bank where an account is held (separate from the card brand).
630
     *
631
     * @return string
632
     */
633 3
    public function getIssuer()
634
    {
635 3
        return $this->getParameter('issuer');
636
    }
637
638
    /**
639
     * Set the payment issuer.
640
     *
641
     * This field is used by some European gateways, and normally represents
642
     * the bank where an account is held (separate from the card brand).
643
     *
644
     * @param string $value
645
     * @return $this
646
     */
647 3
    public function setIssuer($value)
648
    {
649 3
        return $this->setParameter('issuer', $value);
650
    }
651
652
    /**
653
     * Get the payment issuer.
654
     *
655
     * This field is used by some European gateways, which support
656
     * multiple payment providers with a single API.
657
     *
658
     * @return string
659
     */
660 3
    public function getPaymentMethod()
661
    {
662 3
        return $this->getParameter('paymentMethod');
663
    }
664
665
    /**
666
     * Set the payment method.
667
     *
668
     * This field is used by some European gateways, which support
669
     * multiple payment providers with a single API.
670
     *
671
     * @param string $value
672
     * @return $this
673
     */
674 3
    public function setPaymentMethod($value)
675
    {
676 3
        return $this->setParameter('paymentMethod', $value);
677
    }
678
679
    /**
680
     * Send the request
681
     *
682
     * @return ResponseInterface
683
     */
684 12
    public function send()
685
    {
686 12
        $data = $this->getData();
687
688 12
        return $this->sendData($data);
689
    }
690
691
    /**
692
     * Get the associated Response.
693
     *
694
     * @return ResponseInterface
695
     */
696 6
    public function getResponse()
697
    {
698 6
        if (null === $this->response) {
699 3
            throw new RuntimeException('You must call send() before accessing the Response!');
700
        }
701
702 3
        return $this->response;
703
    }
704
}
705