Completed
Push — master ( 77863b...f57b5c )
by Barry vd.
14:50
created

src/Common/Message/AbstractRequest.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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 5
                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