Step Lifecycle
Understanding how and when your step methods are called.
#The flow
When a user lands on your step, here's what happens:
- **mount()** - Component initializes, load existing data
- User fills the form
- User clicks "Continue"
- **validateStep()** - Validate form data
- **execute()** - Save data if validation passes
- Navigate to next step
If validation fails, the user stays on your step and sees error messages.
#Method execution order
Component Created ↓ mount() ↓ render() ← Shows the form ↓User clicks "Continue" ↓validateStep() ↓Did validation pass? ↙ ↘ No Yes ↓ ↓render() execute()(errors) ↓ render() ↓ Next step
#Detailed breakdown
#Component initialization
protected function mount(): void{ $this->loadFormData();}
Runs once when the step loads. Use it to:
- Load data from session
- Set default values
- Initialize component state
**Example with defaults:**
protected function mount(): void{ $this->loadFormData(); if (empty($this->formData['port'])) { $this->formData['port'] = 3306; }}
#User interaction
User fills the form. Livewire automatically syncs wire:model fields to $this->formData.
No code needed - it just works.
#Form submission
User clicks your submit button:
<x-installer::button type="submit" wireTarget="submit"> Continue</x-installer::button>
This calls the submit() method inherited from BaseStep. You never override this method.
#Validation phase
protected function validateStep(): void{ $this->validate();}
Called automatically by submit(). Validation rules come from rules().
**If validation fails:**
- User stays on current step
- Error messages display via
<x-installer::form.error /> -
execute()is NOT called
**If validation passes:**
- Continue to execution phase
#Execution phase
protected function execute(): void{ $this->saveToSession('yourplugin', $this->formData);}
Only runs if validation passed. Use it to:
- Save data to session
- Make API calls
- Update database (if migrations ran)
- Set success messages
**Example with API call:**
protected function execute(): void{ // Always save to session first $this->saveToSession('license', $this->formData); // Then do additional work try { $response = Http::post('https://api.example.com/verify', [ 'license' => $this->formData['license_key'], ]); if ($response->successful()) { $this->successMessage = __('license::license.verified'); } else { $this->errorMessage = __('license::license.invalid'); } } catch (\Exception $e) { $this->errorMessage = __('license::license.error'); }}
#Navigation
After execute() completes, the installer:
- Calls
render()one final time - Navigates to the next step
- The next step's
mount()is called
#Property persistence
Livewire persists these properties between requests:
public $formData = [];public $errorMessage = '';public $successMessage = '';
Set them in any method, they'll be available in the view:
protected function execute(): void{ $this->saveToSession('app', $this->formData); $this->successMessage = 'Settings saved!';}
@if($successMessage) <x-installer::alert.success> {{ $successMessage }} </x-installer::alert.success>@endif
#Session data flow
Session is the single source of truth until migrations run:
Step 1: execute() ↓saveToSession('welcome', [...]) ↓Session: {welcome: {...}} Step 2: execute() ↓saveToSession('database', [...]) ↓Session: {welcome: {...}, database: {...}} Step 3: execute() ↓Database migrations run ↓Move session data to database ↓Session cleared
Access data from previous steps:
protected function mount(): void{ $this->loadFormData(); $databaseConfig = $this->getFromSession('database'); $appName = $this->getFromSession('app.app_name');}
#Skipping steps
Steps can be conditional. Override shouldDisplay():
public function shouldDisplay(): bool{ // Only show this step if license verification is enabled return config('installer.require_license', false);}
If shouldDisplay() returns false, the step is skipped entirely. None of its methods run.
#Error handling
Validation errors show automatically via <x-installer::form.error />.
For custom errors, use $this->errorMessage:
protected function execute(): void{ try { // Some operation } catch (\Exception $e) { $this->errorMessage = __('yourplugin::yourplugin.error'); return; // Stop execution } $this->successMessage = __('yourplugin::yourplugin.success');}
Display in the view:
@if($errorMessage) <x-installer::alert.error> {{ $errorMessage }} </x-installer::alert.error>@endif
#Re-rendering
Livewire re-renders your component automatically:
- After
mount() - After any Livewire action (like
submit()) - When properties change
Each time, render() is called with fresh data:
public function render(){ return view('yourplugin::livewire.steps.your-step', [ 'fields' => config('installer-yourplugin.form_fields'), 'isVerified' => $this->isVerified(), ]);}
#Next steps
- Follow best practices: Best Practices
- See helper traits in action: Helper Traits
- View a complete example: Complete Plugin Example