Installation:
composer require pixelworxio/livewire-workflows
Publish config (if needed):
php artisan vendor:publish --provider="Pixelworxio\LivewireWorkflows\LivewireWorkflowsServiceProvider"
Define a Workflow:
Register workflows in a service provider (e.g., AppServiceProvider):
use Pixelworxio\LivewireWorkflows\Facades\Workflow;
public function boot()
{
Workflow::flow('checkout')
->entersAt(name: 'checkout.start', path: '/checkout')
->finishesAt('checkout.complete')
->step('cart-review')
->goTo(CartReview::class)
->order(10)
->step('payment')
->goTo(PaymentForm::class)
->order(20);
}
First Use Case:
CartReview).public $workflow;
public $step;
public function mount()
{
$this->workflow = Workflow::getCurrent();
$this->step = $this->workflow->getCurrentStep();
}
public function proceed()
{
$this->workflow->proceed();
}
Workflow Definition:
Workflow::flow() to define a named workflow (e.g., onboarding, checkout).entersAt(), finishesAt(), and step() for declarative setup.Workflow::flow('checkout')
->entersAt(name: 'checkout.start', path: '/checkout')
->finishesAt('checkout.complete')
->step('cart')
->goTo(Cart::class)
->unlessPasses(HasItemsGuard::class)
->order(10)
->step('shipping')
->goTo(Shipping::class)
->unlessPasses(ShippingInfoGuard::class)
->order(20);
Step Components:
Cart, Shipping).$workflow and $step properties.proceed() to advance to the next step:
public function proceed()
{
if ($this->workflow->proceed()) {
return redirect()->to($this->workflow->getNextStepPath());
}
// Handle validation errors or guards
}
Guards:
unlessPasses(), onlyIfPasses()).Pixelworxio\LivewireWorkflows\Contracts\Guard:
class HasItemsGuard implements Guard
{
public function passes($workflow, $step): bool
{
return Cart::count() > 0;
}
}
State Persistence:
$currentStep = $this->workflow->getCurrentStep();
$stepData = $this->workflow->getStepData($currentStep->name);
Routing:
route('workflows.checkout.cart-review');
'workflows' => [
'checkout' => [
'prefix' => 'custom-prefix',
],
],
Conditional Logic:
public function mount()
{
if ($this->workflow->canSkip('shipping')) {
$this->workflow->skip('shipping');
}
}
Guard Evaluation Order:
onlyIfPasses() for steps that should only render if a guard passes.Session Persistence:
auth:logout) will reset workflows.Workflow::reset() in logout logic if needed:
public function logout()
{
Workflow::reset();
auth()->logout();
}
Component Lifecycle:
$workflow or $step are set in created(). Use mount() instead:
// ❌ Avoid
public function created()
{
$this->workflow->proceed(); // May fail if workflow isn't loaded
}
// ✅ Correct
public function mount()
{
$this->workflow->proceed();
}
Route Caching:
php artisan route:clear
'cache_routes' => env('WORKFLOWS_CACHE_ROUTES', false),
Step Data Serialization:
Livewire 3.x vs 4.x:
redirect()) differ between versions. Use:
// Livewire 4.x
return redirect()->to($path);
// Livewire 3.x (fallback)
return redirect()->route($path);
Log Workflow State:
\Log::info('Workflow state:', [
'current_step' => $this->workflow->getCurrentStep()?->name,
'steps' => $this->workflow->getSteps(),
'data' => $this->workflow->getAllStepData(),
]);
Inspect Guards:
class DebugGuard implements Guard
{
public function passes($workflow, $step): bool
{
$result = /* your logic */;
\Log::debug("Guard {$step->name} passed: {$result}");
return $result;
}
}
Check Route Registration:
php artisan route:list | grep workflows
Session Data:
\Log::info('Session workflow data:', session('workflows'));
Custom Workflow Storage:
WorkflowStorage:
$this->app->bind(
Pixelworxio\LivewireWorkflows\Contracts\WorkflowStorage::class,
CustomWorkflowStorage::class
);
Event Listeners:
WorkflowStarting, StepProceeding):
use Pixelworxio\LivewireWorkflows\Events\WorkflowStarting;
WorkflowStarting::listen(function (WorkflowStarting $event) {
\Log::info("Workflow '{$event->workflow->name}' started");
});
Dynamic Workflows:
$dynamicWorkflow = Workflow::createTemporary()
->step('dynamic-step')
->goTo(DynamicComponent::class);
API Integration:
Route::get('/workflow-state', function () {
return response()->json(Workflow::getCurrent()?->getAllStepData());
});
Testing:
Workflow::fake() for unit tests:
use Pixelworxio\LivewireWorkflows\Facades\Workflow;
public function test_workflow()
{
Workflow::fake();
Workflow::flow('test')->step('step1')->goTo(TestComponent::class);
$response = $this->get('/workflows/test/step1');
$response->assertSee('Test Component');
}
How can I help you explore Laravel packages today?