Configuring transitions

Transitions can be used to transition the state of a model from one to another, in a structured and safe way.

You can specify which states are allowed to transition from one to another, and if you want to handle side effects or have more complex transitions, you can also provide custom transition classes.

Transitions are configured in the registerStates method on your model.

class Payment extends Model
{
    // …

    protected function registerStates(): void
    {
        $this->addState('state', PaymentState::class)
            ->allowTransition(Pending::class, Paid::class)
            ->allowTransition(Pending::class, Failed::class, PendingToFailed::class);
    }
}

In this example we’re using both a simple transition, and a custom one. Transitions can be used like so:

$payment->state->transitionTo(Paid::class);

This line will only work when a valid transition was configured. If the initial state of $payment already was Paid, a \Spatie\ModelStates\Exceptions\TransitionError will be thrown instead of changing the state.

Allow multiple transitions at once

A little shorthand allowTransitions can be used to allow multiple transitions at once:

class Payment extends Model
{
    // …

    protected function registerStates(): void
    {
        $this->addState('state', PaymentState::class)
            ->allowTransitions([
                [Pending::class, Paid::class],
                [Pending::class, Failed::class, PendingToFailed::class],
            ]);
    }
}

Allowing multiple from states

If you’ve got multiple states that can transition to the same state, you can define all of them in one allowTransition call:

class Payment extends Model
{
    // …

    protected function registerStates(): void
    {
        $this->addState('state', PaymentState::class)
            ->allowTransition([Created::class, Pending::class], Failed::class, ToFailed::class);
    }
}

Using transitions

Transitions can be used by calling the transitionTo method on the state field like so:

$payment->state->transitionTo(Paid::class);

If you only have one state field on your model, you can use the transitionTo method directly on it:

$payment->transitionTo(Paid::class);

If there are multiple fields, a \Spatie\ModelStates\Exceptions\CouldNotPerformTransition exception will be thrown. You can pass the state field name explicitly as a second parameter if you want to:

$payment->transitionTo(Paid::class, 'fieldName');