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

title: Custom transition classes weight: 2

If you want your transitions to do more than just changing the state, you can use transition classes.

Imagine transitioning a payment's state from pending to failed, which will also save an error message to the database. Here's what such a basic transition class might look like.

use Spatie\ModelStates\Transition;

class PendingToFailed extends Transition
{
    private Payment $payment;

    private string $message;

    public function __construct(Payment $payment, string $message)
    {
        $this->payment = $payment;

        $this->message = $message;
    }

    public function handle(): Payment
    {
        $this->payment->state = new Failed($this->payment);
        $this->payment->failed_at = now();
        $this->payment->error_message = $this->message;

        $this->payment->save();

        return $this->payment;
    }
}

Now the transition should be configured in the model:

abstract class PaymentState extends State
{
    // …

    public static function config(): StateConfig
    {
        return parent::config()
            ->allowTransition(Pending::class, Failed::class, PendingToFailed::class);
    }
}

It can be used like so:

$payment->state->transitionTo(Failed::class, 'error message');

Note: the State::transitionTo method will take as many additional arguments as you'd like, these arguments will be passed to the transition's constructor. The first argument in the transition's constructor will always be the model that the transition is performed on.

Another way of handling transitions is by working directly with the transition classes – this allows for better IDE autocompletion, which can be useful to some people. Instead of using transitionTo(), you can use the transition() and pass it a transition class directly.

$payment->state->transition(new CreatedToFailed($payment, 'error message'));

If you're using the approach above, and want to ensure that this transition can only be performed when the payment is in the Created state, you may implement the canTransition() method on the transition class itself.

class CreatedToFailed extends Transition
{
    // …

    public function canTransition(): bool
    {
        return $this->payment->state->equals(Created::class);
    
    }
}

If the check in canTransition() fails, a \Spatie\ModelStates\Exceptions\TransitionNotAllowed will be thrown.

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