Completed
Pull Request — master (#20)
by Davide
01:27
created

Validator::replaceOmocodiaSection()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 9
cts 9
cp 1
rs 9.9
c 0
b 0
f 0
cc 4
nc 3
nop 4
crap 4
1
<?php
2
3
namespace CodiceFiscale;
4
5
/**
6
 * Description of Validator
7
 *
8
 * @author Antonio Turdo <[email protected]>
9
 * @author davidepastore
10
 */
11
class Validator extends AbstractCalculator
12
{
13
    private $regexs = array(
14
        0 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z][0-9]{3}[a-z]$/i', //RSSMRA85T10A562S
15
        1 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z][0-9]{2}[a-z]{2}$/i', //RSSMRA85T10A56NH
16
        2 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRA85T10A5S2E
17
        3 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z][0-9][a-z]{3}$/i', //RSSMRA85T10A5SNT
18
        4 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRA85T10AR62N
19
        5 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z]{2}[0-9][a-z]{2}$/i', //RSSMRA85T10AR6NC
20
        6 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z]{3}[0-9][a-z]$/i', //RSSMRA85T10ARS2Z
21
        7 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z]{5}$/i', //RSSMRA85T10ARSNO
22
        8 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{2}[0-9]{3}[a-z]$/i', //RSSMRA85T1LA562V
23
        9 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{2}[0-9]{2}[a-z]{2}$/i', //RSSMRA85T1LA56NK
24
        10 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{2}[0-9][a-z][0-9][a-z]$/i', //RSSMRA85T1LA5S2H
25
        11 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{2}[0-9][a-z]{3}$/i', //RSSMRA85T1LA5SNW
26
        12 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{3}[0-9]{2}[a-z]$/i', //RSSMRA85T1LAR62Q
27
        13 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{3}[0-9][a-z]{2}$/i', //RSSMRA85T1LAR6NF
28
        14 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{4}[0-9][a-z]$/i', //RSSMRA85T1LARS2C
29
        15 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{6}$/i', //RSSMRA85T1LARSNR
30
        16 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z][0-9]{3}[a-z]$/i', //RSSMRA85TM0A562D
31
        17 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z][0-9]{2}[a-z]{2}$/i', //RSSMRA85TM0A56NS
32
        18 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRA85TM0A5S2P
33
        19 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z][0-9][a-z]{3}$/i', //RSSMRA85TM0A5SNE
34
        20 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRA85TM0AR62Y
35
        21 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z]{2}[0-9][a-z]{2}$/i', //RSSMRA85TM0AR6NN
36
        22 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z]{3}[0-9][a-z]$/i', //RSSMRA85TM0ARS2K
37
        23 => '/^[a-z]{6}[0-9]{2}[a-z]{2}[0-9][a-z]{5}$/i', //RSSMRA85TM0ARSNZ
38
        24 => '/^[a-z]{6}[0-9]{2}[a-z]{4}[0-9]{3}[a-z]$/i', //RSSMRA85TMLA562G
39
        25 => '/^[a-z]{6}[0-9]{2}[a-z]{4}[0-9]{2}[a-z]{2}$/i', //RSSMRA85TMLA56NV
40
        26 => '/^[a-z]{6}[0-9]{2}[a-z]{4}[0-9][a-z][0-9][a-z]$/i', //RSSMRA85TMLA5S2S
41
        27 => '/^[a-z]{6}[0-9]{2}[a-z]{4}[0-9][a-z]{3}$/i', //RSSMRA85TMLA5SNH
42
        28 => '/^[a-z]{6}[0-9]{2}[a-z]{5}[0-9]{2}[a-z]$/i', //RSSMRA85TMLAR62B
43
        29 => '/^[a-z]{6}[0-9]{2}[a-z]{5}[0-9][a-z]{2}$/i', //RSSMRA85TMLAR6NQ
44
        30 => '/^[a-z]{6}[0-9]{2}[a-z]{6}[0-9][a-z]$/i', //RSSMRA85TMLARS2N
45
        31 => '/^[a-z]{6}[0-9]{2}[a-z]{8}$/i', //RSSMRA85TMLARSNC
46
        32 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z][0-9]{3}[a-z]$/i', //RSSMRA8RT10A562E
