Support the ongoing development of Laravel.io →
posted 10 years ago
Eloquent
Last updated 2 years ago.
0

You might want to post some code?

Last updated 2 years ago.
0

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?

Last updated 2 years ago.
0

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();  // <<<<
    }
    
    ....
Last updated 2 years ago.
0

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.

Last updated 2 years ago.
0

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 :-)

Last updated 2 years ago.
0

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.

Last updated 2 years ago.
0

Sign in to participate in this thread!

Eventy

Your banner here too?

kmcluckie kmcluckie Joined 12 Feb 2014

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2024 Laravel.io - All rights reserved.