isValidNationalNumber()   B
last analyzed

Complexity

Conditions 11
Paths 17

Size

Total Lines 63
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 11.0761

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 11
eloc 34
c 3
b 0
f 0
nc 17
nop 1
dl 0
loc 63
ccs 32
cts 35
cp 0.9143
crap 11.0761
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace drupol\BelgianNationalNumberFaker\Validator;
6
7
use const FILTER_SANITIZE_NUMBER_INT;
8
9
/**
10
 * Class BelgianNationalNumberValidator.
11
 */
12
final class BelgianNationalNumberValidator
13
{
14
    /**
15
     * Validates a Belgian identification number.
16
     *
17
     * @param string $id
18
     *   The number.
19
     *
20
     * @return bool
21
     *   True if valid, false otherwise.
22
     */
23 2
    public static function isValid(string $id): bool
24
    {
25 2
        return self::isValidNationalNumber($id);
26
    }
27
28
    /**
29
     * Check if the number is a valid national number.
30
     *
31
     * @param string $national_number
32
     *   The number.
33
     *
34
     * @return bool
35
     *   True if validated, false otherwise.
36
     */
37 2
    private static function isValidNationalNumber(string $national_number): bool
38
    {
39 2
        $national_number = filter_var($national_number, FILTER_SANITIZE_NUMBER_INT);
40
41 2
        if (false === $national_number) {
42
            return false;
43
        }
44
45 2
        $allowedCharactersPattern = '/^[0-9\\ \\-]+$/';
46 2
        $nonNumericPattern = '/\\D/';
47
48 2
        if (1 !== preg_match($allowedCharactersPattern, $national_number)) {
49 1
            return false;
50
        }
51
52 2
        $national_number = preg_replace($nonNumericPattern, '', $national_number);
53
54 2
        if (null === $national_number) {
55
            return false;
56
        }
57
58 2
        if (11 !== mb_strlen($national_number)) {
59 1
            return false;
60
        }
61
62 2
        $birthDatePart = (int) mb_substr($national_number, 0, 6);
63 2
        $counterPart = (int) mb_substr($national_number, 6, 3);
64 2
        $controlPart = (int) mb_substr($national_number, 9, 2);
65
66
        // 1. CONTROL NUMBER CHECKING
67 2
        $born2kOrLater = false;
68 2
        $calculatedControl = 97 - (($birthDatePart . $counterPart) % 97);
69
70 2
        if ($calculatedControl !== $controlPart) {
71 2
            $born2kOrLater = true;
72 2
            $calculatedControl = 97 - (('2' . $birthDatePart . $counterPart) % 97);
73
74 2
            if ($calculatedControl !== $controlPart) {
75 2
                return false;
76
            }
77
        }
78
79
        // 2. BIRTHDATE CHECKING
80 2
        $birthDate = true === $born2kOrLater ?
81 2
            '20' . $birthDatePart :
82 2
            '19' . $birthDatePart;
83
84 2
        $checkdate = checkdate(
85 2
            (int) mb_substr($birthDate, 4, 2),
86 2
            (int) mb_substr($birthDate, 6, 2),
87 2
            (int) mb_substr($birthDate, 0, 4)
88
        );
89
90 2
        if (false === $checkdate) {
91 1
            return false;
92
        }
93
94
        // 3. COUNTER CHECKING
95 2
        if (1 > $counterPart || 997 < $counterPart) {
96
            return false;
97
        }
98
99 2
        return true;
100
    }
101
}
102