From 9629ba087f14519e753db6a2d12925264b178110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdi=20U=CC=88NAL?= Date: Thu, 26 Sep 2024 18:25:46 +0300 Subject: [PATCH 1/3] feat: add rules support for per translations --- .../Concerns/HasTranslatableValidation.php | 22 ++++++++++ .../CreateRecord/Concerns/Translatable.php | 41 ++++++++++++++++++- .../EditRecord/Concerns/Translatable.php | 14 ++++++- 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/Resources/Pages/Concerns/HasTranslatableValidation.php diff --git a/src/Resources/Pages/Concerns/HasTranslatableValidation.php b/src/Resources/Pages/Concerns/HasTranslatableValidation.php new file mode 100644 index 0000000..ba2026b --- /dev/null +++ b/src/Resources/Pages/Concerns/HasTranslatableValidation.php @@ -0,0 +1,22 @@ +form->getComponents(); + + foreach ($components as $component) { + $rules = $component->getValidationRules(); + if (! empty($rules[$locale])) { + $component->rule($rules[$locale]); + break; + } + } + } +} diff --git a/src/Resources/Pages/CreateRecord/Concerns/Translatable.php b/src/Resources/Pages/CreateRecord/Concerns/Translatable.php index 38afb8c..af570e1 100644 --- a/src/Resources/Pages/CreateRecord/Concerns/Translatable.php +++ b/src/Resources/Pages/CreateRecord/Concerns/Translatable.php @@ -4,6 +4,7 @@ use Filament\Facades\Filament; use Filament\Resources\Concerns\HasActiveLocaleSwitcher; +use Filament\Resources\Pages\Concerns\HasTranslatableValidation; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; use Illuminate\Validation\ValidationException; @@ -12,6 +13,7 @@ trait Translatable { use HasActiveLocaleSwitcher; + use HasTranslatableValidation; protected ?string $oldActiveLocale = null; @@ -28,6 +30,28 @@ public function getTranslatableLocales(): array return static::getResource()::getTranslatableLocales(); } + public function beforeFill() + { + /** + * For the rules assigned to the locales to work properly, + * an empty form state must be created for each local. + */ + if (empty($this->otherLocaleData)) { + $components = $this->form->getComponents(); + $formData = collect($components) + ->mapWithKeys( + fn ($component) => [ + $component->getName() => null, + ]) + ->toArray(); + foreach ($this->getTranslatableLocales() as $locale) { + $this->otherLocaleData[$locale] = []; + + $this->otherLocaleData[$locale] = $formData; + } + } + } + protected function handleRecordCreation(array $data): Model { $record = app(static::getModel()); @@ -42,7 +66,17 @@ protected function handleRecordCreation(array $data): Model $originalData = $this->data; + /** + * Set the data for the active locale. + */ + $this->otherLocaleData[$this->activeLocale] = Arr::only($this->data, $translatableAttributes); + foreach ($this->otherLocaleData as $locale => $localeData) { + /** + * Set the validation rules for the active locale. + */ + $this->setLocaleByRules($locale); + $this->data = [ ...$this->data, ...$localeData, @@ -51,7 +85,12 @@ protected function handleRecordCreation(array $data): Model try { $this->form->validate(); } catch (ValidationException $exception) { - continue; + /** + * If the validation fails for the active locale, set the active locale + */ + $this->activeLocale = $locale; + + throw $exception; } $localeData = $this->mutateFormDataBeforeCreate($localeData); diff --git a/src/Resources/Pages/EditRecord/Concerns/Translatable.php b/src/Resources/Pages/EditRecord/Concerns/Translatable.php index a18e7dd..9eb93e2 100644 --- a/src/Resources/Pages/EditRecord/Concerns/Translatable.php +++ b/src/Resources/Pages/EditRecord/Concerns/Translatable.php @@ -5,6 +5,7 @@ use Filament\Resources\Concerns\HasActiveLocaleSwitcher; use Filament\Resources\Pages\Concerns\HasTranslatableFormWithExistingRecordData; use Filament\Resources\Pages\Concerns\HasTranslatableRecord; +use Filament\Resources\Pages\Concerns\HasTranslatableValidation; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; use Illuminate\Validation\ValidationException; @@ -14,6 +15,7 @@ trait Translatable use HasActiveLocaleSwitcher; use HasTranslatableFormWithExistingRecordData; use HasTranslatableRecord; + use HasTranslatableValidation; protected ?string $oldActiveLocale = null; @@ -34,9 +36,19 @@ protected function handleRecordUpdate(Model $record, array $data): Model $originalData = $this->data; + /** + * Set the data for the active locale. + */ + $this->otherLocaleData[$this->activeLocale] = Arr::only($this->data, $translatableAttributes); + $existingLocales = null; foreach ($this->otherLocaleData as $locale => $localeData) { + /** + * Set the locale for the validation rules. + */ + $this->setLocaleByRules($locale); + $existingLocales ??= collect($translatableAttributes) ->map(fn (string $attribute): array => array_keys($record->getTranslations($attribute))) ->flatten() @@ -51,7 +63,7 @@ protected function handleRecordUpdate(Model $record, array $data): Model try { $this->form->validate(); } catch (ValidationException $exception) { - if (! array_key_exists($locale, $existingLocales)) { + if (! in_array($locale, $existingLocales, true)) { continue; } From 6c39192d98e5de6306844318d045a3eb4d1c473a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdi=20U=CC=88NAL?= Date: Thu, 26 Sep 2024 19:44:06 +0300 Subject: [PATCH 2/3] refactor: Correction related to accesses of form components. --- .../Pages/Concerns/HasTranslatableValidation.php | 7 ++++++- .../Pages/CreateRecord/Concerns/Translatable.php | 11 +++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Resources/Pages/Concerns/HasTranslatableValidation.php b/src/Resources/Pages/Concerns/HasTranslatableValidation.php index ba2026b..8cbf546 100644 --- a/src/Resources/Pages/Concerns/HasTranslatableValidation.php +++ b/src/Resources/Pages/Concerns/HasTranslatableValidation.php @@ -2,6 +2,8 @@ namespace Filament\Resources\Pages\Concerns; +use Filament\Forms\Components\Contracts\HasValidationRules; + trait HasTranslatableValidation { /** @@ -9,7 +11,10 @@ trait HasTranslatableValidation */ public function setLocaleByRules(string $locale): void { - $components = $this->form->getComponents(); + $components = array_filter( + $this->form->getFlatComponents(), + fn ($component) => $component instanceof HasValidationRules + ); foreach ($components as $component) { $rules = $component->getValidationRules(); diff --git a/src/Resources/Pages/CreateRecord/Concerns/Translatable.php b/src/Resources/Pages/CreateRecord/Concerns/Translatable.php index af570e1..c597501 100644 --- a/src/Resources/Pages/CreateRecord/Concerns/Translatable.php +++ b/src/Resources/Pages/CreateRecord/Concerns/Translatable.php @@ -3,6 +3,7 @@ namespace Filament\Resources\Pages\CreateRecord\Concerns; use Filament\Facades\Filament; +use Filament\Forms\Components\Contracts\HasValidationRules; use Filament\Resources\Concerns\HasActiveLocaleSwitcher; use Filament\Resources\Pages\Concerns\HasTranslatableValidation; use Illuminate\Database\Eloquent\Model; @@ -37,12 +38,14 @@ public function beforeFill() * an empty form state must be created for each local. */ if (empty($this->otherLocaleData)) { - $components = $this->form->getComponents(); + $components = $this->form->getFlatComponents(); $formData = collect($components) + ->filter( + fn ($component) => $component instanceof HasValidationRules + ) ->mapWithKeys( - fn ($component) => [ - $component->getName() => null, - ]) + fn ($component) => [$component->getName() => null] + ) ->toArray(); foreach ($this->getTranslatableLocales() as $locale) { $this->otherLocaleData[$locale] = []; From cda2ca00a3105fe4d4424aa21718e9cba08894f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdi=20U=CC=88NAL?= Date: Thu, 26 Sep 2024 20:58:30 +0300 Subject: [PATCH 3/3] refactor: updated the readme on how to use form validation --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index 48fc07e..24915b1 100644 --- a/README.md +++ b/README.md @@ -275,3 +275,39 @@ If you wish to translate the package, you may publish the language files using: ```bash php artisan vendor:publish --tag=filament-spatie-laravel-translatable-plugin-translations ``` + +## Form Validation + +You can define and use form validation rules according to the locale as follows. + +```php +public static function form(Form $form): Form +{ + return $form + ->schema([ + Forms\Components\TextInput::make('name') + ->label(__('Category Name')) + ->helperText(__('This is the name of the category.')) + ->rules(function (?Category $record) { + return [ + 'tr' => [ + 'required', + 'string', + 'max:100', + Rule::unique('tags', 'name->tr') + ->where('type', 'category') + ->ignore($record?->id, 'id') + ], + 'en' => [ + 'required', + 'string', + 'max:100', + Rule::unique('tags', 'name->en') + ->where('type', 'category') + ->ignore($record?->id, 'id') + ], + ]; + }) + ]); +} +```