Originaly based on https://github.com/daveawb/understated
FSM's are a resource that allow developers tight control over resources within an application. There are many articles detailing FSM's and what they are and what they're capable of so I won't go into much detail here.
- >= PHP 7.0
- >= Laravel 5.4
Add the following to your composer.json file
{
"require": {
"studionet/overstated": "0.1.0"
}
}
Open config/app.php
and register the required service provider.
'providers' => [
// ...
OverStated\Providers\OverStatedServiceProvider::class,
]
First you have to define states as classes, for example :
use OverStated\States\State;
/**
* Class Deleted
*/
class Deleted extends State {
/** @var string $id */
protected $id = 'deleted';
}
And transitions :
use OverStated\Transitions\Transition;
/**
* Class Delete
*/
class Delete extends Transition {
// Transition slug
public $slug = "delete";
// Transition nice name
public $name = "Delete";
// Transition description
public $description = "Delete a property";
// Transition from which state(s) you can transit
public $from = ["draft", "valid"];
// Transition destination state
public $to = "deleted";
}
The simple way to use it is in a Model, with the Stateful trait
use OverStated\Support\Stateful;
use App\Fsm\Property\States;
use App\Fsm\Property\Transitions;
class Post extends Model {
use Stateful;
/** @type array $attributes default values */
protected $attributes = [
'status' => "draft",
];
// You have to define fields which will be controlled by FSMs
// Here, it's the field 'status', which have states and a transition
/** @var array $fsmDefinitions */
protected $fsmDefinitions = [
'status' => [
'states' => [
States\Draft::class,
States\Valid::class,
States\Deleted::class,
],
'transitions' => [
Transitions\Delete::class,
]
]
];
}
After that, you can update defined field like :
// Will echo "draft"
echo $post->status;
// Change status
$post->fsmTransit("status", "delete");
// Will echo "deleted"
echo $post->status;
// Will throw an OverStated\Exceptions\TransitionException
$post->fsmTransit("status", "delete");
Or, you can manually create FSM
use OverStated\Builders\GraphBuilder;
use App\Fsm\Property\States;
use App\Fsm\Property\Transitions;
$builder = new GraphBuilder();
$builder = $builder->create();
// Set states
$builder->state(States\Draft::class);
$builder->state(States\Valid::class);
$builder->state(States\Deleted::class);
// Set transitions
$builder->transition(Transitions\Delete::class);
// Get the machine from the builder
$fsm = $builder->getMachine();
// Initialise state
$fsm->initialise("draft");
You can now use it
// Will output "draft"
$fsm->getState()->getId();
// Change state
$fsm->transition("delete");
// Will output "deleted"
$fsm->getState()->getId();
// Will throw an OverStated\Exceptions\TransitionException
$fsm->transition("delete");
You can add a hook on a transition by overriding validatesTransition().
use OverStated\Transitions\Transition;
/**
* Class Validate
*/
class Validate extends Transition {
public $slug = "validate";
public $name = "Validate";
public $description = "Validate a post";
public $from = ["draft"];
public $to = "valid";
/**
* @override
*/
public function validatesTransition() {
// Model is available if you use Stateful trait on a Model
$post = $this->machine->getModel();
if (empty($post->content)) {
$this->addError('Content must be set')
}
}
}