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

Laravel Model States Laravel Package

spatie/laravel-model-states

Add robust state behavior to Laravel Eloquent models using the state pattern and state machines. Represent each state as a class, cast states transparently to/from the database, and define clear, safe transitions with configurable state logic.

View on GitHub
Deep Wiki
Context7

Getting Started

Begin by installing the package via Composer and publishing its config (though the config is minimal and often unused). Next, define an abstract state class (e.g., PaymentState extends State) in app/States/ and concrete state classes (e.g., Pending, Paid) inside the same directory. Use the HasStates trait on your Eloquent model and cast the state column (e.g., state) to your abstract state class. Set a default state and allowed transitions in the config() method of the abstract class. Start using states immediately via $model->state->transitionTo(...), and leverage methods defined on your state classes.

Implementation Patterns

  • Encapsulate behavior per state: Define methods like color(), label(), or isAllowedTo(...) on your state class to hide logic that changes per state (e.g., Paid::color() returns 'green').
  • Group related state classes: Place all states for a model in a subdirectory (app/States/Payment/) to keep things organized; the package auto-discovers them if colocated with the abstract class.
  • Leverage transitions with guards: Use ->allowTransition(...) in config() to define valid state changes—transitions throw exceptions if invalid unless you override onFailedTransition.
  • Automate state discovery: Prefer registerStatesFromDirectory() over manual registration for maintainability across large projects.
  • Custom events: Override the default StateChanged event via stateChangedEvent() to integrate with notification or logging systems.
  • Type-hint safely: Implement HasStatesContract for precise IDE autocompletion and Psalm/PHPStan support.
  • Multiple state fields: Use separate columns and abstract state classes per state machine (e.g., invoice_status, fulfillment_status) on the same model.

Gotchas and Tips

  • Class name vs. name property: Avoid relying solely on ::class; define public static $name on concrete states for human-readable DB values (e.g., 'paid'). However, don’t use hyphens in names—they conflict internally.
  • Directory cohesion: For auto-resolution to work, all concrete state classes and the abstract class must reside in the same directory. Otherwise, register manually or use registerStatesFromDirectory().
  • Casts are mandatory: Forgetting protected $casts = ['state' => MyState::class] will cause the field to serialize as a string, breaking state behavior entirely.
  • State mutations: Never modify state properties in place—transitionTo() creates a new instance; access via $model->state always returns current state.
  • Migration considerations: Ensure the state column is a string (or enum in modern DBs); don’t use tinyInteger or boolean—this package stores class names or custom names as strings.
  • Event listeners: The default StateChanged event fires after persistence; if you hook into it, ensure your listeners don’t throw or assume existing state.
  • Testing tip: Use State::from() or State::castFrom() in tests to instantiate states directly without DB round-trips (e.g., Pending::from($model)).
  • Upgrading risks: This package has infrequent breaking changes, but always check the CHANGELOG before upgrading—especially after major versions (v1→v2 involved migration of attributes to attributes).
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport