Mastering Filament Wizards: Advanced Techniques and Best Practices

Mastering Filament Wizards: Advanced Techniques and Best Practices

Wizards in Filament provide a powerful way to break down complex forms into manageable steps. Let's dive deep into advanced techniques and patterns for creating sophisticated wizard interfaces.

Basic Wizard Setup with Advanced Features

use Filament\Forms\Components\Wizard;
use Filament\Forms\Components\Wizard\Step;

public static function form(Form $form): Form
{
    return $form
        ->schema([
            Wizard::make([
                Step::make('Basic Information')
                    ->icon('heroicon-o-user')
                    ->schema([
                        TextInput::make('title')
                            ->required()
                            ->maxLength(255),
                        Select::make('category_id')
                            ->relationship('category', 'name')
                            ->required(),
                    ])
                    ->description('Fill in the basic details'),

                Step::make('Content')
                    ->icon('heroicon-o-document-text')
                    ->schema([
                        RichEditor::make('content')
                            ->required(),
                    ]),

                Step::make('Settings')
                    ->icon('heroicon-o-cog')
                    ->schema([
                        Toggle::make('is_published'),
                        DateTimePicker::make('published_at'),
                    ]),
            ])
            ->skippable() // Allow skipping steps
            ->startOnStep(2) // Start on specific step
            ->submitAction('Create Post') // Custom submit button text
            ->persistStepInQueryString('step') // Persist step in URL
        ]);
}        

Conditional Steps and Dynamic Logic

Wizard::make([
    Step::make('Account Type')
        ->schema([
            Select::make('account_type')
                ->options([
                    'personal' => 'Personal',
                    'business' => 'Business',
                ])
                ->reactive()
                ->required(),
        ]),

    Step::make('Business Details')
        ->schema([
            TextInput::make('company_name'),
            TextInput::make('vat_number'),
        ])
        ->visible(fn (callable $get) => $get('account_type') === 'business'),

    Step::make('Personal Details')
        ->schema([
            TextInput::make('first_name'),
            TextInput::make('last_name'),
        ])
        ->visible(fn (callable $get) => $get('account_type') === 'personal'),
])        

Advanced Validation and Step Dependencies

class CreateUserWizard extends Component implements HasForms
{
    public $state = [
        'account' => [],
        'profile' => [],
        'preferences' => [],
    ];

    protected function getFormSchema(): array
    {
        return [
            Wizard::make([
                Step::make('Account')
                    ->schema([
                        TextInput::make('account.email')
                            ->email()
                            ->required()
                            ->unique('users', 'email'),
                        TextInput::make('account.password')
                            ->password()
                            ->required()
                            ->minLength(8),
                    ])
                    ->beforeValidation(function () {
                        // Custom validation logic
                    }),

                Step::make('Profile')
                    ->schema([
                        FileUpload::make('profile.avatar')
                            ->image()
                            ->maxSize(1024),
                    ])
                    ->afterValidation(function () {
                        // Post-validation processing
                    }),

                Step::make('Preferences')
                    ->schema([
                        CheckboxList::make('preferences.notifications')
                            ->options([
                                'email' => 'Email',
                                'sms' => 'SMS',
                            ]),
                    ]),
            ])
            ->enableStepIndex(false) // Hide step index
            ->disabled(fn () => $this->isProcessing)
        ];
    }
}        

Custom Step Navigation and Actions

Wizard::make([
    // Steps configuration
])
->beforeStep(function ($step, $previousStep) {
    // Logic before moving to next step
    if ($previousStep === 'payment' && !$this->paymentVerified) {
        $this->addError('payment', 'Payment verification failed');
        return false;
    }
    return true;
})
->afterStep(function ($step) {
    // Logic after completing a step
    if ($step === 'document_upload') {
        ProcessUploadedDocuments::dispatch($this->state['documents']);
    }
})
->submitAction(
    Action::make('submit')
        ->label('Complete Registration')
        ->action(function (array $data) {
            // Custom submission logic
        })
)        

Wizard with Progress Tracking

class RegistrationWizard extends Component implements HasForms
{
    public $progress = 0;
    
    protected function getFormSchema(): array
    {
        return [
            Wizard::make([
                // Steps configuration
            ])
            ->afterStep(function ($step) {
                $totalSteps = count($this->getSteps());
                $currentStep = array_search($step, array_keys($this->getSteps())) + 1;
                $this->progress = ($currentStep / $totalSteps) * 100;
            })
        ];
    }

    public function render()
    {
        return view('registration-wizard', [
            'progress' => $this->progress
        ]);
    }
}        

State Management and Data Persistence

class ComplexWizard extends Component implements HasForms
{
    public $state = [];
    
    protected function getFormSchema(): array
    {
        return [
            Wizard::make([
                Step::make('Step 1')
                    ->schema([
                        // Fields
                    ])
                    ->beforeValidation(function () {
                        $this->state['timestamp'] = now();
                    })
                    ->afterValidation(function () {
                        Cache::put(
                            "wizard.{$this->userId}.step1",
                            $this->state,
                            now()->addHour()
                        );
                    }),
            ])
            ->startOnStep(
                Cache::get("wizard.{$this->userId}.lastStep", 1)
            )
        ];
    }
}        

Integration with External Services

Wizard::make([
    Step::make('Payment Information')
        ->schema([
            Select::make('payment_method')
                ->options([
                    'credit_card' => 'Credit Card',
                    'paypal' => 'PayPal',
                ])
                ->reactive(),
            
            Group::make()
                ->schema([
                    TextInput::make('card_number'),
                    TextInput::make('expiry'),
                    TextInput::make('cvv'),
                ])
                ->visible(fn (callable $get) => 
                    $get('payment_method') === 'credit_card'
                ),
        ])
        ->afterValidation(function (array $state) {
            // Integrate with payment gateway
            $response = PaymentGateway::process($state);
            
            if (!$response->successful()) {
                $this->addError(
                    'payment',
                    'Payment processing failed: ' . $response->message
                );
                return false;
            }
        }),
])        

Best Practices and Tips


1. Break Down Complex Forms:

protected function getSteps(): array
{
    return [
        'basic' => $this->getBasicInformationStep(),
        'details' => $this->getDetailedInformationStep(),
        'review' => $this->getReviewStep(),
    ];
}

protected function getBasicInformationStep(): Step
{
    return Step::make('Basic Information')
        ->schema([
            // Fields
        ]);
}        

2. Handle Errors Gracefully:

->afterStep(function ($step) {
    try {
        // Process step
    } catch (Exception $e) {
        Log::error('Wizard step failed', [
            'step' => $step,
            'error' => $e->getMessage(),
        ]);
        
        $this->addError('wizard', 'An error occurred');
        return false;
    }
})        

3. Implement Save Draft Functionality:

public function saveDraft()
{
    $data = $this->form->getState();
    
    Draft::create([
        'user_id' => auth()->id(),
        'data' => $data,
        'step' => $this->currentStep,
    ]);
    
    Notification::make()
        ->title('Draft saved successfully')
        ->success()
        ->send();
}        

These advanced techniques will help you create sophisticated wizard interfaces that handle complex workflows while maintaining a great user experience. Remember to consider validation, state management, and error handling when implementing these features.

要查看或添加评论,请登录

Ali Mousavi的更多文章

社区洞察

其他会员也浏览了