Skip to content

Quick Start ​

This guide covers the basic configuration needed to start using Filament Flow: setting up your database, creating state classes, and configuring your model.

Database Setup ​

Your database table must have a string column to store the state. Additionally, you may want to add timestamp columns to track when specific states were reached.

Example migration:

php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->id();
            $table->string('order_number')->unique();
            $table->string('customer_name');
            $table->string('customer_email');
            $table->text('customer_address')->nullable();
            $table->decimal('total_amount', 10, 2)->default(0);
            
            // Required: State column
            $table->string('state');
            
            // Optional: Timestamp columns for tracking state changes
            $table->timestamp('processed_at')->nullable();
            $table->timestamp('shipped_at')->nullable();
            $table->timestamp('delivered_at')->nullable();
            $table->timestamp('cancelled_at')->nullable();
            
            // Optional: Additional state-related data
            $table->text('cancellation_reason')->nullable();
            $table->text('notes')->nullable();
            
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('orders');
    }
};

Required columns:

  • state (string) — Stores the fully qualified class name of the current state

Recommended columns:

  • State-specific timestamp columns (e.g., processed_at, shipped_at)
  • Additional data columns for transition information (e.g., cancellation_reason)
  • A notes or comments text column for general information

Creating State Classes ​

1. Create the Abstract State Class ​

First, create an abstract state class that implements HasStateMetadata and uses the HasStateMetadata trait:

php
<?php
// app/States/Order/OrderState.php

namespace App\States\Order;

use RoBYCoNTe\FilamentFlow\Concerns\HasStateMetadata;
use RoBYCoNTe\FilamentFlow\Contracts\HasStateMetadata as HasStateMetadataContract;
use Spatie\ModelStates\State;
use Spatie\ModelStates\StateConfig;

abstract class OrderState extends State implements HasStateMetadataContract
{
    use HasStateMetadata;

    public static function config(): StateConfig
    {
        return parent::config()
            ->default(PendingState::class)
            ->allowTransition(PendingState::class, ProcessingState::class, ProcessTransition::class)
            ->allowTransition(ProcessingState::class, ShippedState::class, ShipTransition::class)
            ->allowTransition(ShippedState::class, DeliveredState::class)
            ->allowTransition([PendingState::class, ProcessingState::class], CancelledState::class, CancelTransition::class);
    }
}

2. Create Concrete State Classes ​

Each state should implement the UI metadata interfaces for a rich visual experience:

php
<?php
// app/States/Order/PendingState.php

namespace App\States\Order;

use Filament\Support\Colors\Color;
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasDescription;
use Filament\Support\Contracts\HasIcon;
use Filament\Support\Contracts\HasLabel;
use Filament\Support\Icons\Heroicon;

final class PendingState extends OrderState implements HasLabel, HasIcon, HasColor, HasDescription
{
    public function getLabel(): string
    {
        return __("Pending");
    }

    public function getIcon(): string
    {
        return Heroicon::Clock;
    }

    public function getColor(): string|array
    {
        return Color::Amber;
    }

    public function getDescription(): string
    {
        return __("The order is pending and awaiting processing.");
    }
}

Available interfaces:

InterfaceDescription
HasLabelDisplay name for the state
HasIconIcon using Heroicon enum or string
HasColorColor using Filament's Color helper
HasDescriptionOptional description text

Configuring Your Model ​

Add the HasStates trait and cast your state column:

php
<?php
// app/Models/Order.php

namespace App\Models;

use App\States\Order\OrderState;
use Illuminate\Database\Eloquent\Model;
use Spatie\ModelStates\HasStates;

class Order extends Model
{
    use HasStates;

    protected $fillable = [
        'order_number',
        'customer_name',
        'customer_email',
        'customer_address',
        'total_amount',
        'state',
        'notes',
        'processed_at',
        'shipped_at',
        'delivered_at',
        'cancelled_at',
        'cancellation_reason',
    ];

    protected $casts = [
        'state' => OrderState::class,
        'total_amount' => 'decimal:2',
        'processed_at' => 'datetime',
        'shipped_at' => 'datetime',
        'delivered_at' => 'datetime',
        'cancelled_at' => 'datetime',
    ];
}

Next Steps ​

Proprietary software. All rights reserved.