pixelworxio/livewire-workflows
最新稳定版本:0.5.3b
Composer 安装命令:
composer require pixelworxio/livewire-workflows
包简介
Build multi-step workflows in Laravel / Livewire with zero boilerplate
README 文档
README
Livewire Workflows (BETA)
Build powerful multi-step workflows in Laravel with zero boilerplate. Define complex user journeys—onboarding, checkouts, surveys—using an expressive, route-like DSL. Get automatic route registration, guard-based navigation, state persistence, and full Livewire integration out of the box.
// Define a complete workflow in seconds Workflow::flow('onboarding') ->entersAt(name: 'onboarding.start', path: '/onboarding') ->finishesAt('dashboard') ->step('verify-email') ->goTo(VerifyEmail::class) ->unlessPasses(EmailVerifiedGuard::class) ->order(10) ->step('profile') ->goTo(EditProfile::class) ->unlessPasses(ProfileCompletedGuard::class) ->order(20);
That's it. No manual routes. No state management headaches.
View the testbench repo, https://github.com/pixelworxio/livewire-workflows-testbench, for examples of how this package can help you with your project.
✨ Why Livewire Workflows?
| Feature | Livewire Workflows | Manual Implementation |
|---|---|---|
| Route Management | ✅ Auto-generated | ❌ Define every route manually |
| State Persistence | ✅ Built-in (Session/DB) | ❌ Roll your own |
| Navigation Logic | ✅ Guard-based pipeline | ❌ Complex conditionals everywhere |
| Back Button | ✅ History tracking | ❌ Custom session juggling |
| Progress Tracking | ✅ One method call | ❌ Calculate yourself |
| Events & Analytics | ✅ Fire automatically | ❌ Remember to dispatch |
Result: Spend time building features, not workflow infrastructure.
📦 Installation
composer require pixelworxio/livewire-workflows
Quick Setup (Session-Based)
php artisan workflows:install
Production Setup (Database-Backed)
php artisan workflows:install --with-db php artisan migrate
🚀 Quick Start (3 Minutes)
1. Define Your Workflow
Open routes/workflows.php:
use Pixelworxio\LivewireWorkflows\Facades\Workflow; Workflow::flow('onboarding') ->entersAt(name: 'onboarding.start', path: '/onboarding') ->finishesAt('dashboard') ->step('verify-email') ->goTo(\App\Livewire\Onboarding\VerifyEmail::class) ->unlessPasses(\App\Guards\EmailVerifiedGuard::class) ->order(10) ->step('profile') ->goTo(\App\Livewire\Onboarding\EditProfile::class) ->unlessPasses(\App\Guards\ProfileCompletedGuard::class) ->order(20);
Routes auto-registered:
- Entry:
GET /onboarding→onboarding.start - Step 1:
GET /onboarding/verify-email→onboarding.verify-email - Step 2:
GET /onboarding/profile→onboarding.profile
2. Create a Guard
Quick Generation:
php artisan make:workflow-guard EmailVerified
This generates a guard at App\Guards\EmailVerifiedGuard.php with the proper structure.
namespace App\Guards; use Illuminate\Http\Request; use Pixelworxio\LivewireWorkflows\Contracts\GuardContract; class EmailVerifiedGuard implements GuardContract { public function passes(Request $request): bool { return true; } public function onEnter(Request $request): void {} public function onExit(Request $request): void {} public function onPass(Request $request): void {} public function onFail(Request $request): void {} }
Guard Logic: passes() = true → skip step. passes() = false → show step.
3. Build Your Livewire Component
namespace App\Livewire\Onboarding; use Livewire\Component; use Pixelworxio\LivewireWorkflows\Attributes\WorkflowStep; use Pixelworxio\LivewireWorkflows\Livewire\Concerns\InteractsWithWorkflows; #[WorkflowStep(flow:'onboarding', key:'verify-email')] class VerifyEmail extends Component { use InteractsWithWorkflows; public function resend() { auth()->user()->sendEmailVerificationNotification(); session()->flash('message', 'Verification email sent!'); } public function goToNextStep(): void { // ... handle your logic $this->continue('onboarding'); // workflow name is optional when using WorkflowStep attribute } public function render() { return view('livewire.onboarding.verify-email'); } }
And in your Blade view:
<div> <h1>Verify Your Email</h1> <p>Check your inbox for the verification link.</p> <button wire:click="resend">Resend Email</button> <button wire:click="goToNextStep"> I've Verified — Continue </button> </div>
4. Done!
Visit /onboarding. The package:
- Evaluates guards in order
- Redirects to first incomplete step
- Tracks progress automatically
- Completes when all steps pass
📖 Core Concepts
Auto-Generated Routes
Routes are automatically registered from your DSL:
->entersAt(name: 'checkout.start', path: '/checkout') // Entry route ->step('shipping') // Auto: /checkout/shipping ->step('payment') // Auto: /checkout/payment
Generated:
checkout.start→/checkoutcheckout.shipping→/checkout/shippingcheckout.payment→/checkout/payment
Dynamic Routes with Parameters
Workflows support dynamic route parameters and route model binding:
Workflow::flow('user-checkout') ->entersAt(name: 'user-checkout.start', path: '/user/{user}/checkout/{product}') ->finishesAt('dashboard') ->step('shipping') ->goTo(\App\Livewire\Checkout\Shipping::class) ->unlessPasses(\App\Guards\HasShippingAddress::class) ->order(10) ->step('payment') ->goTo(\App\Livewire\Checkout\Payment::class) ->unlessPasses(\App\Guards\HasPaymentMethod::class) ->order(20);
Generated Routes:
user-checkout.start→/user/{user}/checkout/{product}user-checkout.shipping→/user/{user}/checkout/{product}/shippinguser-checkout.payment→/user/{user}/checkout/{product}/payment
Route Model Binding:
// Supports Laravel's route model binding syntax ->entersAt(name: 'checkout.start', path: '/user/{user:id}/product/{product:slug}')
Navigation Preserves Parameters:
Route parameters are automatically passed through all workflow navigation:
class Shipping extends Component { use InteractsWithWorkflows; protected ?string $workflowName = 'user-checkout'; // Livewire receives route parameters public function mount($user, $product) { // $user and $product are automatically injected } public function submit() { // Parameters are automatically preserved when continuing $this->continue($this->workflowName); // Still navigates with {user} and {product} } }
The continue() and back() methods automatically extract and pass route parameters from the current request, ensuring seamless navigation throughout the workflow.
Guard Behavior
Guards use positive semantics:
class ProfileCompleteGuard implements GuardContract { public function passes(Request $request): bool { return $request->user()->profile_completed; } }
| Guard Result | Step Behavior |
|---|---|
passes() = true |
Skip this step |
passes() = false |
Show this step |
Use unlessPasses(Guard::class): "Show step UNLESS guard passes."
Navigation Flow
- User visits entry route (
/onboarding) - Package evaluates guards in
order - Redirects to first failing guard's step
- User completes step, calls
$this->continue('onboarding') - Re-evaluates from entry → next unmet step or finish
🧩 Advanced Features
State Management
Setting Workflow Name
Use the #[WorkflowName] attribute to explicitly declare your component's workflow, when not using the WorkflowStep attribute:
use Pixelworxio\LivewireWorkflows\Attributes\WorkflowName; #[WorkflowName('checkout')] class CheckoutShipping extends Component { use InteractsWithWorkflows; // protected ?string $workflowName = 'checkout'; // No need to set }
Benefits:
- ✅ Eliminates boilerplate
- ✅ Makes workflow association explicit
- ✅ Auto-detected during component boot
- ✅ Falls back to route-based detection if not present
Persisting State
Persist data across workflow steps with the #[WorkflowState] attribute:
use Pixelworxio\LivewireWorkflows\Attributes\WorkflowName; use Pixelworxio\LivewireWorkflows\Attributes\WorkflowState; #[WorkflowName('checkout')] class CheckoutShipping extends Component { use InteractsWithWorkflows; #[WorkflowState] public ?string $address = null; #[WorkflowState(encrypt: true)] public ?string $creditCard = null; #[WorkflowState(namespace: 'shipping')] public ?string $method = null; }
Features:
- Auto-hydration on mount
- Auto-persistence on dehydrate
- Encryption support
- Namespace grouping
- Session or database storage
Progress Tracking
$progress = workflow('onboarding')->progressFor($request); // Returns: [ 'total' => 3, 'completed' => 1, 'remaining' => 2, 'percentage' => 33.33, 'current_step' => 'verify-email', 'next_step' => 'profile', 'is_complete' => false, ]
Events
Listen to workflow lifecycle:
use Pixelworxio\LivewireWorkflows\Events\{WorkflowAdvanced, WorkflowCompleted}; Event::listen(WorkflowAdvanced::class, function ($event) { Log::info("User {$event->userKey} moved from {$event->fromKey} to {$event->toKey}"); }); Event::listen(WorkflowCompleted::class, function ($event) { Mail::to($user)->send(new OnboardingComplete()); });
CLI Tools
# Generate a new workflow php artisan make:workflow checkout # Generate a guard class php artisan make:workflow-guard EmailVerified # Add a step to existing workflow php artisan make:workflow-step checkout payment \ --component=App\\Livewire\\Checkout\\Payment \ --guard=App\\Guards\\CartNotEmptyGuard \ --order=20 # Validate and document all workflows php artisan workflows:scan
🎯 Real-World Examples
Multi-Page Checkout
Workflow::flow('checkout') ->entersAt(name: 'checkout.start', path: '/checkout') ->finishesAt('orders.confirmation') ->step('cart') ->goTo(ReviewCart::class) ->unlessPasses(CartNotEmptyGuard::class) ->order(10) ->step('shipping') ->goTo(ShippingAddress::class) ->unlessPasses(ShippingAddressGuard::class) ->order(20) ->step('payment') ->goTo(PaymentMethod::class) ->unlessPasses(PaymentMethodGuard::class) ->order(30);
Employee Onboarding
Workflow::flow('employee-onboarding') ->entersAt(name: 'onboard.start', path: '/onboard') ->finishesAt('employee.dashboard') ->step('paperwork') ->goTo(Paperwork::class) ->unlessPasses(PaperworkCompleteGuard::class) ->order(10) ->step('it-setup') ->goTo(ITSetup::class) ->unlessPasses(ITAccountGuard::class) ->order(20) ->step('training') ->goTo(TrainingModules::class) ->unlessPasses(TrainingCompleteGuard::class) ->order(30);
User Registration Flow
Workflow::flow('signup') ->entersAt(name: 'signup.start', path: '/signup') ->finishesAt('welcome') ->step('account') ->goTo(CreateAccount::class) ->unlessPasses(AccountCreatedGuard::class) ->order(10) ->step('verify-email') ->goTo(VerifyEmail::class) ->unlessPasses(EmailVerifiedGuard::class) ->order(20) ->step('preferences') ->goTo(SetPreferences::class) ->unlessPasses(PreferencesSetGuard::class) ->order(30);
🔧 Configuration
Publish and customize the config:
php artisan vendor:publish --tag=livewire-workflows-config
config/livewire-workflows.php:
return [ // State persistence: 'null', 'session', or 'eloquent' 'repository' => env('WORKFLOWS_REPOSITORY', 'session'), // Middleware applied to all workflow routes 'middleware' => ['web', 'auth'], ];
State Repository Options
| Repository | Use Case | Persistence |
|---|---|---|
null |
Stateless workflows | None |
session |
Guest users, simple flows | Session lifetime |
eloquent |
Authenticated users, production | Database |
📊 API Reference
Workflow DSL
Workflow::flow(string $name) ->entersAt(name: string, path: string) ->finishesAt(string $routeName) ->step(string $key) ->goTo(string $componentClass) ->unlessPasses(string $guardClass) ->order(int $order);
Livewire Trait Methods
use InteractsWithWorkflows; $this->continue(string $flow): RedirectResponse $this->back(string $flow, string $currentKey): ?RedirectResponse $this->syncState(): void // Manually persist state
Note: When using the #[WorkflowStep] attribute, the $flow and $currentKey properties are optional
#[WorkflowStep(flow: 'my-flow', key: 'current-step', middleware: ['auth'])]
use InteractsWithWorkflows;
$this->continue(): RedirectResponse
$this->back(): ?RedirectResponse
Helper Functions
workflow(string $flow)->redirect(Request $request, ?string $doneRoute = null) workflow(string $flow)->nextRouteNameFor(Request $request, ?string $doneRoute = null) workflow(string $flow)->previousRouteNameFor(string $currentKey, Request $request) workflow(string $flow)->progressFor(Request $request)
State Management Helpers
// Automatic with attributes #[WorkflowState] public ?string $email = null; #[WorkflowState(encrypt: true)] public ?string $password = null; #[WorkflowState(namespace: 'profile')] public ?string $name = null; // Manual helpers $this->putWorkflowState(string $key, mixed $value) $this->getWorkflowState(string $key, mixed $default = null) $this->hasWorkflowState(string $key) $this->forgetWorkflowState(string $key) $this->clearWorkflowState(?string $namespace = null) $this->allWorkflowState()
🆚 Comparison with Alternatives
**Or so Claude.ai says...
| Feature | Livewire Workflows | Spatie Laravel Wizard | Custom Solution |
|---|---|---|---|
| Route Auto-Registration | ✅ | ❌ | ❌ |
| Guard-Based Navigation | ✅ | ❌ | Custom |
| State Persistence | ✅ Built-in | ❌ | Custom |
| Livewire 3 Native | ✅ | ⚠️ Limited | N/A |
| History/Back Support | ✅ | ⚠️ Basic | Custom |
| Progress Tracking | ✅ | ❌ | Custom |
| Events | ✅ | ❌ | Custom |
| Learning Curve | Low | Medium | High |
💬 FAQ
Can I use this with Livewire v3 and the v4 beta?
The package is tested to work with Livewire v3. Livewire v4 beta compatibility is planned, but not yet tested.
Do I need to define routes manually?
No. Step routes are auto-registered from your DSL. You only need to define the finish route in your regular routes/web.php, if not already present.
Can I protect workflows with authentication?
Yes. Add 'auth' to the middleware array in config/livewire-workflows.php.
How do I skip steps dynamically?
Make the guard's passes() method return true when the step should be skipped.
Can workflows share state?
No. State is scoped per workflow and per user. This is by design for data isolation.
What happens if a user jumps to a step URL directly?
The step page loads, but calling continue() will re-evaluate guards and redirect appropriately.
🛠️ Requirements
- PHP 8.3+
- Laravel 11.x or 12.x
- Livewire 3.x
🤝 Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
Development Setup
git clone https://github.com/pixelworxio/livewire-workflows.git cd livewire-workflows composer install composer test
📜 License
The MIT License (MIT). Please see License File for more information.
🙏 Credits
Built with ❤️ using Laravel, Livewire, and Spatie's Package Tools.
🌟 Show Your Support
Give a ⭐️ if this project helped you!
统计信息
- 总下载量: 13
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 65
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-11-06