PHP code example of iotron / laravel-state-machine

1. Go to this page and download the library: Download iotron/laravel-state-machine library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

iotron / laravel-state-machine example snippets


namespace App\StateMachines;

use App\Enums\OrderStatus;
use Iotron\StateMachine\StateMachines\StateMachine;

class OrderStatusStateMachine extends StateMachine
{
    public function transitions(): array
    {
        return [
            'pending'    => ['confirmed', 'cancelled'],
            'confirmed'  => ['dispatched', 'cancelled'],
            'dispatched' => ['delivered'],
        ];
    }

    public function defaultState(): ?string
    {
        return OrderStatus::PENDING->value;
    }
}

use Iotron\StateMachine\Concerns\HasStateMachines;

class Order extends Model
{
    use HasStateMachines;

    public $stateMachines = [
        'status' => OrderStatusStateMachine::class,
    ];

    protected function casts(): array
    {
        return [
            'status' => OrderStatus::class, // native enum cast works!
        ];
    }
}

$order = Order::create();

// Query state
$order->status()->is(OrderStatus::PENDING);       // true
$order->status()->canBe(OrderStatus::CONFIRMED);   // true
$order->status()->canBe(OrderStatus::DELIVERED);   // false

// Transition
$order->status()->transitionTo(OrderStatus::CONFIRMED);

// History
$order->status()->was(OrderStatus::PENDING);        // true
$order->status()->timesWas(OrderStatus::PENDING);    // 1
$order->status()->whenWas(OrderStatus::CONFIRMED);   // Carbon
$order->status()->snapshotWhen(OrderStatus::CONFIRMED); // Transition model

// Custom properties
$order->status()->transitionTo('dispatched', ['tracking' => 'ABC123']);
$order->status()->getCustomProperty('tracking'); // 'ABC123'

// config/state-machine.php
return [
    'tables' => [
        'transitions'         => 'state_histories',    // history table name
        'pending_transitions' => 'pending_transitions',
    ],
    'record_changed_attributes'    => true,  // capture dirty attributes on transition
    'cancel_pending_on_transition' => true,  // auto-cancel pending when transitioning
];

public function transitions(): array
{
    return [
        'draft'     => ['pending', 'cancelled'],
        'pending'   => ['approved', 'rejected'],
        'approved'  => ['published'],
        // Wildcard support
        '*'         => ['archived'],  // any state can go to archived
    ];
}

public function defaultState(): ?string
{
    return 'draft';
    // or: return MyEnum::DRAFT->value;
}

public function recordHistory(): bool
{
    return true;
}

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Support\Facades\Validator as ValidatorFacade;

public function validatorForTransition($from, $to, $model): ?Validator
{
    if ($to === 'published') {
        $validator = ValidatorFacade::make([], []);

        if (! $model->title) {
            $validator->after(fn ($v) => $v->errors()->add(
                'title', 'A title is 

public function beforeTransitionHooks(): array
{
    return [
        'published' => [ // keyed by the FROM state
            function (string $from, string $to, Model $model) {
                // Runs before leaving 'published'
            },
        ],
    ];
}

public function afterTransitionHooks(): array
{
    return [
        'confirmed' => [ // keyed by the TO state
            function (string $from, string $to, Model $model) {
                $model->update(['confirmed_at' => now()]);
            },
        ],
    ];
}

// 2 queries total: models + stateHistory
$orders = Order::with('stateHistory')->get();

// 0 additional queries for any number of models
foreach ($orders as $order) {
    $order->status()->was(OrderStatus::PENDING);
    $order->status()->timesWas(OrderStatus::CONFIRMED);
    $order->status()->snapshotWhen(OrderStatus::DISPATCHED);
}

// In a listener or EventServiceProvider
use Iotron\StateMachine\Events\TransitionCompleted;

Event::listen(TransitionCompleted::class, function (TransitionCompleted $event) {
    if ($event->field === 'status' && $event->to === 'published') {
        // Send notification, dispatch job, etc.
    }
});

$order->status()->postponeTransitionTo('dispatched', Carbon::tomorrow());

// bootstrap/app.php or routes/console.php
use Iotron\StateMachine\Jobs\DispatchPendingTransitions;

Schedule::job(new DispatchPendingTransitions)->everyMinute();

use Iotron\StateMachine\Models\Transition;

// Query scopes
Transition::forField('status')->to('published')->get();
Transition::withTransition('pending', 'published')->get();
Transition::withCustomProperty('reason', '=', 'approved')->get();
Transition::withResponsible($user)->get();

// Instance methods
$transition->getCustomProperty('key');
$transition->allCustomProperties();
$transition->changedAttributesNames();
$transition->changedAttributeOldValue('title');
$transition->changedAttributeNewValue('title');

protected function casts(): array
{
    return [
        'status' => OrderStatus::class, // just works!
    ];
}
bash
php artisan vendor:publish --tag=state-machine-config
bash
php artisan vendor:publish --tag=state-machine-migrations
php artisan migrate
diff
  public function afterTransitionHooks(): array
  {
      return [
          'confirmed' => [
-             function ($from, $model) {
+             function ($from, $to, $model) {
                  $model->update(['confirmed_at' => now()]);
              },
          ],
      ];
  }