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

Workflow Laravel Package

symfony/workflow

Symfony Workflow component helps model and run workflows or finite state machines. Define places and transitions, guard rules, events, and marking stores to track state changes and integrate processes cleanly into your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use Case

  1. Install the Package

    composer require symfony/workflow
    

    For Laravel integration, use symfony/workflow alongside symfony/dependency-injection and symfony/http-kernel (if needed for DI).

  2. Define a Workflow Create a YAML/array definition for your workflow (e.g., order_workflow.yaml):

    # config/workflows/order_workflow.yaml
    app.order_workflow:
        supports:
            - App\Models\Order
        initial_marking: draft
        places:
            draft:
                transitions:
                    submit: pending
            pending:
                transitions:
                    approve: processing
                    reject: rejected
            processing:
                transitions:
                    ship: shipped
            shipped:
                transitions:
                    deliver: delivered
            rejected:
                transitions: ~
    
  3. Register the Workflow in Laravel Use Laravel’s service provider to load the workflow:

    // app/Providers/WorkflowServiceProvider.php
    namespace App\Providers;
    
    use Illuminate\Support\ServiceProvider;
    use Symfony\Component\Workflow\WorkflowInterface;
    use Symfony\Component\Workflow\Registry;
    
    class WorkflowServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton(Registry::class, function ($app) {
                $registry = new Registry();
                $registry->addWorkflow(
                    'order_workflow',
                    $app['config']['workflows.order_workflow']
                );
                return $registry;
            });
        }
    }
    
  4. Apply the Workflow to a Model Use the MarkingStore to track state in your Eloquent model:

    // app/Models/Order.php
    use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore;
    
    class Order extends Model
    {
        protected static function booted()
        {
            static::created(function ($order) {
                $order->markAsDraft(); // Initial state
            });
        }
    
        public function markAsDraft()
        {
            $this->update(['status' => 'draft']);
        }
    
        public function getStatus(): string
        {
            return $this->status;
        }
    }
    
  5. Trigger a Transition Use the workflow registry to apply transitions:

    use Symfony\Component\Workflow\WorkflowInterface;
    
    public function submitOrder(Order $order)
    {
        $workflow = app(WorkflowInterface::class)->get('order_workflow');
        $workflow->apply($order, 'submit');
    
        // Emit Laravel event (optional)
        event(new OrderSubmitted($order));
    }
    
  6. Check Current State

    $currentState = $workflow->getMarking($order);
    $isPending = $workflow->can($order, 'approve');
    

First Use Case: Order Processing

  • Problem: Orders move through draft → pending → processing → shipped → delivered with conditional transitions (e.g., "approve only if payment is verified").
  • Solution: Define the workflow in YAML, apply it to the Order model, and trigger transitions via API/controllers.
  • Outcome: Replace 50+ lines of if-else logic with a declarative workflow, reducing bugs and improving maintainability.

Implementation Patterns

Workflow Integration Workflows

  1. Model Integration

    • Use MethodMarkingStore for Eloquent models (recommended for Laravel):
      $store = new MethodMarkingStore(
          $order,
          'getStatus',
          'markAs{status}'
      );
      $workflow = new Workflow($definition, $store);
      
    • For non-Eloquent entities, use DoctrineMarkingStore or PropertyMarkingStore.
  2. Event-Driven Transitions

    • Bind workflow transitions to Laravel events:
      $workflow->on('order.submitted', function (OrderSubmittedEvent $event) {
          // Send notification, log audit trail, etc.
      });
      
    • Use Symfony’s EventDispatcher or Laravel’s Event system.
  3. Dynamic Workflows

    • Load workflows from the database or config:
      $registry->addWorkflow('dynamic_workflow', $dynamicDefinition);
      
    • Useful for multi-tenancy or tenant-specific workflows.
  4. Guard Conditions

    • Add transition guards (e.g., "approve only if payment is verified"):
      pending:
          transitions:
              approve:
                  to: processing
                  guards: [payment_verified]
      
    • Implement guards as closures or service methods:
      $workflow->addGuard('payment_verified', function (Order $order) {
          return $order->payment->isVerified();
      });
      
  5. Traceable Workflows

    • Enable audit trails with TraceableWorkflow:
      $traceableWorkflow = new TraceableWorkflow($workflow);
      $traceableWorkflow->apply($order, 'submit');
      $history = $traceableWorkflow->getHistory();
      
    • Store history in a database table for compliance.
  6. Visualization

    • Generate Mermaid diagrams for documentation:
      php bin/console workflow:dump --format=mermaid order_workflow
      
    • Or use the GraphvizDumper in code:
      $dumper = new GraphvizDumper();
      echo $dumper->dump($workflow);
      

Laravel-Specific Patterns

  1. Service Container Integration

    • Bind workflows to the container for dependency injection:
      $this->app->bind(WorkflowInterface::class, function ($app) {
          return $app['workflow.registry']->get('order_workflow');
      });
      
  2. Artisan Commands

    • Extend Symfony’s WorkflowDumpCommand for Laravel:
      use Symfony\Component\Workflow\Command\WorkflowDumpCommand;
      
      $command = new WorkflowDumpCommand();
      $command->run(new Application(), ['command' => 'workflow:dump', 'workflow' => 'order_workflow']);
      
  3. Testing Workflows

    • Mock workflows in PHPUnit:
      $mockWorkflow = $this->createMock(WorkflowInterface::class);
      $mockWorkflow->method('can')->willReturn(true);
      $mockWorkflow->method('apply')->willReturnSelf();
      
  4. API Resource Integration

    • Expose workflow transitions in API responses:
      return new JsonResponse([
          'status' => $order->status,
          'allowed_transitions' => $workflow->getEnabledTransitions($order),
      ]);
      
  5. Queueable Transitions

    • Dispatch workflow transitions to queues for async processing:
      dispatch(new ApplyWorkflowTransition($order, 'submit'));
      
    • Handle in a job:
      public function handle()
      {
          $workflow = app(WorkflowInterface::class)->get('order_workflow');
          $workflow->apply($this->order, $this->transition);
      }
      

Gotchas and Tips

Pitfalls

  1. State Contamination

    • Issue: Class-based getter/setter caches can cause incorrect state reads/writes.
    • Fix: Use MethodMarkingStore with explicit getter/setter methods or upgrade to Symfony 7.4+ (fixed in #62211).
  2. Empty String Place Names

    • Issue: Workflows with empty string place names (e.g., "") may fail.
    • Fix: Avoid empty strings; use null or non-empty names (fixed in #62719).
  3. Event Dispatching

    • Issue: Events may not fire if the subject is already in the target marking.
    • Fix: Use Workflow::apply() with true for the second argument to force event dispatching (fixed in #60194).
  4. TraceableWorkflow Reset

    • Issue: TraceableWorkflow lacked a reset() method in older versions.
    • Fix: Upgrade to Symfony 7.4.6+ or manually clear the history array.
  5. HTML Escaping in Graphviz

    • Issue: GraphvizDumper may escape HTML incorrectly.
    • Fix: Upgrade to Symfony 7.4.9+ or manually sanitize labels.
  6. BackedEnum Support

    • Issue: MethodMarkingStore may crash with BackedEnum properties.
    • Fix: Upgrade to Symfony 8.0+ or use PropertyMarkingStore for enums.

Debugging Tips

  1. Dump Workflow State

    php artisan workflow:dump order_workflow
    
    • Outputs a visual representation of the workflow (DOT or Mermaid format).
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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle