Completed
Push — master ( 24a2f1...d4fcc4 )
by Barry vd.
02:09
created

AbstractRequest::getMoney()   D

Complexity

Conditions 9
Paths 10

Size

Total Lines 37
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 9.0101

Importance

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