NISSExtractorHelper::format()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 7
rs 10
1
<?php
2
3
namespace Helip\NISS\Helpers;
4
5
use DateTime;
6
use Helip\NISS\NISS;
7
use InvalidArgumentException;
8
9
/**
10
 * NISSExtractorHelper
11
 *
12
 * This class contains static methods to retrieve information from and clean
13
 * National Identification Numbers (NISS) and National Identification Numbers BIS and TER
14
 *
15
 * @version 1.0.0
16
 * @license LGPL-3.0-only
17
 * @author Pierre Hélin
18
 * @package NISS
19
 */
20
class NISSExtractorHelper
21
{
22
    /**
23
     * Calculates the birthdate.
24
     *
25
     * @param string $niss
26
     * @return DateTime|null
27
     */
28
    public static function calculateBirthdate(string $niss, string $type, string $gender): DateTime|null
29
    {
30
        // Dob cannot be calculated if type is unknown
31
        if ($type == NISS::TYPE_DOB_UNKNOWN) {
32
            return null;
33
        }
34
35
        // extract birthdate
36
        $birthdateString = substr($niss, 0, 6);
37
38
        // extract month
39
        $month = intval(substr($birthdateString, 2, 2));
40
41
        // calculate month based on type
42
        if ($type == NISS::TYPE_BIS && $gender === NISS::GENDER_UNKNOWN) {
43
            $month = $month - 20;
44
        } elseif ($type == NISS::TYPE_BIS) {
45
            $month = $month - 40;
46
        } elseif ($type == NISS::TYPE_TER) {
47
            $month = $month - 60;
48
        } elseif ($type == NISS::TYPE_UNOFFICIAL) {
49
            $month = $month - 80;
50
        }
51
52
        // ensure month is 2 digits
53
        if ($month < 10) {
54
            $month = '0' . $month;
55
        }
56
57
        // check if year is greater than 1999
58
        $century = self::getCentury($niss);
59
60
        // replace month
61
        $newBirthdateString = $century . substr($birthdateString, 0, 2) . $month . substr($birthdateString, 4, 2);
62
63
        // convert to date
64
        return DateTime::createFromFormat('Ymd', $newBirthdateString);
65
    }
66
67
    /**
68
     * Calculates gender based on the control number.
69
     *
70
     * @param string $niss
71
     *
72
     * @return string
73
     */
74
    public static function calculateGender(string $niss): string
75
    {
76
        // gender is based on control number odd (male) or even (female)
77
        $controlNumber = (int) self::getControlNumber($niss);
78
        return ($controlNumber % 2 == 1 ? NISS::GENDER_FEMALE : NISS::GENDER_MALE);
79
    }
80
81
    /**
82
     * Calculate type of NISS number
83
     *
84
     * @param string $niss
85
     *
86
     * @return string
87
     */
88
    public static function calculateType($niss): string
89
    {
90
        // extract month
91
        $month = substr($niss, 2, 2);
92
93
        // check if month is greater than 0
94
        if ($month === '00') {
95
            return NISS::TYPE_DOB_UNKNOWN;
96
        } elseif ($month > 0 && $month < 13) {
97
            return NISS::TYPE_REGULAR;
98
            // BIS type whith unknow gender are augmented by 20
99
        } elseif ($month > 0 + 20 && $month < 13 + 20) {
100
            return NISS::TYPE_BIS;
101
            // BIS type whith know gender are augmented by 40
102
        } elseif ($month > 0 + 40 && $month < 13 + 40) {
103
            return NISS::TYPE_BIS;
104
            // TER type are augmented by 60
105
        } elseif ($month > 0 + 60 && $month < 13 + 60) {
106
            return NISS::TYPE_TER;
107
            // unofficial type are augmented by 80
108
        } elseif ($month > 0 + 80 && $month < 13 + 80) {
109
            return NISS::TYPE_UNOFFICIAL;
110
        } else {
111
            return NISS::TYPE_UNKNOWN;
112
        }
113
    }
114
115
    /**
116
     * Get the century based on the control number.
117
     */
118
    public static function getCentury(string $niss): int
119
    {
120
        // extract control number
121
        $controlNumber = (int) self::getControlNumber($niss);
122
        $reducedNISS = substr($niss, 0, 9);
123
124
        $calculatedControlNumber = self::calculateControlNumber($reducedNISS, false);
125
        if ($calculatedControlNumber === $controlNumber) {
126
            // control number is valid for 1900-1999
127
            return 19;
128
        }
129
        $calculatedControlNumber = self::calculateControlNumber($reducedNISS, true);
130
        if ($calculatedControlNumber === $controlNumber) {
131
            // control number is valid for 2000-2099
132
            return 20;
133
        }
134
135
        throw new InvalidArgumentException('Invalid NISS number');
136
    }
137
138
    /**
139
     * Get the control number.
140
     *
141
     * @param string $niss
142
     *
143
     * @return string
144
     */
145
    public static function getControlNumber(string $niss): string
146
    {
147
        return substr($niss, -2);
148
    }
149
150
    /**
151
     * Get the order number.
152
     *
153
     * @param string $niss
154
     *
155
     * @return string
156
     */
157
    public static function getOrderNumber(string $niss): string
158
    {
159
        return substr($niss, -5, 3);
160
    }
161
162
    /**
163
     * Format a NISS number.
164
     * YY.MM.DD-XXX.CC
165
     *
166
     * @param string $niss
167
     *
168
     * @return string
169
     */
170
    public static function format(string $niss): string
171
    {
172
        return substr($niss, 0, 2) . '.'
173
            . substr($niss, 2, 2) . '.'
174
            . substr($niss, 4, 2) . '-'
175
            . substr($niss, 6, 3) . '.'
176
            . substr($niss, 9, 2);
177
    }
178
179
    /**
180
     * Calculate the control number.
181
     *
182
     * @param string $reducedNISS
183
     * @param bool $bornAfter1999
184
     *
185
     * @return int
186
     */
187
    public static function calculateControlNumber(string $reducedNISS, bool $bornAfter1999): int
188
    {
189
        // add a leading 2 to the string if the birth date is after 1999
190
        // ref.: Arrêté royal du 25 novembre 1997 paru au Moniteur belge du 16 décembre 1997
191
        if ($bornAfter1999) {
192
            $reducedNISS = 2 . $reducedNISS;
193
        }
194
195
        return intval(97 - (intval($reducedNISS) % 97));
196
    }
197
}
198