47
        33 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z][0-9]{2}[a-z]{2}$/i', //RSSMRA8RT10A56NT
48
        34 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRA8RT10A5S2Q
49
        35 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z][0-9][a-z]{3}$/i', //RSSMRA8RT10A5SNF
50
        36 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRA8RT10AR62Z
51
        37 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z]{2}[0-9][a-z]{2}$/i', //RSSMRA8RT10AR6NO
52
        38 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z]{3}[0-9][a-z]$/i', //RSSMRA8RT10ARS2L
53
        39 => '/^[a-z]{6}[0-9][a-z]{2}[0-9]{2}[a-z]{5}$/i', //RSSMRA8RT10ARSNA
54
        40 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{2}[0-9]{3}[a-z]$/i', //RSSMRA8RT1LA562H
55
        41 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{2}[0-9]{2}[a-z]{2}$/i', //RSSMRA8RT1LA56NW
56
        42 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{2}[0-9][a-z][0-9][a-z]$/i', //RSSMRA8RT1LA5S2T
57
        43 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{2}[0-9][a-z]{3}$/i', //RSSMRA8RT1LA5SNI
58
        44 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{3}[0-9]{2}[a-z]$/i', //RSSMRA8RT1LAR62C
59
        45 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{3}[0-9][a-z]{2}$/i', //RSSMRA8RT1LAR6NR
60
        46 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{4}[0-9][a-z]$/i', //RSSMRA8RT1LARS2O
61
        47 => '/^[a-z]{6}[0-9][a-z]{2}[0-9][a-z]{6}$/i', //RSSMRA8RT1LARSND
62
        48 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z][0-9]{3}[a-z]$/i', //RSSMRA8RTM0A562P
63
        49 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z][0-9]{2}[a-z]{2}$/i', //RSSMRA8RTM0A56NE
64
        50 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRA8RTM0A5S2B
65
        51 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z][0-9][a-z]{3}$/i', //RSSMRA8RTM0A5SNQ
66
        52 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRA8RTM0AR62K
67
        53 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z]{2}[0-9][a-z]{2}$/i', //RSSMRA8RTM0AR6NZ
68
        54 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z]{3}[0-9][a-z]$/i', //RSSMRA8RTM0ARS2W
69
        55 => '/^[a-z]{6}[0-9][a-z]{3}[0-9][a-z]{5}$/i', //RSSMRA8RTM0ARSNL
70
        56 => '/^[a-z]{6}[0-9][a-z]{5}[0-9]{3}[a-z]$/i', //RSSMRA8RTMLA562S
71
        57 => '/^[a-z]{6}[0-9][a-z]{5}[0-9]{2}[a-z]{2}$/i', //RSSMRA8RTMLA56NH
72
        58 => '/^[a-z]{6}[0-9][a-z]{5}[0-9][a-z][0-9][a-z]$/i', //RSSMRA8RTMLA5S2E
73
        59 => '/^[a-z]{6}[0-9][a-z]{5}[0-9][a-z]{3}$/i', //RSSMRA8RTMLA5SNT
74
        60 => '/^[a-z]{6}[0-9][a-z]{6}[0-9]{2}[a-z]$/i', //RSSMRA8RTMLAR62N
75
        61 => '/^[a-z]{6}[0-9][a-z]{6}[0-9][a-z]{2}$/i', //RSSMRA8RTMLAR6NC
76
        62 => '/^[a-z]{6}[0-9][a-z]{7}[0-9][a-z]$/i', //RSSMRA8RTMLARS2Z
77
        63 => '/^[a-z]{6}[0-9][a-z]{9}$/i', //RSSMRA8RTMLARSNO
78
        64 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z][0-9]{3}[a-z]$/i', //RSSMRAU5T10A562P
79
        65 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z][0-9]{2}[a-z]{2}$/i', //RSSMRAU5T10A56NE
80
        66 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRAU5T10A5S2B
81
        67 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z][0-9][a-z]{3}$/i', //RSSMRAU5T10A5SNQ
82
        68 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRAU5T10AR62K
83
        69 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z]{2}[0-9][a-z]{2}$/i', //RSSMRAU5T10AR6NZ
84
        70 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z]{3}[0-9][a-z]$/i', //RSSMRAU5T10ARS2W
85
        71 => '/^[a-z]{7}[0-9][a-z][0-9]{2}[a-z]{5}$/i', //RSSMRAU5T10ARSNL
86
        72 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{2}[0-9]{3}[a-z]$/i', //RSSMRAU5T1LA562S
87
        73 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{2}[0-9]{2}[a-z]{2}$/i', //RSSMRAU5T1LA56NH
88
        74 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{2}[0-9][a-z][0-9][a-z]$/i', //RSSMRAU5T1LA5S2E
89
        75 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{2}[0-9][a-z]{3}$/i', //RSSMRAU5T1LA5SNT
90
        76 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{3}[0-9]{2}[a-z]$/i', //RSSMRAU5T1LAR62N
91
        77 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{3}[0-9][a-z]{2}$/i', //RSSMRAU5T1LAR6NC
92
        78 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{4}[0-9][a-z]$/i', //RSSMRAU5T1LARS2Z
93
        79 => '/^[a-z]{7}[0-9][a-z][0-9][a-z]{6}$/i', //RSSMRAU5T1LARSNO
94
        80 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z][0-9]{3}[a-z]$/i', //RSSMRAU5TM0A562A
95
        81 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z][0-9]{2}[a-z]{2}$/i', //RSSMRAU5TM0A56NP
96
        82 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRAU5TM0A5S2M
97
        83 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z][0-9][a-z]{3}$/i', //RSSMRAU5TM0A5SNB
98
        84 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRAU5TM0AR62V
99
        85 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z]{2}[0-9][a-z]{2}$/i', //RSSMRAU5TM0AR6NK
100
        86 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z]{3}[0-9][a-z]$/i', //RSSMRAU5TM0ARS2H
101
        87 => '/^[a-z]{7}[0-9][a-z]{2}[0-9][a-z]{5}$/i', //RSSMRAU5TM0ARSNW
102
        88 => '/^[a-z]{7}[0-9][a-z]{4}[0-9]{3}[a-z]$/i', //RSSMRAU5TMLA562D
103
        89 => '/^[a-z]{7}[0-9][a-z]{4}[0-9]{2}[a-z]{2}$/i', //RSSMRAU5TMLA56NS
104
        90 => '/^[a-z]{7}[0-9][a-z]{4}[0-9][a-z][0-9][a-z]$/i', //RSSMRAU5TMLA5S2P
105
        91 => '/^[a-z]{7}[0-9][a-z]{4}[0-9][a-z]{3}$/i', //RSSMRAU5TMLA5SNE
106
        92 => '/^[a-z]{7}[0-9][a-z]{5}[0-9]{2}[a-z]$/i', //RSSMRAU5TMLAR62Y
107
        93 => '/^[a-z]{7}[0-9][a-z]{5}[0-9][a-z]{2}$/i', //RSSMRAU5TMLAR6NN
108
        94 => '/^[a-z]{7}[0-9][a-z]{6}[0-9][a-z]$/i', //RSSMRAU5TMLARS2K
109
        95 => '/^[a-z]{7}[0-9][a-z]{8}$/i', //RSSMRAU5TMLARSNZ
110
        96 => '/^[a-z]{9}[0-9]{2}[a-z][0-9]{3}[a-z]$/i', //RSSMRAURT10A562B
111
        97 => '/^[a-z]{9}[0-9]{2}[a-z][0-9]{2}[a-z]{2}$/i', //RSSMRAURT10A56NQ
112
        98 => '/^[a-z]{9}[0-9]{2}[a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRAURT10A5S2N
113
        99 => '/^[a-z]{9}[0-9]{2}[a-z][0-9][a-z]{3}$/i', //RSSMRAURT10A5SNC
114
        100 => '/^[a-z]{9}[0-9]{2}[a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRAURT10AR62W
115
        101 => '/^[a-z]{9}[0-9]{2}[a-z]{2}[0-9][a-z]{2}$/i', //RSSMRAURT10AR6NL
116
        102 => '/^[a-z]{9}[0-9]{2}[a-z]{3}[0-9][a-z]$/i', //RSSMRAURT10ARS2I
117
        103 => '/^[a-z]{9}[0-9]{2}[a-z]{5}$/i', //RSSMRAURT10ARSNX
