Completed
Push — master ( cda6af...af8baf )
by Davide
04:58
created

Calculator::cleanString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace CodiceFiscale;
4
5
/**
6
 * Codice Fiscale calculator.
7
 *
8
 * @author davidepastore
9
 */
10
class Calculator
11
{
12
    private $subject;
13
    private $omocodiaLevel = 0;
14
15
    /**
16
     * Array of available vowels.
17
     */
18
    private $vowels = array('A', 'E', 'I', 'O', 'U');
19
20
    /**
21
     * Array of all available months.
22
     */
23
    private $months = array(
24
        '1' => 'A',
25
        '2' => 'B',
26
        '3' => 'C',
27
        '4' => 'D',
28
        '5' => 'E',
29
        '6' => 'H',
30
        '7' => 'L',
31
        '8' => 'M',
32
        '9' => 'P',
33
        '10' => 'R',
34
        '11' => 'S',
35
        '12' => 'T',
36
    );
37
38
    /**
39
     * Array of all avaialable odd characters.
40
     */
41
    private $odd = array(
42
        '0' => 1,
43
        '1' => 0,
44
        '2' => 5,
45
        '3' => 7,
46
        '4' => 9,
47
        '5' => 13,
48
        '6' => 15,
49
        '7' => 17,
50
        '8' => 19,
51
        '9' => 21,
52
        'A' => 1,
53
        'B' => 0,
54
        'C' => 5,
55
        'D' => 7,
56
        'E' => 9,
57
        'F' => 13,
58
        'G' => 15,
59
        'H' => 17,
60
        'I' => 19,
61
        'J' => 21,
62
        'K' => 2,
63
        'L' => 4,
64
        'M' => 18,
65
        'N' => 20,
66
        'O' => 11,
67
        'P' => 3,
68
        'Q' => 6,
69
        'R' => 8,
70
        'S' => 12,
71
        'T' => 14,
72
        'U' => 16,
73
        'V' => 10,
74
        'W' => 22,
75
        'X' => 25,
76
        'Y' => 24,
77
        'Z' => 23,
78
    );
79
80
    /**
81
     * Array of all avaialable even characters.
82
     */
83
    private $even = array(
84
        '0' => 0,
85
        '1' => 1,
86
        '2' => 2,
87
        '3' => 3,
88
        '4' => 4,
89
        '5' => 5,
90
        '6' => 6,
91
        '7' => 7,
92
        '8' => 8,
93
        '9' => 9,
94
        'A' => 0,
95
        'B' => 1,
96
        'C' => 2,
97
        'D' => 3,
98
        'E' => 4,
99
        'F' => 5,
100
        'G' => 6,
101
        'H' => 7,
102
        'I' => 8,
103
        'J' => 9,
104
        'K' => 10,
105
        'L' => 11,
106
        'M' => 12,
107
        'N' => 13,
108
        'O' => 14,
109
        'P' => 15,
110
        'Q' => 16,
111
        'R' => 17,
112
        'S' => 18,
113
        'T' => 19,
114
        'U' => 20,
115
        'V' => 21,
116
        'W' => 22,
117
        'X' => 23,
118
        'Y' => 24,
119
        'Z' => 25,
120
    );
121
122
    /**
123
     * Array of all avaialable omocodia characters.
124
     */
125
    private $omocodiaCodes = array(
126
        '0' => 'L',
127
        '1' => 'M',
128
        '2' => 'N',
129
        '3' => 'P',
130
        '4' => 'Q',
131
        '5' => 'R',
132
        '6' => 'S',
133
        '7' => 'T',
134
        '8' => 'U',
135
        '9' => 'V',
136
    );
137
138
    /**
139
     * Create a Codice Fiscale instance.
140
     *
141
     * @param Subject $subject The subject that will have the codice fiscale.
142
     * @param $properties An array with additional properties.
143
     */
144 22
    public function __construct(Subject $subject, $properties = array())
145
    {
146 22
        $this->subject = $subject;
147
148 22
        if (array_key_exists('omocodiaLevel', $properties)) {
149 20
            $this->omocodiaLevel = $properties['omocodiaLevel'];
150 20
        }
151 22
    }
152
153
    /**
154
     * Calculate the code fiscale.
155
     *
156
     * @returns Returns the complete codice fiscale.
157
     */
158 22
    public function calculate()
159
    {
160 22
        $temporaryCodiceFiscale = $this->calculateSurname().$this->calculateName().
161 22
               $this->calculateBirthDateAndGender().$this->calculateBelfioreCode();
162 22
        $temporaryCodiceFiscale = $this->calculateOmocodia($temporaryCodiceFiscale);
163
164 22
        return $temporaryCodiceFiscale.$this->calculateCheckDigit($temporaryCodiceFiscale);
165
    }
166
167
    /**
168
     * Calculate all possibilities for the code fiscale.
169
     *
170
     * @returns Returns the complete codice fiscale.
171
     */
172 3
    public function calculateAllPossibilities()
173
    {
174 3
        $allPossibilities = array();
175 3
        for ($i = 0; $i < 8; ++$i) {
176 3
            $this->omocodiaLevel = $i;
177 3
            $allPossibilities[] = $this->calculate();
178 3
        }
179
180 3
        return $allPossibilities;
181
    }
182
183
    /**
184
     * Calculate the surname part of the codice fiscale.
185
     *
186
     * @returns Returns the surname part of the codice fiscale.
187
     */
188 22
    private function calculateSurname()
189
    {
190 22
        $consonants = str_replace($this->vowels, '', strtoupper($this->subject->getSurname()));
191 22
        $consonants = $this->cleanString($consonants);
192 22
        if (strlen($consonants) > 2) {
193 18
            $result = substr($consonants, 0, 3);
194 18
        } else {
195 4
            $result = $this->calculateSmallString($consonants, $this->subject->getSurname());
196
        }
197
198 22
        return $result;
199
    }
200
201
    /**
202
     * Calculate the name part of the codice fiscale.
203
     *
204
     * @returns Returns the name part of the codice fiscale.
205
     */
206 22
    private function calculateName()
207
    {
208 22
        $consonants = str_replace($this->vowels, '', strtoupper($this->subject->getName()));
209 22
        $consonants = $this->cleanString($consonants);
210 22
        if (strlen($consonants) > 3) {
211 6
            $result = $consonants[0].$consonants[2].$consonants[3];
212 22
        } elseif (strlen($consonants) == 3) {
213 1
            $result = $consonants;
214 1
        } else {
215 15
            $result = $this->calculateSmallString($consonants, $this->subject->getName());
216
        }
217
218 22
        return $result;
219
    }
220
221
    /**
222
     * Calculate small string for the given parameters (used by name and surname).
223
     *
224
     * @param $consonants A consonants string.
225
     * @param $string The small string.
226
     * @returns Returns the calculated result for the small string.
227
     */
228 15
    private function calculateSmallString($consonants, $string)
229
    {
230 15
        $string = $this->cleanString($string);
231 15
        $vowels = str_replace(str_split($consonants), '', strtoupper($string));
232 15
        $result = substr($consonants.$vowels.'XXX', 0, 3);
233
234 15
        return $result;
235
    }
236
237
    /**
238
     * Calculate the birth date and the gender.
239
     *
240
     * @returns Returns the birth date and gender part of the codice fiscale.
241
     */
242 22
    private function calculateBirthDateAndGender()
243
    {
244 22
        $year = $this->subject->getBirthDate()->format('y');
245 22
        $month = $this->months[$this->subject->getBirthDate()->format('n')];
246 22
        $day = $this->subject->getBirthDate()->format('d');
247 22
        if (strtoupper($this->subject->getGender()) == 'F') {
248 2
            $day += 40;
249 2
        }
250
251 22
        return $year.$month.$day;
252
    }
253
254
    /**
255
     * Calculate the Belfiore code.
256
     *
257
     * @returns Returns the Belfiore code.
258
     */
259 22
    private function calculateBelfioreCode()
260
    {
261 22
        return strtoupper($this->subject->getBelfioreCode());
262
    }
263
264
    /**
265
     * Calculate the check digit.
266
     *
267
     * @param $temporaryCodiceFiscale The first part of the codice fiscale.
268
     * @returns Returns the check digit part of the codice fiscale.
269
     */
270 22
    private function calculateCheckDigit($temporaryCodiceFiscale)
271
    {
272 22
        $sumEven = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->even, 1);
273 22
        $sumOdd = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->odd, 0);
