Completed
Push — master ( 057138...5b0fa8 )
by Davide
02:19
created

src/DavidePastore/CodiceFiscale/Calculator.php (2 issues)

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
namespace DavidePastore\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 17
    public function __construct(Subject $subject, $properties = array())
145
    {
146 17
        $this->subject = $subject;
147
148 17
        if (array_key_exists('omocodiaLevel', $properties)) {
149 15
            $this->omocodiaLevel = $properties['omocodiaLevel'];
150 15
        }
151 17
    }
152
153
    /**
154
     * Calculate the code fiscale.
155
     *
156
     * @returns Returns the complete codice fiscale.
157
     */
158 17
    public function calculate()
159
    {
160 17
        $temporaryCodiceFiscale = $this->calculateSurname().$this->calculateName().
161 17
               $this->calculateBirthDateAndGender().$this->calculateBelfioreCode();
162 17
        $temporaryCodiceFiscale = $this->calculateOmocodia($temporaryCodiceFiscale);
163
164 17
        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 17
    private function calculateSurname()
189
    {
190 17
        $consonants = str_replace($this->vowels, '', strtoupper($this->subject->getSurname()));
191 17
        if (strlen($consonants) > 2) {
192 14
            $result = substr($consonants, 0, 3);
193 14 View Code Duplication
        } else {
0 ignored issues
show
This code seems to be duplicated across your project.

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.

Loading history...
194 3
            $vowels = str_replace(str_split($consonants), '', strtoupper($this->subject->getSurname()));
195 3
            $result = substr($consonants.$vowels.'XXX', 0, 3);
196
        }
197
198 17
        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 17
    private function calculateName()
207
    {
208 17
        $consonants = str_replace($this->vowels, '', strtoupper($this->subject->getName()));
209 17
        if (strlen($consonants) > 3) {
210 5
            $result = $consonants[0].$consonants[2].$consonants[3];
211 17
        } elseif (strlen($consonants) == 3) {
212
            $result = implode($consonants);
213 View Code Duplication
        } else {
0 ignored issues
show
This code seems to be duplicated across your project.

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.

Loading history...
214 12
            $vowels = str_replace(str_split($consonants), '', strtoupper($this->subject->getName()));
215 12
            $result = substr($consonants.$vowels.'XXX', 0, 3);
216
        }
217
218 17
        return $result;
219
    }
220
221
    /**
222
     * Calculate the birth date and the gender.
223
     *
224
     * @returns Returns the birth date and gender part of the codice fiscale.
225
     */
226 17
    private function calculateBirthDateAndGender()
227
    {
228 17
        $year = $this->subject->getBirthDate()->format('y');
229 17
        $month = $this->months[$this->subject->getBirthDate()->format('n')];
230 17
        $day = $this->subject->getBirthDate()->format('d');
231 17
        if (strtoupper($this->subject->getGender()) == 'F') {
232 1
            $day += 40;
233 1
        }
234
235 17
        return $year.$month.$day;
236
    }
237
238
    /**
239
     * Calculate the Belfiore code.
240
     *
241
     * @returns Returns the Belfiore code.
242
     */
243 17
    private function calculateBelfioreCode()
244
    {
245 17
        return strtoupper($this->subject->getBelfioreCode());
246
    }
247
248
    /**
249
     * Calculate the check digit.
250
     *
251
     * @param $temporaryCodiceFiscale The first part of the codice fiscale.
252
     * @returns Returns the check digit part of the codice fiscale.
253
     */
254 17
    private function calculateCheckDigit($temporaryCodiceFiscale)
255
    {
256 17
        $sumEven = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->even, 1);
257 17
        $sumOdd = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->odd, 0);
258
259 17
        return chr(($sumOdd + $sumEven) % 26 + 65);
260
    }
261
262
    /**
263
     * Calculate the sum by the given dictionary for the given temporary codice fiscale.
264
     *
265
     * @param $temporaryCodiceFiscale The temporary codice fiscale.
266
     * @param $dictionaryArray The dictionary array.
267
     * @param $i The start index value.
268
     * @returns Returns the sum by the given dictionary for the given temporary codice fiscale.
269
     */
270 17
    private function calculateSumByDictionary($temporaryCodiceFiscale, $dictionaryArray, $i)
271
    {
272 17
        $sum = 0;
273 17
        for (; $i < 15; $i = $i + 2) {
274 17
            $k = $temporaryCodiceFiscale{$i};
275 17
            $sum = $sum + $dictionaryArray[$k];
276 17
        }
277
278 17
        return $sum;
279
    }
280
281
    /**
282
     * Calculate the omocodia case (additional translation).
283
     *
284
     * @param $temporaryCodiceFiscale The first part of the codice fiscale.
285
     * @returns Returns the new codice fiscale.
286
     */
287 17
    private function calculateOmocodia($temporaryCodiceFiscale)
288
    {
289 17
        if ($this->omocodiaLevel > 0) {
290 7
            $omocodiaLevelApplied = 0;
291 7
            for ($i = strlen($temporaryCodiceFiscale) - 1; $i > 0; --$i) {
292 7
                $k = $temporaryCodiceFiscale{$i};
293 7
                if ($omocodiaLevelApplied < $this->omocodiaLevel && is_numeric($k)) {
294 7
                    $newChar = $this->omocodiaCodes[$k];
295 7
                    $temporaryCodiceFiscale{$i}
296
                    = $newChar;
297 7
                    ++$omocodiaLevelApplied;
298 7
                }
299 7
            }
300 7
        }
301
302 17
        return $temporaryCodiceFiscale;
303
    }
304
}
305