Using Spatie/Laravel-Data to validate Filament Forms

Is it possible to take advantage of Spatie/Laravel-Data to validate Filament forms? Looking to integrate both for consistent validation across API, commands, jobs, and Filament forms. Current approach:
$rules = StockMovementData::getValidationRules([]);
return [
TextInput::make('quantity')
->rules($rules['quantity'])
->numeric()
];
$rules = StockMovementData::getValidationRules([]);
return [
TextInput::make('quantity')
->rules($rules['quantity'])
->numeric()
];
While this works for basic rules, it doesn't handle: - Complex validations requiring context (ValidationContext) - Custom messages - Type casting - Data Object reusability Has anyone successfully integrated these tools? Looking for examples or best practices.
Solution:
got it! example: ```php...
Jump to solution
3 Replies
Bruno Silva
Bruno SilvaOP2mo ago
.
jamesdscrdo
jamesdscrdo4w ago
I'm also interested in this, as I plan to use filament/forms only and glue everything with laravel-data..
Solution
Bruno Silva
Bruno Silva4w ago
got it! example:
// UserData
<?php

namespace App\Data;

use App\Actions\CreateUserAction;
use App\Models\User;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Support\Validation\ValidationContext;

class UserData extends Data
{
public function __construct(
public string $name,
public string $email,
public string $password,
) {}

public static function rules(ValidationContext $context): array
{
return [
'name' => [
function ($attribute, $value, $fail) use ($context) {
if ($context->payload['email'] === 'bruno') {
$fail('Cannot use the name bruno in the email');
}
},
],
'email' => ['required', 'email'],
'password' => ['required'],
];
}

public static function messages(): array
{
return [
'name.required' => 'The name is required',
'email.required' => 'The email is required',
'email.email' => 'Invalid email',
];
}

public static function create(array $data): User
{
return CreateUserAction::run(self::validateAndCreate($data));
}
}

// CreateUser
<?php

namespace App\Filament\Resources\UserResource\Pages;

use App\Data\UserData;
use App\Filament\Resources\UserResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\ValidationException;

class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;

protected function handleRecordCreation(array $data): Model
{
try {
return UserData::create($data);
} catch (ValidationException $e) {
$errors = collect($e->errors())->mapWithKeys(function ($messages, $key) {
return ["data.$key" => $messages];
})->toArray();
throw ValidationException::withMessages($errors);
}
}
}
// UserData
<?php

namespace App\Data;

use App\Actions\CreateUserAction;
use App\Models\User;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Support\Validation\ValidationContext;

class UserData extends Data
{
public function __construct(
public string $name,
public string $email,
public string $password,
) {}

public static function rules(ValidationContext $context): array
{
return [
'name' => [
function ($attribute, $value, $fail) use ($context) {
if ($context->payload['email'] === 'bruno') {
$fail('Cannot use the name bruno in the email');
}
},
],
'email' => ['required', 'email'],
'password' => ['required'],
];
}

public static function messages(): array
{
return [
'name.required' => 'The name is required',
'email.required' => 'The email is required',
'email.email' => 'Invalid email',
];
}

public static function create(array $data): User
{
return CreateUserAction::run(self::validateAndCreate($data));
}
}

// CreateUser
<?php

namespace App\Filament\Resources\UserResource\Pages;

use App\Data\UserData;
use App\Filament\Resources\UserResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\ValidationException;

class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;

protected function handleRecordCreation(array $data): Model
{
try {
return UserData::create($data);
} catch (ValidationException $e) {
$errors = collect($e->errors())->mapWithKeys(function ($messages, $key) {
return ["data.$key" => $messages];
})->toArray();
throw ValidationException::withMessages($errors);
}
}
}
Want results from more Discord servers?
Add your server