# Defining States
States can be defined in 3 ways
- Within a state class
- Witihin an a state enum
- Dynamically in a model attribute definition
Any which way, the state can be directlly accessed the same
if($order->status->is(OrderStatus::OPEN)){
$order->status->transitionTo(OrderStatus::PAID);
}
# Enum States
It's recommended to use Enums over the provided State class.
Here's how an enum can be transformed into a model state. Your enum doesn't have to be a backed enum.
use MOIREI\State\Traits\HasEnumState;
...
enum OrderStatus: string{
use HasEnumState;
case OPEN = 'open';
case PAID = 'paid';
case CLOSED = 'closed';
protected function states(){
return [
State::on(self::OPEN, self::PAID),
...
]
}
}
Whether applied as a caster or an attribute, the accessed attribute value will return an enum.
if($order->status->is(OrderStatus::OPEN)){
// This is an enum:
$enum = $order->status;
}
# Use as a caster
When using as a cast, the implenting model must use the CastsEnumAttributesState
trait.
This is a temporal solution until PHP Enums can be properly manipulated via
ReflectEnum
.
use MOIREI\State\Traits\CastsEnumAttributesState;
...
/**
* @property OrderStatus $status
*/
class Order extends Model{
use CastsEnumAttributesState;
protected $casts = [
'status' => OrderStatus::class
];
}
# Use in attribute definition
A more elegant solution (for Laravel 9+) is to use Attributes.
/**
* @property OrderStatus $status
*/
class Order extends Model{
protected function status(): Attribute{
return OrderStatus::useAttribute();
}
}
# Class States
class OrderStatus extends State{
const OPEN = 'open';
const PAID = 'paid';
const CLOSED = 'closed';
public static function states(): array{
return [
State::on(self::PENDING, [
self::PAID,
self::BLOCKED,
]),
];
}
}
# Use as a caster
State class can be casted without ascribing CastsEnumAttributesState
trait to the model.
/**
* @property OrderStatus $status
*/
class Order extends Model{
protected $casts = [
'status' => OrderStatus::class
];
}
$statusObject = $order->status;
# Use in attribute definition
An similar to Enums, its directly usable as an Attribute.
/**
* @property OrderStatus $status
*/
class Order extends Model{
protected function status(): Attribute{
return OrderStatus::useAttribute();
}
}
# Dynamic States
It's possible to define state on the fly without referencing an external definition.
/**
* @property \MOIREI\State\State $status
*/
class Order extends Model{
protected function status(): Attribute{
return State::make([
...
]);
}
}
This behaves exactly as using Enums or State classes. It is also possible to provide the state type and default value.
/**
* @property \MOIREI\State\State $status
*/
class Order extends Model{
protected function status(): Attribute{
return State::make([
State::on('pending', 'ready'),
State::on('ready', ['pending', 'closed'])
],
type: MyEnum::class,
default: 'pending'
);
}
}
With type MyEnum
, the actual state value returns an enum.
$order->status->value->value;