Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Workflows Laravel Package

pixelworxio/livewire-workflows

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require pixelworxio/livewire-workflows
    

    Publish config (if needed):

    php artisan vendor:publish --provider="Pixelworxio\LivewireWorkflows\LivewireWorkflowsServiceProvider"
    
  2. 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);
    }
    
  3. First Use Case:

    • Create a Livewire component for a step (e.g., CartReview).
    • Access workflow state in your component:
      public $workflow;
      public $step;
      
      public function mount()
      {
          $this->workflow = Workflow::getCurrent();
          $this->step = $this->workflow->getCurrentStep();
      }
      
    • Navigate between steps:
      public function proceed()
      {
          $this->workflow->proceed();
      }
      

Implementation Patterns

Core Workflow

  1. Workflow Definition:

    • Use Workflow::flow() to define a named workflow (e.g., onboarding, checkout).
    • Chain methods like entersAt(), finishesAt(), and step() for declarative setup.
    • Example: Multi-step checkout with guards:
      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);
      
  2. Step Components:

    • Each step maps to a Livewire component (e.g., Cart, Shipping).
    • Inject workflow state into components via $workflow and $step properties.
    • Use 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
      }
      
  3. Guards:

    • Use guards to control step access (e.g., unlessPasses(), onlyIfPasses()).
    • Create custom guards by implementing Pixelworxio\LivewireWorkflows\Contracts\Guard:
      class HasItemsGuard implements Guard
      {
          public function passes($workflow, $step): bool
          {
              return Cart::count() > 0;
          }
      }
      
  4. State Persistence:

    • Workflow state is automatically persisted using Laravel sessions.
    • Access current step data:
      $currentStep = $this->workflow->getCurrentStep();
      $stepData = $this->workflow->getStepData($currentStep->name);
      
  5. Routing:

    • Workflows auto-register routes. Access them via:
      route('workflows.checkout.cart-review');
      
    • Override default routes in config:
      'workflows' => [
          'checkout' => [
              'prefix' => 'custom-prefix',
          ],
      ],
      
  6. Conditional Logic:

    • Dynamically skip steps or redirect based on conditions:
      public function mount()
      {
          if ($this->workflow->canSkip('shipping')) {
              $this->workflow->skip('shipping');
          }
      }
      

Gotchas and Tips

Pitfalls

  1. Guard Evaluation Order:

    • Guards are evaluated before rendering the step component. Ensure guards are idempotent (e.g., avoid side effects like sending emails).
    • Fix: Use onlyIfPasses() for steps that should only render if a guard passes.
  2. Session Persistence:

    • Workflow state relies on Laravel sessions. Clear sessions (e.g., auth:logout) will reset workflows.
    • Fix: Use Workflow::reset() in logout logic if needed:
      public function logout()
      {
          Workflow::reset();
          auth()->logout();
      }
      
  3. Component Lifecycle:

    • Avoid assuming $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();
      }
      
  4. Route Caching:

    • Routes are cached by default. Clear them after defining new workflows:
      php artisan route:clear
      
    • Disable caching in config if testing:
      'cache_routes' => env('WORKFLOWS_CACHE_ROUTES', false),
      
  5. Step Data Serialization:

    • Step data is serialized to JSON. Avoid storing unserializable objects (e.g., Closures, Resources).
    • Fix: Store IDs or primitive data, then re-fetch objects in components.
  6. Livewire 3.x vs 4.x:

    • Some methods (e.g., redirect()) differ between versions. Use:
      // Livewire 4.x
      return redirect()->to($path);
      
      // Livewire 3.x (fallback)
      return redirect()->route($path);
      

Debugging Tips

  1. Log Workflow State:

    \Log::info('Workflow state:', [
        'current_step' => $this->workflow->getCurrentStep()?->name,
        'steps' => $this->workflow->getSteps(),
        'data' => $this->workflow->getAllStepData(),
    ]);
    
  2. Inspect Guards:

    • Temporarily log guard results:
      class DebugGuard implements Guard
      {
          public function passes($workflow, $step): bool
          {
              $result = /* your logic */;
              \Log::debug("Guard {$step->name} passed: {$result}");
              return $result;
          }
      }
      
  3. Check Route Registration:

    • Verify routes are registered:
      php artisan route:list | grep workflows
      
  4. Session Data:

    • Inspect session data for workflow state:
      \Log::info('Session workflow data:', session('workflows'));
      

Extension Points

  1. Custom Workflow Storage:

    • Override storage engine by binding a custom WorkflowStorage:
      $this->app->bind(
          Pixelworxio\LivewireWorkflows\Contracts\WorkflowStorage::class,
          CustomWorkflowStorage::class
      );
      
  2. Event Listeners:

    • Listen to workflow events (e.g., WorkflowStarting, StepProceeding):
      use Pixelworxio\LivewireWorkflows\Events\WorkflowStarting;
      
      WorkflowStarting::listen(function (WorkflowStarting $event) {
          \Log::info("Workflow '{$event->workflow->name}' started");
      });
      
  3. Dynamic Workflows:

    • Build workflows dynamically at runtime:
      $dynamicWorkflow = Workflow::createTemporary()
          ->step('dynamic-step')
          ->goTo(DynamicComponent::class);
      
  4. API Integration:

    • Expose workflow state via API:
      Route::get('/workflow-state', function () {
          return response()->json(Workflow::getCurrent()?->getAllStepData());
      });
      
  5. Testing:

    • Use 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');
      }
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor