Sure. I have a model declared (in part) like so:
class Message extends \LaravelBook\Ardent\Ardent
{
use FiniteStateMachine;
public function __construct($attributes = [])
{
parent::__construct($attributes);
$this->initStateMachine();
}
protected function stateMachineConfig()
{
return [
'states' => [
'Draft' => [
'type' => 'initial'
],
'Sending' => [
'type' => 'normal'
],
'Paused' => [
'type' => 'normal'
],
'Ended' => [
'type' => 'final'
],
'Sent' => [
'type' => 'final'
]
],
'transitions' => [
'Send' => ['from' => ['Draft'], 'to' => 'Sending'],
'Pause' => ['from' => ['Sending'], 'to' => 'Paused'],
'End' => ['from' => ['Paused'], 'to' => 'Ended'],
'Resume' => ['from' => ['Paused'], 'to' => 'Sending'],
'Complete' => ['from' => ['Sending'], 'to' => 'Sent'],
],
'callbacks' => [
'after' => [
['on' => 'Send', 'do' => [$this, 'afterSend']],
['on' => 'Pause', 'do' => [$this, 'afterPause']],
['on' => 'End', 'do' => [$this, 'afterEnd']],
['on' => 'Resume', 'do' => [$this, 'afterResume']],
['on' => 'Complete', 'do' => [$this, 'afterComplete']],
]
],
];
}
...
}
I have a Message record saved in the database with the state
field set to 'Paused'.
However this code:
$m = Pioneer\MassMail\Message::find(1);
echo $m->getCurrentState();
... results in Draft
being echoed, since that is the initial state set by the stateMachineConfig()
method. The problem is that in the constructor the $this->initStateMachine();
line will initialise the state machine, but the state value from the DB is not yet available. For the record the initStateMachine()
method uses the following method defined in the linked trait:
public function getFiniteState()
{
return $this->state;
}
So if initStateMachine()
could get called later it would initialise with the right state.
Does this make sense?
Watch out! You are mislead, the appropriate gist is elsewhere.
A sample of Trait applicable to Eloquent Model is here trait FiniteAuditTrail along with a sample Model implementing the FSM here class MyStatefulModel and more other details in the FiniteAuditTrail Trait gist.
At first glance, you class defintion doesn't include some initialization sequences that should be respectfully coded within:
public static function boot()
. public function __construct($attributes = [])
.Excerpt:
class MyStatefulModel extends Eloquent implements Finite\StatefulInterface
{
use FiniteStateMachine;
use FiniteAuditTrail; // <<<<
public static function boot()
{
parent::boot(); // <<<<
static::finiteAuditTrailBoot(); // <<<<
}
public function __construct($attributes = [])
{
$this->initStateMachine(); // <<<<
parent::__construct($attributes); // <<<<
$this->initAuditTrail(); // <<<<
}
....
I've seen those pages also, but I don't actually want an audit trail of the state transitions. Perhaps I'll look through it though and see how it loads the state from the DB.
True indeed - Your concern is how to make FSM works seamlessly with the way Laravel hydrates the Eloquent Model. Don't forget to share your findings :-)
For the record, what worked was this:
I modified the FSM trait that I linked to above by overriding Eloquents newFromBuilder()
method:
public function newFromBuilder($attributes = [])
{
$instance = parent::newFromBuilder($attributes);
$instance->getStateMachine()->initialize();
return $instance;
}
and modified it's getStateMachine()
method like so:
protected function getStateMachine()
{
if (!$this->stateMachine) { $this->initStateMachine(); }
return $this->stateMachine;
}
Then, all my model needs is the use FiniteStateMachine
statement, and a stateMachineConfig()
method.
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community