feat: unique email addresses of participants unless child, cleanup

addresses #869axbn21
This commit is contained in:
Björn Fromme committed 2025-10-22 17:42:17 +02:00
1 parent be2fffad23
commit 9c716477aa
57 files changed
+1036 -153

No files matched your search

@@ -13,16 +13,18 @@ namespace App\Controller\Booking\Traits;
trait ParticipantValidationTrait
{
/**
* Extracts participant indices that have validation errors.
* Extracts participant validation errors from form.
*
* Parses form errors to identify which participants have validation issues.
* Returns an array of participant indices (e.g., [0, 2, 5]).
* Returns two arrays:
* - errorIndices: Array of participant indices with errors (e.g., [0, 2, 5])
* - errorMessages: Map of participant index to error messages (e.g., [0 => ['E-Mail: ...', 'Vorname: ...']])
*
* @return array<int> Array of participant indices with errors
* @return array{errorIndices: array<int>, errorMessages: array<int, array<string>>}
*/
private function extractParticipantErrorIndices($form): array
private function extractParticipantValidationErrors($form): array
{
$errorIndices = [];
$errorMessages = [];
$errors = $form->getErrors(true); // Get all errors recursively
foreach ($errors as $error) {
@@ -31,13 +33,66 @@ trait ParticipantValidationTrait
continue;
}
// Property paths look like "participants[0].firstName" or "participants[1].email"
if (preg_match('/participants\[(\d+)]/', $propertyPath, $matches)) {
// Property paths from BookingDto validation look like "participants[0].email"
// Note: Using more flexible regex to capture field path after index
if (preg_match('/participants\[(\d+)\]\.?(.*)/', (string) $propertyPath, $matches)) {
$index = (int) $matches[1];
$errorIndices[$index] = true; // Use array key to avoid duplicates
$fieldPath = $matches[2] ?? '';
$message = $error->getMessage();
// Mark this participant as having errors
$errorIndices[$index] = true;
// Initialize error messages array for this participant if needed
if (false === isset($errorMessages[$index])) {
$errorMessages[$index] = [];
}
// Add formatted error message
$errorMessages[$index][] = $this->formatErrorMessage($fieldPath, $message);
}
}
return array_keys($errorIndices);
return [
'errorIndices' => array_keys($errorIndices),
'errorMessages' => $errorMessages,
];
}
/**
* Formats an error message with field context.
*
* @param string $fieldPath The field path that has the error (may be empty or nested)
* @param string $message The error message
*
* @return string Formatted error message
*/
private function formatErrorMessage(string $fieldPath, string $message): string
{
// If no field path, return just the message (error is on participant level)
if ('' === trim($fieldPath)) {
return $message;
}
// Extract the first part of the path for nested fields (e.g., "address.street" -> "address")
$fieldName = explode('.', $fieldPath)[0];
// Field name translations for better user understanding
$fieldLabels = [
'email' => 'E-Mail',
'firstName' => 'Vorname',
'lastName' => 'Nachname',
'dateOfBirth' => 'Geburtsdatum',
'assignedRoomId' => 'Zimmer',
'skiPass' => 'Skipass',
'transportationOutbound' => 'Anreise',
'transportationInbound' => 'Rückreise',
'mobile' => 'Mobilnummer',
'address' => 'Adresse',
];
$fieldLabel = $fieldLabels[$fieldName] ?? $fieldName;
return sprintf('%s: %s', $fieldLabel, $message);
}
}