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

State Machine Laravel Package

winzou/state-machine

Lightweight PHP state machine library. Define graphs with states, transitions, and guard/before/after callbacks, then apply and validate transitions on your domain objects. Supports multiple graphs per object and configurable state property paths.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Workflow-Centric Design: Ideal for finite-state workflows (e.g., order processing, approval chains, task pipelines) where transitions are predefined and validated. Aligns with DDD by encapsulating state logic externally, reducing conditional complexity in domain objects.
  • Callback-Driven Extensibility: Supports guards (authorization/validation), pre/post-transition hooks (notifications, auditing), and method invocations (e.g., object->setCancelled()), enabling event-driven side effects without polluting business logic.
  • Multi-Graph Flexibility: Allows multiple state machines per object (e.g., Order with payment_status and shipping_status graphs), though coordination between graphs requires explicit handling (e.g., atomic transactions).
  • Laravel Synergy: Leverages Laravel’s service container, events, and Eloquent for persistence, with optional Symfony integration via StateMachineBundle. Avoids reinventing state management for common use cases.

Integration Feasibility

  • Stack Compatibility:
    • Laravel: Zero-config for basic usage; StateMachineBundle provides Symfony-style service integration (e.g., dependency injection, event dispatchers).
    • Eloquent: Persist state via a column (e.g., stateA) with no ORM coupling. Supports soft deletes or state history via callbacks.
    • Events: Integrates with Laravel’s Event facade for cross-cutting concerns (e.g., broadcast notifications on state changes).
  • Migration Path:
    • Incremental Adoption: Start with one workflow (e.g., order status) to validate ROI before expanding to other domains.
    • Hybrid Approach: Use for critical paths (e.g., payment processing) while retaining hardcoded logic for simple states.
  • Compatibility:
    • PHP 8.3+: Supports modern features (e.g., named arguments, attributes).
    • Symfony 7/8: Tested via CI; Laravel’s EventDispatcher is a drop-in replacement.
    • No ORM Dependency: Works with raw arrays, Eloquent, or custom repositories.

Technical Risk

  • Versioning Ambiguity:
    • Pre-1.0 Status: ~0.4 releases suggest API instability, though MIT license and active maintenance reduce risk. Pin to ^0.4.6 for stability.
    • BC Breaks: v0.2/v0.3 introduced guard callbacks and state event changes; audit transition logic if upgrading from older versions.
  • Performance:
    • Callback Overhead: Each transition may trigger O(n) callbacks (guards + before/after). Profile in high-throughput systems (e.g., 10K+ TPS).
    • Graph Resolution: Factory lookup adds O(1) cost per object/graph pair; negligible unless managing thousands of graphs.
  • Observability Gaps:
    • No Built-in Logging: Requires manual instrumentation (e.g., after callbacks to log transitions).
    • State History: Not tracked by default; implement via database triggers or callbacks (e.g., append to state_history JSON column).
  • Edge Cases:
    • Concurrent Transitions: No built-in locking; handle race conditions (e.g., Order::ship() called twice) via database transactions or optimistic locking.
    • Circular Dependencies: Guards/callbacks referencing each other could cause infinite loops (e.g., guard A calls transition B, which triggers guard A again).

Key Questions

  1. State Persistence:
    • How will the current state be stored? (e.g., Eloquent column, Redis, cache?)
    • Will state history be required? If so, how will it be implemented? (e.g., JSON array, separate table)
  2. Error Handling:
    • How will failed transitions (e.g., guard rejection) be surfaced to the UI? (e.g., custom exceptions, event listeners)
    • Should invalid transitions trigger alerts (e.g., Slack, Sentry)?
  3. Testing Strategy:
    • How will state machines be unit-tested? (e.g., mocking callbacks, verifying guards)
    • Will integration tests cover full workflows (e.g., pending → shipped → cancelled)?
  4. Scaling:
    • What’s the expected throughput for state transitions? (e.g., 100 TPS vs. 10K TPS)
    • Are there bottlenecks in callback execution (e.g., external API calls)?
  5. Maintenance:
    • Who will own the state machine configurations? (e.g., developers, business analysts)
    • How will workflow changes (e.g., adding a state) be reviewed/approved?

