Skip to content

Commit f4491dc

Browse files
refactor(fi_FI): simplify SSN generation
Replacing complex conditional logic with a cleaner match expression and a dedicated helper method for generating gender-aware birth numbers. Signed-off-by: Rasmus Bertell <rasmus@bertell.fi>
1 parent e21d00b commit f4491dc

File tree

2 files changed

+49
-56
lines changed

2 files changed

+49
-56
lines changed

src/Provider/fi_FI/Person.php

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -91,64 +91,57 @@ class Person extends \Faker\Provider\Person
9191
*
9292
* @see http://www.finlex.fi/fi/laki/ajantasa/2010/20100128
9393
*
94-
* @param string $gender Person::GENDER_MALE || Person::GENDER_FEMALE
94+
* @param static::GENDER_FEMALE|static::GENDER_MALE|null $gender
9595
*
96-
* @return string on format DDMMYYCZZZQ, where DDMMYY is the date of birth, C the century sign, ZZZ the individual number and Q the control character (checksum)
96+
* @return string on format DDMMYYCZZZQ, where DDMMYY is the date of birth,
97+
* C the century sign, ZZZ the individual number and Q the
98+
* control character (checksum)
9799
*/
98-
public function personalIdentityNumber(\DateTime $birthdate = null, $gender = null)
99-
{
100-
$checksumCharacters = '0123456789ABCDEFHJKLMNPRSTUVWXY';
100+
public function personalIdentityNumber(
101+
?\DateTime $birthdate = null,
102+
?string $gender = null
103+
) {
104+
$birthdate ??= \Faker\Provider\DateTime::dateTimeThisCentury();
105+
$centurySign = match ((int) ($birthdate->format('Y') / 100)) {
106+
18 => '+',
107+
19 => '-', // Technically can also be Y, X, W, V, or U
108+
20 => 'A', // Technically can also be B, C, D, E, or F
109+
default => throw new \InvalidArgumentException(
110+
'Year must be between 1800 and 2099 inclusive.',
111+
),
112+
};
101113

102-
if (!$birthdate) {
103-
$birthdate = \Faker\Provider\DateTime::dateTimeThisCentury();
104-
}
114+
$checksumCharacters = '0123456789ABCDEFHJKLMNPRSTUVWXY';
105115
$datePart = $birthdate->format('dmy');
116+
$randomDigits = $this->getBirthNumber($gender);
117+
$checksum = $checksumCharacters[
118+
(int) ($datePart . $randomDigits) % strlen($checksumCharacters)
119+
];
106120

107-
switch ((int) ($birthdate->format('Y') / 100)) {
108-
case 18:
109-
$centurySign = '+';
110-
111-
break;
112-
113-
case 19:
114-
$centurySign = '-';
115-
116-
break;
117-
118-
case 20:
119-
$centurySign = 'A';
120-
121-
break;
122-
123-
default:
124-
throw new \InvalidArgumentException('Year must be between 1800 and 2099 inclusive.');
125-
}
126-
127-
$randomDigits = self::numberBetween(0, 89);
121+
return $datePart . $centurySign . $randomDigits . $checksum;
122+
}
128123

129-
if ($gender && $gender == static::GENDER_MALE) {
130-
if ($randomDigits === 0) {
131-
$randomDigits .= static::randomElement([3, 5, 7, 9]);
132-
} else {
133-
$randomDigits .= static::randomElement([1, 3, 5, 7, 9]);
134-
}
135-
} elseif ($gender && $gender == static::GENDER_FEMALE) {
136-
if ($randomDigits === 0) {
137-
$randomDigits .= static::randomElement([2, 4, 6, 8]);
138-
} else {
139-
$randomDigits .= static::randomElement([0, 2, 4, 6, 8]);
140-
}
141-
} else {
142-
if ($randomDigits === 0) {
143-
$randomDigits .= self::numberBetween(2, 9);
144-
} else {
145-
$randomDigits .= (string) static::numerify('#');
146-
}
147-
}
148-
$randomDigits = str_pad($randomDigits, 3, '0', STR_PAD_LEFT);
124+
/**
125+
* Generate the birth number for person.
126+
*
127+
* Birth number is odd for men and even for women.
128+
* Numbers 900-999 are reserved for temporary use.
129+
* Number 001 is not used.
130+
*
131+
* @param static::GENDER_FEMALE|static::GENDER_MALE|null $gender
132+
*
133+
* @return numeric-string Gendered three digit birth number
134+
*/
135+
protected function getBirthNumber(?string $gender = null): string
136+
{
137+
[$min, $max] = match ($gender) {
138+
static::GENDER_MALE => [3, 899],
139+
static::GENDER_FEMALE => [2, 898],
140+
default => [2, 999],
141+
};
149142

150-
$checksum = $checksumCharacters[(int) ($datePart . $randomDigits) % strlen($checksumCharacters)];
143+
$number = (string) (mt_rand(0, (int) (($max - $min) / 2)) * 2 + $min);
151144

152-
return $datePart . $centurySign . $randomDigits . $checksum;
145+
return str_pad($number, 3, '0', STR_PAD_LEFT);
153146
}
154147
}

test/Provider/fi_FI/PersonTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ final class PersonTest extends TestCase
1616
public function provideSeedAndExpectedReturn()
1717
{
1818
return [
19-
[1, '1800-01-01', '010100+5207'],
20-
[2, '1930-08-08', '080830-508R'],
21-
[3, '1999-12-31', '311299-409D'],
22-
[4, '2000-01-01', '010100A039P'],
23-
[5, '2015-06-17', '170615A690X'],
19+
[1, '1800-01-01', '010100+5805'],
20+
[2, '1930-08-08', '080830-566L'],
21+
[3, '1999-12-31', '311299-452T'],
22+
[4, '2000-01-01', '010100A036L'],
23+
[5, '2015-06-17', '170615A774M'],
2424
];
2525
}
2626

0 commit comments

Comments
 (0)