diff --git a/config/custom-fields.php b/config/custom-fields.php index 61b06045..b2e1051c 100644 --- a/config/custom-fields.php +++ b/config/custom-fields.php @@ -79,6 +79,30 @@ 'cluster' => null, ], + /* + |-------------------------------------------------------------------------- + | Field Settings + |-------------------------------------------------------------------------- + | + | Configure default settings for custom fields. + | + */ + 'fields' => [ + 'description_max_length' => 255, + ], + + /* + |-------------------------------------------------------------------------- + | Section Settings + |-------------------------------------------------------------------------- + | + | Configure default settings for custom field sections. + | + */ + 'sections' => [ + 'description_max_length' => 255, + ], + /* |-------------------------------------------------------------------------- | Database Configuration diff --git a/src/Filament/Integration/Base/AbstractFormComponent.php b/src/Filament/Integration/Base/AbstractFormComponent.php index 132492bc..45b00e80 100644 --- a/src/Filament/Integration/Base/AbstractFormComponent.php +++ b/src/Filament/Integration/Base/AbstractFormComponent.php @@ -85,7 +85,11 @@ function (Field $field) use ($customField): Field { $this->coreVisibilityLogic->shouldAlwaysSave($customField) || filled($state) ) - ->required($this->validationService->isRequired($customField)) + ->when( + $this->validationService->isRequired($customField) && $customField->typeData->dataType->isBoolean(), + fn (Field $field): Field => $field->markAsRequired(), + fn (Field $field): Field => $field->required($this->validationService->isRequired($customField)), + ) ->rules(fn (Field $component): array => $this->getFieldValidationRules( $customField, $component->getRecord()?->getKey() diff --git a/src/Filament/Management/Schemas/FieldForm.php b/src/Filament/Management/Schemas/FieldForm.php index 226f7aaa..97609db5 100644 --- a/src/Filament/Management/Schemas/FieldForm.php +++ b/src/Filament/Management/Schemas/FieldForm.php @@ -272,7 +272,7 @@ public static function schema(bool $withOptionsRelationship = true): array ]), Textarea::make('settings.description') ->label(__('custom-fields::custom-fields.field.form.description')) - ->maxLength(255) + ->maxLength(config('custom-fields.fields.description_max_length', 255)) ->rows(2) ->live(onBlur: true) ->columnSpanFull() diff --git a/src/Filament/Management/Schemas/SectionForm.php b/src/Filament/Management/Schemas/SectionForm.php index 5e21918e..1d0bb5ba 100644 --- a/src/Filament/Management/Schemas/SectionForm.php +++ b/src/Filament/Management/Schemas/SectionForm.php @@ -147,7 +147,7 @@ public static function schema(): array fn (Get $get): bool => $get('type') === CustomFieldSectionType::SECTION ) - ->maxLength(255) + ->maxLength(config('custom-fields.sections.description_max_length', 255)) ->nullable() ->columnSpan(12), ...self::visibilitySchema(), diff --git a/src/Services/ValidationService.php b/src/Services/ValidationService.php index 912aaacf..8b5c8b82 100644 --- a/src/Services/ValidationService.php +++ b/src/Services/ValidationService.php @@ -209,6 +209,10 @@ private function getTypeSpecificRules(CustomField $customField, string|int|null $rules[] = $decimalPlaces === 0 ? 'integer' : 'decimal:0,'.$decimalPlaces; } + if ($this->isRequired($customField) && $customField->typeData->dataType->isBoolean()) { + $rules[] = 'accepted'; + } + return $rules; } diff --git a/tests/Feature/Integration/ValidationCapabilitiesTest.php b/tests/Feature/Integration/ValidationCapabilitiesTest.php index 7915af22..077005e1 100644 --- a/tests/Feature/Integration/ValidationCapabilitiesTest.php +++ b/tests/Feature/Integration/ValidationCapabilitiesTest.php @@ -458,3 +458,45 @@ function validationSubmitEdit(Post $post, array $customFields): Testable ->assertHasNoFormErrors() ->assertRedirect(); }); + +// =========================================================================== +// Required boolean (checkbox/toggle) validation +// =========================================================================== + +it('rejects required checkbox with false value', function (): void { + createField($this, 'agree_terms', 'checkbox', ['required' => true]); + + validationSubmitCreate($this, ['agree_terms' => false]) + ->assertHasFormErrors(['custom_fields.agree_terms']); +}); + +it('accepts required checkbox with true value', function (): void { + createField($this, 'agree_terms', 'checkbox', ['required' => true]); + + validationSubmitCreate($this, ['agree_terms' => true]) + ->assertHasNoFormErrors() + ->assertRedirect(); +}); + +it('rejects required toggle with false value', function (): void { + createField($this, 'opt_in', 'toggle', ['required' => true]); + + validationSubmitCreate($this, ['opt_in' => false]) + ->assertHasFormErrors(['custom_fields.opt_in']); +}); + +it('accepts required toggle with true value', function (): void { + createField($this, 'opt_in', 'toggle', ['required' => true]); + + validationSubmitCreate($this, ['opt_in' => true]) + ->assertHasNoFormErrors() + ->assertRedirect(); +}); + +it('accepts non-required checkbox with false value', function (): void { + createField($this, 'newsletter', 'checkbox'); + + validationSubmitCreate($this, ['newsletter' => false]) + ->assertHasNoFormErrors() + ->assertRedirect(); +});