ldc-bien-etre-animal/app/Http/Requests/ContactRequest.php

139 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Requests;
use App\Enums\Country;
use App\Http\Requests\Concerns\HasEmailRateLimit;
use Axlon\PostalCodeValidation\Rules\PostalCode;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
use Uwil\LaravelCommon\Helpers\ToolboxHelper;
class ContactRequest extends FormRequest
{
use HasEmailRateLimit;
/** @var list<Country> */
private const ALLOWED_COUNTRIES = [
Country::france,
Country::belgium,
];
/** @var list<string> */
private const PROFILES = [
'consommateur',
'eleveur',
];
private ?Country $selectedCountry = null;
public function authorize(): bool
{
// NOTE: Public form
return true;
}
#[\Override]
public function prepareForValidation(): void
{
$countryInput = $this->string('country')->trim()->value();
$matchedCountry = Country::tryFromIso2($countryInput);
if ($matchedCountry && in_array($matchedCountry, self::ALLOWED_COUNTRIES, true)) {
$this->selectedCountry = $matchedCountry;
}
}
/**
* @return array<string, mixed>
*/
public function rules(): array
{
ToolboxHelper::validateRecaptcha($this);
$allowedIso2 = array_map(static fn(Country $c): string => $c->iso2(), self::ALLOWED_COUNTRIES);
$postalCodeRule = $this->selectedCountry !== null
? PostalCode::forCountry($this->selectedCountry->iso2())
: 'string';
return [
'lastName' => ['required', 'string', 'min:3', 'max:50'],
'firstName' => ['required', 'string', 'min:3', 'max:50'],
'email' => ['required', 'string', 'email:strict,rfc,spoof', 'max:255'],
'phone' => ['required', 'phone:' . ($this->selectedCountry?->iso2() ?? implode(',', $allowedIso2))],
'profile' => ['required', 'string', Rule::in(self::PROFILES)],
'company' => ['nullable', 'string', 'min:2', 'max:60'],
'postalCode' => ['nullable', 'required_with:city,country', $postalCodeRule],
'city' => ['nullable', 'required_with:postalCode,country', 'string', 'min:2', 'max:60'],
'country' => ['nullable', 'required_with:city,postalCode', Rule::in($allowedIso2)],
'subject' => ['required', 'string', 'min:3', 'max:100'],
'message' => ['required', 'string', 'min:30', 'max:255'],
'attachment' => ['nullable', 'file', 'max:2048', 'mimes:jpg,jpeg,png', 'extensions:jpg,jpeg,png'],
'acceptsUsage' => ['required', 'accepted'],
];
}
/**
* @return array<string, string>
*/
#[\Override]
public function messages(): array
{
$countryLabels = implode(', ', array_map(
static fn(Country $country): string => $country->label('fr'),
self::ALLOWED_COUNTRIES
));
return [
'phone.phone' => "Le numéro de téléphone doit être un numéro valide pour : {$countryLabels}.",
'postalCode.postal_code' => "Le code postal doit être valide pour le pays sélectionné ({$countryLabels}).",
'country.in' => "Le pays sélectionné doit être l'un des suivants : {$countryLabels}.",
'acceptsUsage.accepted' => "Vous devez accepter l'utilisation de vos données personnelles.",
'g-recaptcha-response.required' => 'Veuillez valider le reCAPTCHA.',
];
}
#[\Override]
public function attributes(): array
{
return [
'lastName' => 'nom',
'firstName' => 'prénom',
'email' => 'adresse email',
'phone' => 'téléphone',
'profile' => 'profil',
'company' => 'société',
'postalCode' => 'code postal',
'city' => 'ville',
'country' => 'pays',
'subject' => 'sujet',
'message' => 'message',
'attachment' => 'pièce jointe',
'acceptsUsage' => 'conditions d\'utilisation',
'g-recaptcha-response' => 'reCAPTCHA',
];
}
protected function rateLimitPrefix(): string
{
return 'contact';
}
protected function rateLimitMaxAttempts(): int
{
return 3;
}
protected function rateLimitMessageKey(): string
{
return 'validation.rate_limit.too_many_attempts';
}
public function withValidator(Validator $validator): void
{
$validator->after(fn(Validator $v) => $this->applyEmailRateLimit($v));
}
}