NISSGeneratorHelper::generateStringControlNumber()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 12
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
 * NISSGeneratorHelper
11
 *
12
 * This class contains static methods to generate National Identification Numbers (NISS)
13
 * 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 NISSGeneratorHelper
21
{
22
    /**
23
     * Generate a belgian NISS number
24
     *
25
     * @param DateTime $birthDate
26
     * @param ?int $orderNumber
27
     * @param string $gender M, F or null
28
     * @param string $type default or bis
29
     *
30
     * @return string
31
     */
32
    public static function generate(DateTime $birthDate, string $gender, ?int $orderNumber = null, string $type)
33
    {
34
        // Checks orderNumber
35
        if ($orderNumber !== null && ($orderNumber < 1 || $orderNumber > 999)) {
36
            throw new InvalidArgumentException('The order number must be null or between 1 and 999.');
37
        }
38
39
        // Checks gender
40
        if ($gender !== NISS::GENDER_FEMALE && $gender !== NISS::GENDER_MALE && $gender !== NISS::GENDER_UNKNOWN) {
41
            throw new InvalidArgumentException('The gender must be null, F or M. Given: ' . $gender);
42
        }
43
44
        // TODO: Function + match bis and gender unknown
45
        // check if order number matches the gender
46
        if ($orderNumber == !null && $gender !== NISS::GENDER_UNKNOWN) {
47
            $isEven = $orderNumber % 2 == 0;
48
            if (($isEven && $gender === NISS::GENDER_MALE) || (!$isEven && $gender === NISS::GENDER_FEMALE)) {
49
                throw new InvalidArgumentException('The gender does not match the order number.');
50
            }
51
        }
52
53
        // generate the dob string matching the type
54
        $birthString = self::modifyDateOfBirth($birthDate, $type, $gender);
55
56
        // generate the order number, matching the gender
57
        $orderString = self::generateStringOrderNumber($orderNumber, $gender);
58
59
        // generate the control number
60
        $controlNumber = self::generateStringControlNumber($birthDate, $birthString, $orderString);
61
62
        return $birthString . $orderString . $controlNumber;
63
    }
64
65
66
    /**
67
     * return date of birth of a NISS number matching the type.
68
     *
69
     * @param DateTime $birthDate
70
     * @param string $type (default, bis or ter)
71
     * @param string $gender (M, F or null)
72
     *
73
     * @return string
74
     */
75
    public static function modifyDateOfBirth(DateTime $birthDate, string $type, string $gender): string
76
    {
77
        if ($type === NISS::TYPE_DOB_UNKNOWN) {
78
            return '000001';
79
        } elseif ($type === NISS::TYPE_REGULAR) {
80
            $month = $birthDate->format('m');
81
        } elseif ($type === NISS::TYPE_UNOFFICIAL) {
82
            // add 80 to the mounth if the NISS is unofficial
83
            $month = ((int) $birthDate->format('m')) + 80;
84
        } elseif ($type === NISS::TYPE_BIS && $gender !== NISS::GENDER_UNKNOWN) {
85
            // add 40 if gender is known
86
            $month = ((int) $birthDate->format('m')) + 40;
87
        } elseif ($type === NISS::TYPE_BIS && $gender == NISS::GENDER_UNKNOWN) {
88
            // add 20 if gender is unknown
89
            $month = ((int) $birthDate->format('m')) + 20;
90
        } elseif ($type === NISS::TYPE_TER) {
91
            // add 60 if NISS is ter
92
            $month = ((int) $birthDate->format('m')) + 60;
93
        } else {
94
            throw new InvalidArgumentException('The type must be default, bis or ter. Given: ' . $type);
95
        }
96
97
        return $birthDate->format('y') . str_pad($month, 2, '0', STR_PAD_LEFT) . $birthDate->format('d');
98
    }
99
100
101
    /**
102
     * Generate a control number.
103
     *
104
     * @param dateTime $birthString
105
     * @param string $orderString
106
     * @param ?string $type (default, bis or ter)
107
     *
108
     * @return string
109
     */
110
    private static function generateStringControlNumber(
111
        DateTime $birthDate,
112
        string $birthString,
113
        string $orderString
114
    ): string {
115
        // concatenate the birth date and the order number
116
        $unionString = $birthString . $orderString;
117
        $isAfter1999 = intval($birthDate->format('Y')) > 1999;
118
119
        $controlNumber = NISSExtractorHelper::calculateControlNumber($unionString, $isAfter1999);
120
121
        return str_pad($controlNumber, 2, '0', STR_PAD_LEFT);
122
    }
123
124
    /**
125
     * Generate a random order number, based on gender
126
     *
127
     * @param ?int $orderNumber
128
     * @param ?string $gender M, F or null
129
     *
130
     * @return string
131
     */
132
    private static function generateStringOrderNumber(?string $orderNumber = null, ?string $gender = null): string
133
    {
134
        // sanity check
135
        if ($orderNumber !== null && ($orderNumber < 1 || $orderNumber > 999)) {
136
            throw new InvalidArgumentException('The order number must be null or between 1 and 999.');
137
        }
138
139
        if ($orderNumber) {
140
            $order = $orderNumber;
141
        } elseif ($gender === NISS::GENDER_UNKNOWN) {
142
            $order = rand(1, 999);
143
        } else {
144
            $order = 1 + (rand(0, 499) * 2);
145
            if ($gender === NISS::GENDER_MALE) {
146
                $order--;
147
            }
148
        }
149
150
        return str_pad($order, 3, '0', STR_PAD_LEFT);
151
    }
152
}
153