118
        104 => '/^[a-z]{9}[0-9][a-z]{2}[0-9]{3}[a-z]$/i', //RSSMRAURT1LA562E
119
        105 => '/^[a-z]{9}[0-9][a-z]{2}[0-9]{2}[a-z]{2}$/i', //RSSMRAURT1LA56NT
120
        106 => '/^[a-z]{9}[0-9][a-z]{2}[0-9][a-z][0-9][a-z]$/i', //RSSMRAURT1LA5S2Q
121
        107 => '/^[a-z]{9}[0-9][a-z]{2}[0-9][a-z]{3}$/i', //RSSMRAURT1LA5SNF
122
        108 => '/^[a-z]{9}[0-9][a-z]{3}[0-9]{2}[a-z]$/i', //RSSMRAURT1LAR62Z
123
        109 => '/^[a-z]{9}[0-9][a-z]{3}[0-9][a-z]{2}$/i', //RSSMRAURT1LAR6NO
124
        110 => '/^[a-z]{9}[0-9][a-z]{4}[0-9][a-z]$/i', //RSSMRAURT1LARS2L
125
        111 => '/^[a-z]{9}[0-9][a-z]{6}$/i', //RSSMRAURT1LARSNA
126
        112 => '/^[a-z]{10}[0-9][a-z][0-9]{3}[a-z]$/i', //RSSMRAURTM0A562M
127
        113 => '/^[a-z]{10}[0-9][a-z][0-9]{2}[a-z]{2}$/i', //RSSMRAURTM0A56NB
128
        114 => '/^[a-z]{10}[0-9][a-z][0-9][a-z][0-9][a-z]$/i', //RSSMRAURTM0A5S2Y
129
        115 => '/^[a-z]{10}[0-9][a-z][0-9][a-z]{3}$/i', //RSSMRAURTM0A5SNN
130
        116 => '/^[a-z]{10}[0-9][a-z]{2}[0-9]{2}[a-z]$/i', //RSSMRAURTM0AR62H
131
        117 => '/^[a-z]{10}[0-9][a-z]{2}[0-9][a-z]{2}$/i', //RSSMRAURTM0AR6NW
132
        118 => '/^[a-z]{10}[0-9][a-z]{3}[0-9][a-z]$/i', //RSSMRAURTM0ARS2T
133
        119 => '/^[a-z]{10}[0-9][a-z]{5}$/i', //RSSMRAURTM0ARSNI
134
        120 => '/^[a-z]{12}[0-9]{3}[a-z]$/i', //RSSMRAURTMLA562P
135
        121 => '/^[a-z]{12}[0-9]{2}[a-z]{2}$/i', //RSSMRAURTMLA56NE
136
        122 => '/^[a-z]{12}[0-9][a-z][0-9][a-z]$/i', //RSSMRAURTMLA5S2B
137
        123 => '/^[a-z]{12}[0-9][a-z]{3}$/i', //RSSMRAURTMLA5SNQ
138
        124 => '/^[a-z]{13}[0-9]{2}[a-z]$/i', //RSSMRAURTMLAR62K
139
        125 => '/^[a-z]{13}[0-9][a-z]{2}$/i', //RSSMRAURTMLAR6NZ
140
        126 => '/^[a-z]{14}[0-9][a-z]$/i', //RSSMRAURTMLARS2W
141
        127 => '/^[a-z]{16}$/i', //RSSMRAURTMLARSNL
142
    );
143
    
144
    private $codiceFiscale;
145
    private $omocodiaAllowed = true;
146
    private $century = null;
147
    
148
    private $foundOmocodiaLevel = null;
149
    private $codiceFiscaleWithoutOmocodia = null;
150
    private $birthDate = null;
151
    private $gender = null;
152
    
153
    private $error = null;
154
    private $isValid = false;
155
156
    /**
157
     * Create a Validator instance.
158
     *
159
     * @param string $codiceFiscale the codice fiscale to validate
160
     * @param array $properties  An array with additional properties.
161
     */
162 154
    public function __construct($codiceFiscale, $properties = array())
