feat(i18n): accessibility - per-field form errors, landmark aria-labels, tests (closes #76)
This commit is contained in:
@@ -32,15 +32,25 @@ class HomeController extends Controller
|
||||
};
|
||||
|
||||
// ── Pull flashed state ────────────────────────────────────────
|
||||
$formSuccess = !empty($_SESSION['form_success']);
|
||||
$formErrors = $_SESSION['form_errors'] ?? [];
|
||||
$formData = $_SESSION['form_data'] ?? null;
|
||||
unset($_SESSION['form_success'], $_SESSION['form_errors'], $_SESSION['form_data']);
|
||||
$formSuccess = !empty($_SESSION['form_success']);
|
||||
$formErrors = $_SESSION['form_errors'] ?? [];
|
||||
$formFieldErrors = $_SESSION['form_field_errors'] ?? [];
|
||||
$formData = $_SESSION['form_data'] ?? null;
|
||||
unset(
|
||||
$_SESSION['form_success'],
|
||||
$_SESSION['form_errors'],
|
||||
$_SESSION['form_field_errors'],
|
||||
$_SESSION['form_data'],
|
||||
);
|
||||
|
||||
if ($formSuccess) {
|
||||
$formData = ['fname' => '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'visit', 'message' => ''];
|
||||
$formData = self::emptyFormData();
|
||||
$formFieldErrors = [];
|
||||
} elseif (!is_array($formData)) {
|
||||
$formData = ['fname' => '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'visit', 'message' => ''];
|
||||
$formData = self::emptyFormData();
|
||||
$formFieldErrors = is_array($formFieldErrors) ? $formFieldErrors : [];
|
||||
} else {
|
||||
$formFieldErrors = is_array($formFieldErrors) ? $formFieldErrors : [];
|
||||
}
|
||||
|
||||
// ── CSRF token ────────────────────────────────────────────────
|
||||
@@ -72,17 +82,19 @@ class HomeController extends Controller
|
||||
exit;
|
||||
}
|
||||
|
||||
// Per-field errors enable aria-invalid + aria-describedby.
|
||||
$formFieldErrors = [];
|
||||
if ($formData['fname'] === '') {
|
||||
$formErrors[] = 'form.error.fname_required';
|
||||
$formFieldErrors['fname'][] = 'form.error.fname_required';
|
||||
}
|
||||
if ($formData['lname'] === '') {
|
||||
$formErrors[] = 'form.error.lname_required';
|
||||
$formFieldErrors['lname'][] = 'form.error.lname_required';
|
||||
}
|
||||
if ($formData['email'] === '' || !filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$formErrors[] = 'form.error.email_invalid';
|
||||
$formFieldErrors['email'][] = 'form.error.email_invalid';
|
||||
}
|
||||
if ($formData['message'] === '') {
|
||||
$formErrors[] = 'form.error.message_required';
|
||||
$formFieldErrors['message'][] = 'form.error.message_required';
|
||||
}
|
||||
if ($containsHeaderInjection($formData['email']) || $containsHeaderInjection($formData['fname'] . ' ' . $formData['lname'])) {
|
||||
$formErrors[] = 'form.error.header_injection';
|
||||
@@ -98,7 +110,7 @@ class HomeController extends Controller
|
||||
$formErrors[] = 'form.error.rate_limit';
|
||||
}
|
||||
|
||||
if (empty($formErrors)) {
|
||||
if (empty($formErrors) && empty($formFieldErrors)) {
|
||||
$interestKey = self::INTEREST_KEYS[$formData['interest']] ?? 'form.interest.visit';
|
||||
$interestLabel = I18n::t($interestKey, [], $locale);
|
||||
|
||||
@@ -129,8 +141,9 @@ class HomeController extends Controller
|
||||
$formErrors[] = 'form.error.send_failed';
|
||||
}
|
||||
|
||||
$_SESSION['form_errors'] = $formErrors;
|
||||
$_SESSION['form_data'] = $formData;
|
||||
$_SESSION['form_errors'] = $formErrors;
|
||||
$_SESSION['form_field_errors'] = $formFieldErrors;
|
||||
$_SESSION['form_data'] = $formData;
|
||||
header('Location: /#kontakt');
|
||||
exit;
|
||||
}
|
||||
@@ -177,10 +190,26 @@ class HomeController extends Controller
|
||||
$this->render('home/index', [
|
||||
'formSuccess' => $formSuccess,
|
||||
'formErrors' => $formErrors,
|
||||
'formFieldErrors' => $formFieldErrors,
|
||||
'formData' => $formData,
|
||||
'interestKeys' => self::INTEREST_KEYS,
|
||||
'escapeContactValue' => $escapeContactValue,
|
||||
'structuredData' => $structuredData,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{fname: string, lname: string, email: string, phone: string, interest: string, message: string}
|
||||
*/
|
||||
private static function emptyFormData(): array
|
||||
{
|
||||
return [
|
||||
'fname' => '',
|
||||
'lname' => '',
|
||||
'email' => '',
|
||||
'phone' => '',
|
||||
'interest' => 'visit',
|
||||
'message' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user