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.
An array of transitionable states can be retrieved using the transitionableStates() on the state field.
abstract class PaymentState extends State
{
// …
public static function config(): StateConfig
{
return parent::config()
->allowTransition(Pending::class, Paid::class)
->allowTransition(Paid::class, Refunded::class);
}
}
$transitionableStates = $payment->state->transitionableStates();
This will return an array with all transitionable states for the current state, for example Pending:
[
0 => "paid"
]
If you need the actual state instances instead of just their string representations, you can use the transitionableStateInstances() method:
$stateInstances = $payment->state->transitionableStateInstances();
This will return an array of instantiated state objects:
[
0 => Paid {
// State instance with model reference
}
]
This method is particularly useful when you need to access state methods directly. For example, to display available transitions with their properties:
[@foreach](https://github.com/foreach)($payment->state->transitionableStateInstances() as $stateInstance)
<div>
<span style="color: {{ $stateInstance->color() }}">{{ $stateInstance->label() }}</span>
<i class="{{ $stateInstance->icon() }}"></i>
</div>
[@endforeach](https://github.com/endforeach)
With this approach, you can directly call any method defined on your state classes, allowing you to encapsulate UI and business logic within your states:
abstract class PaymentState extends State
{
abstract public function color(): string;
abstract public function label(): string;
abstract public function icon(): string;
// ...other state methods
}
class Paid extends PaymentState
{
public function color(): string
{
return '#4CAF50'; // green
}
public function label(): string
{
return 'Mark as Paid';
}
public function icon(): string
{
return 'check-circle';
}
}
This method tells you how many available transitions exist for the current state.
$stateCount = $payment->state->transitionableStatesCount(); // 4
This method tells you whether there are any available transitions for the current state.
$hasTransitions = $payment->state->hasTransitionableStates(); // true or false
If you want to know whether a state can be transitioned to another one, you can use the canTransitionTo method:
$payment->state->canTransitionTo(Paid::class);
How can I help you explore Laravel packages today?