163
    {
164 154
        $this->codiceFiscale = strtoupper($codiceFiscale);
165
        
166 154
        if (array_key_exists('omocodiaAllowed', $properties)) {
167 154
            $this->omocodiaAllowed = $properties['omocodiaAllowed'];
168 154
        }
169
        
170 154
        if (array_key_exists('century', $properties)) {
171 143
            $this->century = $properties['century'];
172 143
        }
173
        
174
        try {
175 154
            $this->validateLength();
176
177 152
            $this->validateFormat();
178
179 151
            $this->validateCheckDigit();
180
            
181 150
            $this->validateAndReplaceOmocodia();
182
183 149
            $this->validateBirthDateAndGender();
184
185 146
            $this->isValid = true;
186 154
        } catch (\Exception $e) {
187 8
            $this->error = $e->getMessage();
188
        }
189 154
    }
190
191
    /**
192
     * Validates length
193
     *
194
     * @throws \Exception
195
     */
196 154
    private function validateLength()
197
    {
198
        // check empty
199 154
        if (empty($this->codiceFiscale)) {
200 1
            throw new \Exception('The codice fiscale to validate is empty');
201
        }
202
203
        // check length
204 153
        if (strlen($this->codiceFiscale) !== 16) {
205 1
            throw new \Exception('The codice fiscale to validate has an invalid length');
206
        }
207 152
    }
208
209
    /**
210
     * Validates format
211
     *
212
     * @throws \Exception
213
     */
214 152
    private function validateFormat()
215
    {
216 152
        $regexpValid = false;
217 152
        if (!$this->omocodiaAllowed) {
218
            // just one regex
219 1
            if (preg_match($this->regexs[0], $this->codiceFiscale)) {
220 1
                $this->foundOmocodiaLevel = 0;
221 1
                $regexpValid = true;
222 1
            }
223 1
        } else {
224
            // all the regex
225 151
            $omocodiaLevelApplied = 0;
226 151
            foreach ($this->regexs as $regex) {
227 151
                if (preg_match($regex, $this->codiceFiscale)) {
228 150
                    $this->foundOmocodiaLevel = $omocodiaLevelApplied;
229 150
                    $regexpValid = true;
230 150
                    break;
231
                }
232 133
                $omocodiaLevelApplied++;
233 151
            }
234
        }
235
236 152
        if (!$regexpValid) {
237 1
            throw new \Exception('The codice fiscale to validate has an invalid format');
238
        }
239 151
    }
240
    
241
    /**
242
     * Validates check digit
243
     *
244
     * @throws \Exception
245
     */
246 151
    private function validateCheckDigit()
247
    {
248 151
        $checkDigit = $this->calculateCheckDigit($this->codiceFiscale);
249 151
        if ($checkDigit != $this->codiceFiscale[15]) {
250 1
            throw new \Exception('The codice fiscale to validate has an invalid control character');
251
        }
252 150
    }
253
    
254
    /**
255
     * Validates omocodia and replace with matching chars
256
     *
257
     * @throws \Exception
258
     */
259 150
    private function validateAndReplaceOmocodia()
260
    {
261
        // check and replace omocodie
262 150
        $this->codiceFiscaleWithoutOmocodia = $this->codiceFiscale;
263 150
        $this->replaceOmocodiaSection(2, 1, 1, $this->omocodiaPositions[0]);
264 149
        $this->replaceOmocodiaSection(4, 2, 3, $this->omocodiaPositions[1]);
265 149
        $this->replaceOmocodiaSection(8, 4, 7, $this->omocodiaPositions[2]);
266 149
        $this->replaceOmocodiaSection(16, 8, 15, $this->omocodiaPositions[3]);
267 149
        $this->replaceOmocodiaSection(32, 16, 31, $this->omocodiaPositions[4]);
268 149
        $this->replaceOmocodiaSection(64, 32, 63, $this->omocodiaPositions[5]);
269 149
        $this->replaceOmocodiaSection(128, 64, 127, $this->omocodiaPositions[6]);
270 149
    }
271
272
    /**
273
     * Replace a section of the omocodia.
274
     *
275
     * @param $divider The divider.
276
     * @param $startingIndex The starting index.
277
     * @param $endingIndex The ending index.
278
     * @param $characterIndex The index to use to make the substitutions on the $codiceFiscaleWithoutOmocodia.
279
     */
280 150
    private function replaceOmocodiaSection($divider, $startingIndex, $endingIndex, $characterIndex)