274
275 22
        return chr(($sumOdd + $sumEven) % 26 + 65);
276
    }
277
278
    /**
279
     * Calculate the sum by the given dictionary for the given temporary codice fiscale.
280
     *
281
     * @param $temporaryCodiceFiscale The temporary codice fiscale.
282
     * @param $dictionaryArray The dictionary array.
283
     * @param $i The start index value.
284
     * @returns Returns the sum by the given dictionary for the given temporary codice fiscale.
285
     */
286 22
    private function calculateSumByDictionary($temporaryCodiceFiscale, $dictionaryArray, $i)
287
    {
288 22
        $sum = 0;
289 22
        for (; $i < 15; $i = $i + 2) {
290 22
            $k = $temporaryCodiceFiscale{$i};
291 22
            $sum = $sum + $dictionaryArray[$k];
292 22
        }
293
294 22
        return $sum;
295
    }
296
297
    /**
298
     * Calculate the omocodia case (additional translation).
299
     *
300
     * @param $temporaryCodiceFiscale The first part of the codice fiscale.
301
     * @returns Returns the new codice fiscale.
302
     */
303 22
    private function calculateOmocodia($temporaryCodiceFiscale)
304
    {
305 22
        if ($this->omocodiaLevel > 0) {
306 7
            $omocodiaLevelApplied = 0;
307 7
            for ($i = strlen($temporaryCodiceFiscale) - 1; $i > 0; --$i) {
308 7
                $k = $temporaryCodiceFiscale{$i};
309 7
                if ($omocodiaLevelApplied < $this->omocodiaLevel && is_numeric($k)) {
310 7
                    $newChar = $this->omocodiaCodes[$k];
311 7
                    $temporaryCodiceFiscale{$i}
312
                    = $newChar;
313 7
                    ++$omocodiaLevelApplied;
314 7
                }
315 7
            }
316 7
        }
317
318 22
        return $temporaryCodiceFiscale;
319
    }
320
321
    /**
322
     * Clean the string removing some characters.
323
     *
324
     * @param $string The string to clean.
325
     * @returns Returns a clean string.
326
     */
327 22
    private function cleanString($string)
328
    {
329 22
        return preg_replace('/[\s\'"`]+/', '', $string);
330
    }
331
}
332