1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
|
4
|
|
|
namespace MerchantSafeUnipay\ValueObject; |
5
|
|
|
|
6
|
|
|
use Zend\Validator\CreditCard as CreditCardValidator; |
7
|
|
|
use InvalidArgumentException; |
8
|
|
|
|
9
|
|
|
class CreditCard |
10
|
|
|
{ |
11
|
|
|
private $cardNumber; |
12
|
|
|
private $expireDateMonth; |
13
|
|
|
private $expireDateYear; |
14
|
|
|
private $nameOnCard; |
15
|
|
|
private $cardVerificationVal; |
16
|
|
|
private $cardType; // check values of Zend\Validator\CreditCard::$cardName |
17
|
|
|
|
18
|
|
|
protected static $validCardTypes = [ |
19
|
|
|
'All', |
20
|
|
|
'American_Express', |
21
|
|
|
'Unionpay', |
22
|
|
|
'Diners_Club', |
23
|
|
|
'Diners_Club_US', |
24
|
|
|
'Discover', |
25
|
|
|
'JCB', |
26
|
|
|
'Laser', |
27
|
|
|
'Maestro', |
28
|
|
|
'Mastercard', |
29
|
|
|
'Solo', |
30
|
|
|
'Visa' |
31
|
|
|
]; |
32
|
|
|
|
33
|
|
|
public function __construct( |
34
|
|
|
string $cardNumber, |
35
|
|
|
string $expireDateMonth, |
36
|
|
|
string $expireDateYear, |
37
|
|
|
string $cardVerificationVal, |
38
|
|
|
string $cardType, |
39
|
|
|
string $nameOnCard |
40
|
|
|
) { |
41
|
|
|
|
42
|
|
|
$this->cardNumber = trim($cardNumber); |
43
|
|
|
$this->expireDateMonth = trim($expireDateMonth); |
44
|
|
|
$this->expireDateYear = trim($expireDateYear); |
45
|
|
|
$this->cardVerificationVal = trim($cardVerificationVal); |
46
|
|
|
$this->cardType = trim($cardType); |
47
|
|
|
$this->nameOnCard = trim($nameOnCard); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
public function validate() |
51
|
|
|
{ |
52
|
|
|
$this->validateCardType(); |
53
|
|
|
$this->validateCardNumber(); |
54
|
|
|
$this->validatecardVerificationValue(); |
55
|
|
|
$this->validateNameOnCard(); |
56
|
|
|
$this->validateExpireDates(); |
57
|
|
|
return true; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
private function validateCardType() |
61
|
|
|
{ |
62
|
|
|
if (!in_array($this->cardType, self::$validCardTypes, true)) { |
63
|
|
|
$message = sprintf('%s is not valid card type. See Zend\Validator\CreditCard::$cardName', $this->cardType); |
64
|
|
|
throw new InvalidArgumentException($message); |
65
|
|
|
} |
66
|
|
|
return true; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
private function validateCardNumber() |
70
|
|
|
{ |
71
|
|
|
$valid = new CreditCardValidator($this->cardType); |
72
|
|
|
if (!$valid->isValid($this->cardNumber)) { |
73
|
|
|
$message = sprintf('%s is not valid %s card number.', $this->cardNumber, $this->cardType); |
74
|
|
|
throw new InvalidArgumentException($message); |
75
|
|
|
} |
76
|
|
|
return true; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
private function validatecardVerificationValue() |
80
|
|
|
{ |
81
|
|
View Code Duplication |
if (is_numeric($this->cardVerificationVal) |
|
|
|
|
82
|
|
|
&& $this->cardType === CreditCardValidator::AMERICAN_EXPRESS |
83
|
|
|
&& strlen($this->cardVerificationVal) === 4 |
84
|
|
|
) { |
85
|
|
|
return true; |
86
|
|
|
} |
87
|
|
View Code Duplication |
if (is_numeric($this->cardVerificationVal) |
|
|
|
|
88
|
|
|
&& $this->cardType !== CreditCardValidator::AMERICAN_EXPRESS |
89
|
|
|
&& strlen($this->cardVerificationVal) === 3 |
90
|
|
|
) { |
91
|
|
|
return true; |
92
|
|
|
} |
93
|
|
|
$message = sprintf('%s is not valid CVV.', $this->cardVerificationVal); |
94
|
|
|
throw new InvalidArgumentException($message); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
private function validateNameOnCard() |
98
|
|
|
{ |
99
|
|
|
if (empty(trim($this->nameOnCard))) { |
100
|
|
|
$message = 'Name on card cannot be empty'; |
101
|
|
|
throw new InvalidArgumentException($message); |
102
|
|
|
} |
103
|
|
|
return true; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
private function validateExpireDates() |
107
|
|
|
{ |
108
|
|
|
preg_match('#^0[1-9]|1[012]$#', $this->expireDateMonth, $matches); |
109
|
|
|
if (empty($matches)) { |
110
|
|
|
$message = 'month value of card expire date is not valid.'; |
111
|
|
|
throw new InvalidArgumentException($message); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
if (!is_numeric($this->expireDateYear) |
115
|
|
|
|| strlen($this->expireDateYear) !== 4 |
116
|
|
|
|| $this->expireDateYear < date('Y') |
117
|
|
|
) { |
118
|
|
|
$message = 'Year value of card expire date is not valid.'; |
119
|
|
|
throw new InvalidArgumentException($message); |
120
|
|
|
} |
121
|
|
|
return true; |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.