281
    {
282 150
        if ($this->foundOmocodiaLevel % $divider >= $startingIndex && $this->foundOmocodiaLevel % $divider <= $endingIndex) {
283 132
            $charToCheck = $this->codiceFiscaleWithoutOmocodia{$characterIndex};
284 132
            if (!in_array($charToCheck, $this->omocodiaCodes)) {
285 1
                throw new \Exception('The codice fiscale to validate has an invalid character');
286
            }
287 131
            $newChar = array_search($charToCheck, $this->omocodiaCodes);
288 131
            $this->codiceFiscaleWithoutOmocodia{$characterIndex} = $newChar;
289 131
        }
290 149
    }
291
    
292
    /**
293
     * Validates birthdate and gender
294
     *
295
     * @throws \Exception
296
     */
297 149
    private function validateBirthDateAndGender()
298
    {
299
        // calculate day and sex
300 149
        $day = (int) substr($this->codiceFiscaleWithoutOmocodia, 9, 2);
301 149
        $this->gender = $day > 40 ? self::CHR_WOMEN : self::CHR_MALE;
302
303 149
        if ($this->gender === self::CHR_WOMEN) {
304 3
            $day -= 40;
305 3
        }
306
307
        // check day
308 149
        if ($day > 31) {
309 1
            throw new \Exception('The codice fiscale to validate has invalid characters for birth day');
310
        }
311
312
        // check month
313 148
        $monthChar = substr($this->codiceFiscaleWithoutOmocodia, 8, 1);
314 148
        if (!in_array($monthChar, $this->months)) {
315 1
            throw new \Exception('The codice fiscale to validate has an invalid character for birth month');
316
        }
317
        
318
        // calculate month, year and century
319 147
        $month = array_search($monthChar, $this->months);
320 147
        $year = substr($this->codiceFiscaleWithoutOmocodia, 6, 2);
321 147
        $century = $this->calculateCentury($year);
322
323
        // validate and calculate birth date
324 147
        if (!checkdate($month, $day, $century.$year)) {
325 1
            throw new \Exception('The codice fiscale to validate has an non existent birth date');
326
        }
327
        
328 146
        $this->birthDate = new \DateTime();
329 146
        $this->birthDate->setDate($century.$year, $month, $day)->setTime(0, 0, 0)->format('Y-m-d');
330 146
    }
331
    
332
    /**
333
     *
334
     * @param string $year
335
     * @return string
336
     */
337 147
    private function calculateCentury($year)
338
    {
339 147
        $currentDate = new \DateTime();
340 147
        $currentYear = $currentDate->format('y');
341 147
        if (!is_null($this->century)) {
342 1
            $century = $this->century;
343 1
        } else {
344 146
            $currentCentury = substr($currentDate->format('Y'), 0, 2);
345 146
            $century = $year < $currentYear ? $currentCentury : $currentCentury - 1;
346
        }
347
        
348 147
        return $century;
349
    }
350
351
    /**
352
     * Return the validation error
353
     *
354
     * @return string
355
     */
356 11
    public function getError()
357
    {
358 11
        return $this->error;
359
    }
360
361
    /**
362
     * Return true if the provided codice fiscale is valid, false otherwise
363
     *
364
     * @return boolean
365
     */
366 154
    public function isFormallyValid()
367
    {
368 154
        return $this->isValid;
369
    }
370
371
    /**
372
     * Return true if the provided codice fiscale is an omocodia, false otherwise
373
     *
374
     * @return boolean
375
     */
376 1
    public function isOmocodia()
377
    {
378 1
        return $this->foundOmocodiaLevel > 0;
379
    }
380
381
    /**
382
     * Return the provided codice fiscale, cleaned up by omocodia
383
     *
384
     * @return string
385
     */
386 143
    protected function getCodiceFiscaleWithoutOmocodia()
387
    {
388 143
        return $this->codiceFiscaleWithoutOmocodia;
389
    }
390
391
    /**
392
     * Return the birth date
393
     *
394
     * @return \DateTime
395
     */
396 143
    protected function getBirthDate()
397
    {
398 143
        return $this->birthDate;
399
    }
400
401
    /**
402
     * Return the gender
403
     *
404
     * @return string
405
     */
406 143
    protected function getGender()
407
    {
408 143
        return $this->gender;
409
    }
410
}
411