Completed
Push — master ( 12664a...6076e1 )
by Pol
01:47
created

belgianNationalIdentificationNumber()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace drupol\BelgianNationalNumberFaker\Provider;
6
7
use Faker\Provider\Base;
8
use Faker\Provider\DateTime;
9
10
/**
11
 * Class BelgianNationalNumber.
12
 */
13
class BelgianNationalNumber extends Base
14
{
15
    /**
16
     * Generate a random Belgian National Number.
17
     *
18
     * @return string
19
     *
20
     * @see https://en.wikipedia.org/wiki/National_identification_number
21
     */
22 1
    public function belgianNationalIdentificationNumber(): string
23
    {
24
        do {
25 1
            $probe = \mb_substr(DateTime::date('Ymd'), 2) . static::randomNumber(5);
26 1
        } while (false === static::isValidNationalNumber($probe));
27
28 1
        return $probe;
29
    }
30
31
    /**
32
     * Check if the number is a valid national number.
33
     *
34
     * @param string $national_number
35
     *   The number.
36
     *
37
     * @return bool
38
     *   True if validated, false otherwise.
39
     */
40 1
    private static function isValidNationalNumber(string $national_number): bool
41
    {
42 1
        $national_number = \filter_var($national_number, \FILTER_SANITIZE_NUMBER_INT);
43
44 1
        if (false === $national_number) {
45
            return false;
46
        }
47
48 1
        $allowedCharactersPattern = '/^[0-9\\ \\-]+$/';
49 1
        $nonNumericPattern = '/\\D/';
50
51 1
        if (1 !== \preg_match($allowedCharactersPattern, $national_number)) {
52
            return false;
53
        }
54
55 1
        $national_number = \preg_replace($nonNumericPattern, '', $national_number);
56
57 1
        if (null === $national_number) {
58
            return false;
59
        }
60
61 1
        if (11 !== \mb_strlen($national_number)) {
62 1
            return false;
63
        }
64
65 1
        $birthDatePart = (int) \mb_substr($national_number, 0, 6);
66 1
        $counterPart = (int) \mb_substr($national_number, 6, 3);
67 1
        $controlPart = (int) \mb_substr($national_number, 9, 2);
68
69
        // 1. CONTROL NUMBER CHECKING
70 1
        $born2kOrLater = false;
71 1
        $calculatedControl = 97 - (($birthDatePart . $counterPart) % 97);
72
73 1
        if ($calculatedControl !== $controlPart) {
74 1
            $born2kOrLater = true;
75 1
            $calculatedControl = 97 - (('2' . $birthDatePart . $counterPart) % 97);
76
77 1
            if ($calculatedControl !== $controlPart) {
78 1
                return false;
79
            }
80
        }
81
82
        // 2. BIRTHDATE CHECKING
83 1
        $birthDate = true === $born2kOrLater ?
84
            '20' . $birthDatePart :
85 1
            '19' . $birthDatePart;
86
87 1
        if (!\checkdate(
88 1
            (int) \mb_substr($birthDate, 4, 2),
89 1
            (int) \mb_substr($birthDate, 6, 2),
90 1
            (int) \mb_substr($birthDate, 0, 4)
91
        )
92
        ) {
93
            return false;
94
        }
95
96
        // 3. COUNTER CHECKING
97 1
        if (1 > $counterPart || 997 < $counterPart) {
98
            return false;
99
        }
100
101 1
        return true;
102
    }
103
}
104