85 lines
2.3 KiB
PHP
85 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace App\Traits;
|
|
|
|
use InvalidArgumentException;
|
|
|
|
/**
|
|
* Custom state machine trait for Eloquent models.
|
|
* Replacement for spatie/laravel-model-states (incompatible with Laravel 13).
|
|
*
|
|
* Usage:
|
|
* 1. Define a PHP enum for your states
|
|
* 2. Use this trait on your model
|
|
* 3. Implement `getStateMachineConfig()` returning state field + allowed transitions
|
|
*/
|
|
trait HasStateMachine
|
|
{
|
|
/**
|
|
* Get the state machine configuration.
|
|
* Override in your model.
|
|
*
|
|
* @return array{field: string, transitions: array<string, string[]>}
|
|
*/
|
|
abstract protected static function stateMachineConfig(): array;
|
|
|
|
public function getStateField(): string
|
|
{
|
|
return static::stateMachineConfig()['field'];
|
|
}
|
|
|
|
public function getCurrentState(): string
|
|
{
|
|
$field = $this->getStateField();
|
|
return $this->{$field};
|
|
}
|
|
|
|
public function canTransitionTo(string $newState): bool
|
|
{
|
|
$config = static::stateMachineConfig();
|
|
$currentState = $this->getCurrentState();
|
|
$transitions = $config['transitions'] ?? [];
|
|
|
|
if (!isset($transitions[$currentState])) {
|
|
return false;
|
|
}
|
|
|
|
return in_array($newState, $transitions[$currentState], true);
|
|
}
|
|
|
|
public function transitionTo(string $newState): static
|
|
{
|
|
if (!$this->canTransitionTo($newState)) {
|
|
$currentState = $this->getCurrentState();
|
|
$field = $this->getStateField();
|
|
throw new InvalidArgumentException(
|
|
"Cannot transition '{$field}' from '{$currentState}' to '{$newState}'."
|
|
);
|
|
}
|
|
|
|
$field = $this->getStateField();
|
|
$oldState = $this->getCurrentState();
|
|
|
|
$this->{$field} = $newState;
|
|
$this->save();
|
|
|
|
// Fire an event for the transition
|
|
$modelName = class_basename(static::class);
|
|
event("{$modelName}StateChanged", [
|
|
'model' => $this,
|
|
'field' => $field,
|
|
'from' => $oldState,
|
|
'to' => $newState,
|
|
]);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getAllowedTransitions(): array
|
|
{
|
|
$config = static::stateMachineConfig();
|
|
$currentState = $this->getCurrentState();
|
|
return $config['transitions'][$currentState] ?? [];
|
|
}
|
|
}
|