|string> */ public function rules(): array { return [ 'deviceName' => ['sometimes', 'string', 'max:255'], 'device_name' => ['sometimes', 'string', 'max:255'], 'name' => [ 'required', 'string', 'min:3', 'max:32', 'regex:/^[a-zA-Z0-9_.-]+$/', 'unique:users,name', ], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'locale' => ['sometimes', 'string', Rule::in(config('app.supported_locales', ['fr', 'en']))], 'password' => [ 'required', 'string', Password::min(8) ->mixedCase() ->letters() ->numbers() ->symbols() ->uncompromised(), ], 'termsAccepted' => ['required', 'accepted'], 'avatar' => ['sometimes', 'nullable', 'image', 'max:2048'], 'bio' => ['nullable', 'string'], ]; } public function messages(): array { return [ 'avatar.max' => __('api.validation.image_max_2mb'), ]; } public function after(): array { return $this->moderationChecks( [$this->input('name'), $this->input('bio')], [$this->file('avatar')], ); } protected function prepareForValidation(): void { if ($this->has('locale')) { $this->merge([ 'locale' => $this->normalizeLocale((string) $this->input('locale')), ]); } if ($this->has('deviceName') && ! $this->has('device_name')) { $this->merge([ 'device_name' => $this->input('deviceName'), ]); } } private function normalizeLocale(string $locale): string { $locale = strtolower(str_replace('_', '-', $locale)); return explode('-', $locale)[0]; } }