1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace App\Module\User\FindAbbreviatedNameList\Service; |
4
|
|
|
|
5
|
|
|
use App\Module\User\Data\UserData; |
6
|
|
|
|
7
|
|
|
class UserNameAbbreviator |
8
|
|
|
{ |
9
|
24 |
|
public function __construct() |
10
|
|
|
{ |
11
|
24 |
|
} |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Recursive function that builds abbreviation for lastname. |
15
|
|
|
* |
16
|
|
|
* @param string $lastName |
17
|
|
|
* @param UserData[] $usersToCheck |
18
|
|
|
* |
19
|
|
|
* @return string |
20
|
|
|
*/ |
21
|
15 |
|
private function buildLastNameAbbreviation(string $lastName, array $usersToCheck): string |
22
|
|
|
{ |
23
|
15 |
|
$abbreviatedLastName = ''; |
24
|
15 |
|
foreach ($usersToCheck as $userToCheck) { |
25
|
|
|
// Check given lastname against all other lastnames that have the same firstname |
26
|
15 |
|
$buildLastName = static function (string $lastName, string $lastNameToCheck, int $i = 1) use ( |
27
|
15 |
|
&$buildLastName |
28
|
15 |
|
): string { |
29
|
|
|
// When $i (amount of letters) of last name to abbreviate is the same as the full name, |
30
|
|
|
// there is no short form and the function must end as it would cause infinite recursion. |
31
|
|
|
// Checks if short form ($i letters from the beginning of lastName) is contained in name to check |
32
|
15 |
|
if (strlen($lastName) > $i && str_contains($lastNameToCheck, substr($lastName, 0, $i))) { |
33
|
|
|
// Increase number of letters that should be used of the last name as it exists in the name to check |
34
|
15 |
|
$i++; |
35
|
15 |
|
$shortName = $buildLastName($lastNameToCheck, $lastName, $i); |
36
|
|
|
} else { |
37
|
|
|
// Return first $i letters of lastname |
38
|
15 |
|
$shortName = substr($lastName, 0, $i); |
39
|
|
|
} |
40
|
|
|
|
41
|
15 |
|
return $shortName; |
42
|
15 |
|
}; |
43
|
|
|
// Always privilege longest lastname abbreviation as it means that this length necessary |
44
|
15 |
|
if (strlen($builtLastName = $buildLastName($lastName, (string)$userToCheck->lastName)) > strlen( |
45
|
15 |
|
$abbreviatedLastName |
46
|
15 |
|
)) { |
47
|
15 |
|
$abbreviatedLastName = $builtLastName; |
48
|
|
|
} |
49
|
|
|
} |
50
|
|
|
// If lastname abbreviation not full lastname, add . |
51
|
15 |
|
if ($abbreviatedLastName !== $lastName) { |
52
|
|
|
$abbreviatedLastName .= '.'; |
53
|
|
|
} |
54
|
|
|
|
55
|
15 |
|
return $abbreviatedLastName; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Find all the names of users for the dropdown. |
60
|
|
|
* Firstnames are privileged but if there is a duplicate, |
61
|
|
|
* the first last name chars are added. |
62
|
|
|
* |
63
|
|
|
* @param UserData[] $users original users |
64
|
|
|
* |
65
|
|
|
* @return array<int, string> array of users with abbreviated full names |
66
|
|
|
*/ |
67
|
21 |
|
public function abbreviateUserNames(array $users): array |
68
|
|
|
{ |
69
|
21 |
|
$outputNames = []; |
70
|
21 |
|
$groupedUsers = []; |
71
|
|
|
|
72
|
|
|
// Group users by first name |
73
|
21 |
|
foreach ($users as $user) { |
74
|
|
|
// Use first_name as array key for duplicates to be grouped |
75
|
20 |
|
$groupedUsers[$user->firstName][$user->id] = $user; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
// Loop over the ordered user array |
79
|
|
|
/** @var UserData[] $usersWithIdenticalFirstName */ |
80
|
21 |
|
foreach ($groupedUsers as $firstName => $usersWithIdenticalFirstName) { |
81
|
|
|
// If there is only one entry it means that it's a unique first name |
82
|
20 |
|
if (count($usersWithIdenticalFirstName) === 1) { |
83
|
|
|
// reset() returns the first value of the array |
84
|
5 |
|
$userWithUniqueFirstName = reset($usersWithIdenticalFirstName); |
85
|
5 |
|
$outputNames[(int)$userWithUniqueFirstName->id] = (string)$userWithUniqueFirstName->firstName; |
86
|
5 |
|
continue; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
// Duplicates |
90
|
15 |
|
foreach ($usersWithIdenticalFirstName as $userId => $user) { |
91
|
|
|
// Make copy of users with identical first name to unset it and pass only the "other" users to the function |
92
|
15 |
|
$usersToCheckAgainst = $usersWithIdenticalFirstName; |
93
|
|
|
// Remove currently iterated user from users to be checked against array |
94
|
15 |
|
unset($usersToCheckAgainst[$userId]); |
95
|
|
|
// Call recursive function which compares last name of currently iterated user with other users with same |
96
|
|
|
// first name and returns the shortest version of non-duplicate lastname |
97
|
15 |
|
$lastNameAbbr = $this->buildLastNameAbbreviation((string)$user->lastName, $usersToCheckAgainst); |
98
|
15 |
|
$outputNames[(int)$userId] = $user->firstName . ' ' . $lastNameAbbr; |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
|
102
|
21 |
|
return $outputNames; |
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
|