Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
85.71% |
6 / 7 |
CRAP | |
92.86% |
26 / 28 |
InnValidator | |
0.00% |
0 / 1 |
|
85.71% |
6 / 7 |
19.13 | |
92.86% |
26 / 28 |
getDefaultErrorMessages | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
checkValueLength | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
validateValue | |
0.00% |
0 / 1 |
7.39 | |
80.00% |
8 / 10 |
|||
checkN1CheckNumber | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
|||
checkN2CheckNumber | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
calculateCheckSum | |
100.00% |
1 / 1 |
3 | |
100.00% |
5 / 5 |
|||
calculateCheckNumber | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
1 | <?php |
2 | |
3 | namespace shumorkiniv\validators; |
4 | |
5 | |
6 | /** |
7 | * Class InnValidator |
8 | * InnValidator validates that the attribute value is valid INN. |
9 | * |
10 | * Note, this validator should only be used with string-typed or integer-typed attributes. |
11 | * |
12 | * @author Shumorkin Ilya <shumorkinilya@mail.ru> |
13 | */ |
14 | class InnValidator extends RequisitesValidator |
15 | { |
16 | /** @var int Divider for check sum */ |
17 | const DIVIDER = 11; |
18 | /** @var int Index of number wich compare with control */ |
19 | const COMPARED_NUMBER_LEGAL_INDEX = 9; |
20 | /** @var int Index of number wich compare with first control */ |
21 | const COMPARED_NUMBER_INDIVIDUAL_INDEX1 = 10; |
22 | /** @var int Index of number wich compare with second control */ |
23 | const COMPARED_NUMBER_INDIVIDUAL_INDEX2 = 11; |
24 | /** @var int Length of INN for legal entities */ |
25 | const LEGAL_ENTITY_LENGTH = 10; |
26 | /** @var int Length of INN for individuals */ |
27 | const INDIVIDUAL_LENGTH = 12; |
28 | |
29 | /** @var int[] Coefficients for check first check number of 12-digit INN */ |
30 | private const N1_COEFFICIENTS_INDIVIDUAL = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8]; |
31 | /** @var int[] Coefficients for check first check number of 12-digit INN */ |
32 | private const N2_COEFFICIENTS_INDIVIDUAL = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8]; |
33 | /** @var int[] Coefficients for check check number of 10-digit INN */ |
34 | private const N1_COEFFICIENTS_LEGAL_ENTITY = [2, 4, 10, 3, 5, 9, 4, 6, 8]; |
35 | |
36 | /** |
37 | * @inheritdoc |
38 | */ |
39 | protected function getDefaultErrorMessages(): array |
40 | { |
41 | return [ |
42 | 'wrongLength' => 'ИНН должен состоять из 11 или 12 чисел.', |
43 | 'wrongChar' => 'ИНН должен состоять только из цифр.', |
44 | 'invalidValue' => 'Несуществующий ИНН.', |
45 | ]; |
46 | } |
47 | |
48 | /** |
49 | * @inheritdoc |
50 | */ |
51 | protected function checkValueLength(string $value): bool |
52 | { |
53 | return strlen($value) === self::LEGAL_ENTITY_LENGTH || strlen($value) === self::INDIVIDUAL_LENGTH; |
54 | } |
55 | |
56 | /** |
57 | * @inheritdoc |
58 | */ |
59 | protected function validateValue($value): ?array |
60 | { |
61 | $preValidate = $this->preValidate($value); |
62 | |
63 | if (!empty($preValidate)) { |
64 | return $preValidate; |
65 | } |
66 | |
67 | if ($this->length === self::LEGAL_ENTITY_LENGTH) { |
68 | if (!$this->checkN1CheckNumber()) { |
69 | return [$this->message, []]; |
70 | } |
71 | } |
72 | |
73 | if ($this->length === self::INDIVIDUAL_LENGTH) { |
74 | if (!$this->checkN1CheckNumber() || !$this->checkN2CheckNumber()) { |
75 | return [$this->message, []]; |
76 | } |
77 | } |
78 | |
79 | return null; |
80 | } |
81 | |
82 | /** |
83 | * Check of n1 - first check number |
84 | * |
85 | * @return bool |
86 | */ |
87 | private function checkN1CheckNumber(): bool |
88 | { |
89 | $isLegal = $this->length === self::LEGAL_ENTITY_LENGTH; |
90 | |
91 | $coefficients = $isLegal ? self::N1_COEFFICIENTS_LEGAL_ENTITY : self::N1_COEFFICIENTS_INDIVIDUAL; |
92 | $checkNumber = $this->calculateCheckNumber($this->calculateCheckSum($coefficients)); |
93 | |
94 | if ($isLegal) { |
95 | return $checkNumber === $this->numbers[self::COMPARED_NUMBER_LEGAL_INDEX]; |
96 | } |
97 | |
98 | return $checkNumber === $this->numbers[self::COMPARED_NUMBER_INDIVIDUAL_INDEX1]; |
99 | } |
100 | |
101 | /** |
102 | * Check of n2 - seond check number (only for individual) |
103 | * |
104 | * @return bool |
105 | */ |
106 | private function checkN2CheckNumber(): bool |
107 | { |
108 | $checkNumber = $this->calculateCheckNumber($this->calculateCheckSum(self::N2_COEFFICIENTS_INDIVIDUAL)); |
109 | |
110 | return $checkNumber === $this->numbers[self::COMPARED_NUMBER_INDIVIDUAL_INDEX2]; |
111 | } |
112 | |
113 | /** |
114 | * Calculating of check sum |
115 | * |
116 | * @param int[] $coefficients |
117 | * @return int |
118 | */ |
119 | private function calculateCheckSum(array $coefficients): int |
120 | { |
121 | $checkSum = 0; |
122 | |
123 | foreach ($this->numbers as $index => $number) { |
124 | if (isset($coefficients[$index])) { |
125 | $checkSum += $number * $coefficients[$index]; |
126 | } |
127 | } |
128 | |
129 | return $checkSum; |
130 | } |
131 | |
132 | /** |
133 | * Calculating of check number |
134 | * |
135 | * @param int $checkSum |
136 | * @return int |
137 | */ |
138 | private function calculateCheckNumber(int $checkSum): int |
139 | { |
140 | $diff = $checkSum / self::DIVIDER; |
141 | |
142 | $checkNumber = $checkSum - self::DIVIDER * (int)$diff; |
143 | |
144 | return $checkNumber > 9 ? $checkNumber % 10 : $checkNumber; |
145 | } |
146 | } |