I've got quite into the power of Spaties [laravel-model-states](https://spatie.be/docs/laravel-model-states/v2/01-introduction) package. I refactored an app a few years ago, and the state pattern and use of classes for states and transitions cleared up so much confusion.
Upgrading to Laravel 9 though I needed to change to spatie models states v2. Which was more involved because the state system changed heavily to use Laravel's casting system.
While not crazy complicated, I had enough states and have used this on several apps, so I made notes for me to follow with each state to avoid having to cycle between different doc pages.
In your state-using model you need to add the casts attribute linking to the abstract state class:
protected $casts = [
'status' => ProductState::class,
];
Take your registered states code from the model:
///from Model
protected function registerStates(): void
{
$this->addState('status', ProductState::class)
->default(Active::class)
->allowTransition(
[Development::class, Special::class, Active::class, TBD::class],
Discontinued::class,
toDiscontinuedTransition::class
)
->allowTransition(
[Development::class, Special::class, TBD::class, Discontinued::class],
Active::class
)
->allowTransition(
[Special::class, Active::class, Discontinued::class],
TBD::class
)
->allowTransition(
[Development::class, Active::class, TBD::class, Discontinued::class],
Special::class
)
->allowTransition(
[Active::class, Special::class],
Development::class
);
}
And move that to your abstract state class:
//In ProductState.php
public static function config(): StateConfig
{
return parent::config()
->default(Active::class)
->allowTransition(
[Development::class, Special::class, Active::class, TBD::class],
Discontinued::class,
toDiscontinuedTransition::class
)
->allowTransition(
[Development::class, Special::class, TBD::class, Discontinued::class],
Active::class
)
->allowTransition(
[Special::class, Active::class, Discontinued::class],
TBD::class
)
->allowTransition(
[Development::class, Active::class, TBD::class, Discontinued::class],
Special::class
)
->allowTransition(
[Active::class, Special::class],
Development::class
);
}
Transitioning inside states:
In my states I had a lot of $this->model->transitionTo()
to change between states. The new system is $this->transitionTo()
a quick find and replace across the states folder fixed that.
There's also a couple of changed methods - all my states worked fine in tests, but there were a few places I was passing a field no longer needed that I took out for completeness.
Review the full changed method list here