Integration Approach

Stack Fit

  • Laravel Integration:
    • Service Provider: Bind the StateMachineFactory to the container for dependency injection:
      $this->app->singleton(StateMachineFactory::class, fn() => new StateMachineFactory());
      
    • Eloquent Models: Store state in a column (e.g., status) and hydrate the state machine in the model’s constructor:
      class Order extends Model {
          protected $stateMachine;
      
          public function __construct(array $attributes = []) {
              parent::__construct($attributes);
              $this->stateMachine = StateMachineFactory::get($this, 'orderWorkflow');
          }
      }
      
    • Events: Dispatch Laravel events (e.g., OrderShipped) in after callbacks:
      'after' => [
          'on-ship' => [
              'on' => 'ship',
              'do' => fn(Order $order) => event(new OrderShipped($order)),
          ],
      ]
      
  • Symfony Integration (Optional):
    • Use StateMachineBundle for event dispatchers, validation, and Symfony forms integration.
    • Configure via YAML:
      winzou_state_machine:
          graphs:
              order_workflow:
                  class: App\Entity\Order
                  property_path: status
                  states: [pending, shipped, cancelled]
                  transitions: { /* ... */ }
      
  • Persistence:
    • Eloquent: Add a status column (e.g., VARCHAR) and hydrate in boot():
      protected static function boot() {
          parent::boot();
          static::created(fn($order) => $order->initializeStateMachine());
      }
      
    • Cache: For read-heavy workflows, cache the state machine instance (e.g., Cache::remember()).

Migration Path

  1. Pilot Phase:
    • Scope: Start with one critical workflow (e.g., order fulfillment) to validate the approach.
    • Implementation:
      • Define the state graph in a separate config file (e.g., config/state_machines/order.php).
      • Attach the state machine to the Eloquent model.
      • Test transition guards and callbacks in isolation.
  2. Incremental Rollout:
    • Phase 2: Add a second workflow (e.g., user account states).
    • Phase 3: Replace hardcoded state logic in controllers/services with state machine transitions.
  3. Legacy Integration:
    • Wrapper Classes: For existing codebases, create adapters to translate legacy state checks to state machine transitions.
    • Feature Flags: Use Laravel’s feature() helper to toggle state machine usage alongside old logic.

Compatibility

  • PHP 8.3+: Leverage named arguments and attributes for cleaner configurations:
    #[StateMachine(
        states: ['pending', 'shipped'],
        transitions: ['ship' => ['from' => 'pending', 'to' => 'shipped']]
    )]
    class Order {}
    
  • Database:
    • MySQL/PostgreSQL: Use ENUM or VARCHAR for state columns.
    • MongoDB: Store state as a field in the document.
  • Testing:
    • Unit Tests: Mock the state machine factory to test transitions in isolation.
    • Feature Tests: Verify full workflows (e.g., pending → shipped → cancelled) with Laravel’s actingAs() and assertDatabaseHas().

Sequencing

  1. Define Workflows:
    • Map business processes to state graphs (e.g., order, user, support_ticket).
    • Document allowed transitions and guard rules (e.g., "cannot cancel if shipped").
  2. Implement Persistence:
    • Add state columns to databases/tables.
    • Hydrate state machines in model constructors or boot() methods.
  3. Add Callbacks:
    • Implement pre/post-transition hooks (e.g., notifications, auditing).
    • Use Laravel events for cross-cutting concerns (e.g., analytics).
  4. Test Edge Cases:
    • Invalid Transitions: Verify guards block
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.
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle
dmstr/api-platform-utils-bundle
dmstr/api-configuration-bundle
chrisdev/ux-components
baks-dev/finances
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager