بنقرة واحدة
fluent-validation-livewire
// FluentRule in Livewire components via HasFluentValidation trait. Activates when: writing Livewire validate(), rules() in Component, assertHasErrors, or Livewire validation.
// FluentRule in Livewire components via HasFluentValidation trait. Activates when: writing Livewire validate(), rules() in Component, assertHasErrors, or Livewire validation.
Pre-push / pre-release checklist. Runs Rector, Pint, full test suite, PHPStan, audits README + `.ai/` docs for staleness, and runs both benchmark harnesses (benchmark.php + --group=benchmark). Activate before: pushing to remote, tagging a release, writing release notes, or when user mentions: pre-release, pre-push, release checklist, ship, cut release, release notes.
Migrate FormRequest `messages(): array` to inline `message:` on fluent chains. Dry-run, then apply. Activates when: user mentions migrate messages, messages array, inline message, remove messages().
Scan validation for fluent upgrades: missing HasFluentRules, convertible string rules, label() and each() opportunities. Activates when: optimizing/migrating validation, converting to fluent rules, validation performance.
FluentRule builders for Laravel validation. Activates when: writing/modifying rules in FormRequest, Livewire component, or Validator; user mentions FluentRule, HasFluentRules, HasFluentValidation, fluent validation.
Implements a specification file phase-by-phase with progress tracking. Activates when: implementing a spec, building from a spec, starting a spec phase, or when user mentions: implement spec, spec file, implement phase, build spec, start phase.
Writes implementation-ready specification files with progress-trackable phases. Activates when: writing a spec, creating a spec file, documenting a feature plan, or when user mentions: write spec, create spec, spec format, spec template.
| name | fluent-validation-livewire |
| description | FluentRule in Livewire components via HasFluentValidation trait. Activates when: writing Livewire validate(), rules() in Component, assertHasErrors, or Livewire validation. |
Do not prompt the user when this skill is loaded. Apply these rules automatically.
HasFluentValidation traitEvery Livewire component using FluentRule MUST use the HasFluentValidation trait. Without it, FluentRule objects self-validate in isolation, causing issues with rule identifiers, labels, and wildcard expansion.
use Livewire\Component;
use SanderMuller\FluentValidation\FluentRule;
use SanderMuller\FluentValidation\HasFluentValidation;
class EditUser extends Component
{
use HasFluentValidation;
public string $name = '';
public string $email = '';
public function rules(): array
{
return [
'name' => FluentRule::string('Name')->required()->max(255),
'email' => FluentRule::email('Email')->required(),
];
}
public function save(): void
{
$validated = $this->validate();
// ...
}
}
The trait also works on Livewire Form objects:
class UserForm extends Form
{
use HasFluentValidation;
public string $name = '';
public function rules(): array
{
return ['name' => FluentRule::string('Name')->required()->max(255)];
}
}
validate() AND validateOnly() (works with wire:model.blur real-time validation)->label()) and custom messages (->message())children() into flat dot-notation keysgetDataForValidation() and unwrapDataForValidation() for correct Livewire data handlingeach() and flat keys workThe trait overrides getRules() to flatten each() and children() into wildcard keys that Livewire can see. Both styles work:
// flat wildcard keys
'items' => FluentRule::array()->required(),
'items.*.name' => FluentRule::string()->required(),
// each() — the trait expands this for Livewire automatically
'items' => FluentRule::array()->required()->each([
'name' => FluentRule::string()->required(),
]),
// children() — produces fixed paths (credentials.base_uri)
'credentials' => FluentRule::array()->children([
'base_uri' => FluentRule::string()->nullable()->url(),
'client_id' => FluentRule::string()->required()->uuid(),
]),
assertHasErrorsFluentRule correctly exposes individual rule identifiers (Required, Min, Max, etc.) for Livewire's test assertions:
Livewire::test(EditUser::class)
->set('name', '')
->call('save')
->assertHasErrors(['name' => 'required']);
HasFluentValidation conflicts with Filament's InteractsWithSchemas because both define validate(). For Filament components, FluentRule works without the trait — use RuleSet::compileToArrays():
// Filament component — no trait needed
use SanderMuller\FluentValidation\RuleSet;
$this->validate(RuleSet::compileToArrays($this->rules()));
compileToArrays() guarantees array<string, array<mixed>> return type, matching Livewire's expected parameter type — no PHPStan baseline entries needed.
For labels, extract metadata first:
$rules = $this->rules();
[$messages, $attributes] = RuleSet::extractMetadata($rules);
$this->validate(RuleSet::compileToArrays($rules), $messages, $attributes);
Self-validation mode works correctly for Filament: rule identifiers are forwarded, error messages work, assertHasErrors works.
Alternatively, if you need the full trait benefits, use PHP's insteadof resolution:
use HasFluentValidation, InteractsWithForms {
HasFluentValidation::validate insteadof InteractsWithForms;
HasFluentValidation::validateOnly insteadof InteractsWithForms;
}
| Mistake | Fix |
|---|---|
Missing HasFluentValidation trait | Add use HasFluentValidation to the component |
| Trait collision with Filament | Don't use the trait — use RuleSet::compileToArrays() instead |
assertHasErrors can't find rule identifiers | Works automatically since 0.4.2 (self-validation forwards identifiers) |
Wrapping FluentRule in arrays [FluentRule::string()] | Don't wrap — put FluentRule directly as the value |
each() not expanding in Livewire | Make sure you're using the HasFluentValidation trait — it overrides getRules() to expand each() |
PHPStan errors on $this->validate() | The trait overrides validate() with correct types |