a909m / filament-statefusion
Filament StateFusion is a powerful FilamentPHP plugin that seamlessly integrates Spatie Laravel Model States into the Filament admin panel. This package provides an intuitive way to manage model states, transitions, and filtering within Filament, enhancing the user experience and developer productiv
Fund package maintenance!
A909M
Requires
- php: ^8.1
- filament/filament: ^3.0
- spatie/laravel-model-states: ^2.10
- spatie/laravel-package-tools: ^1.15.0
Requires (Dev)
- laravel/pint: ^1.0
- nunomaduro/collision: ^7.9
- nunomaduro/larastan: ^2.0.1
- orchestra/testbench: ^8.0
- pestphp/pest: ^2.1
- pestphp/pest-plugin-arch: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
This package is auto-updated.
Last update: 2025-04-10 06:06:59 UTC
README
Filament StateFusion is a powerful FilamentPHP plugin that seamlessly integrates Spatie Laravel Model States into the Filament admin panel. This package provides an intuitive way to manage model states, transitions, and filtering within Filament, enhancing the user experience and developer productivity.
Introduction
The Model States for Filament plug-in is a powerful tool that seamlessly integrates model states and transitions into the Filament UI. It supports Spatie Laravel Model States out-of-the-box, which makes transitioning, listing, and filtering states effortless tasks.
Example
Consider a scenario where you're managing an e-commerce platform with various order states like new, processing, shipped, delivered, and canceled. With this plug-in, you can effortlessly list all products based on their states, apply filters to quickly locate specific orders in each state, and seamlessly transition between states directly within Filament's intuitive interface. For instance, you can move an order from processing to shipped with just a few clicks, streamlining your workflow and enhancing productivity.
This plug-in leverages the robust capabilities of Filament PHP and the support of Spatie Laravel Model States out-of-the-box, providing a seamless solution for managing model states and transitions with efficiency and ease.
tateDiagram-v2 [*] --> New New --> Processing New --> Canceled Processing --> Shipped Processing --> Canceled Shipped --> Delivered Delivered --> [*] Canceled --> [*]Loading
Features
- Listing states within tables and exports
- Filtering records by states
- Grouping records by states
- Transitioning to valid states using select or toggle button components
- Transitioning to valid states using page and table actions
- Bulk transition to valid states using bulk actions
- Out-of-the-box support for the Spatie Laravel Model States package
- Compatible with dark mode
Installation
You can install the package via composer:
composer require a909m/filament-statefusion
Setup
In this paragraph, we list the steps you need to follow to get up and running with the out-of-the-box supported Spatie integration.
Spatie
Make sure you have configured at least one Spatie Laravel model state. For more information, refer to the official Spatie documentation.
State Preparation
When utilizing Spatie Laravel Model States, you'll have several abstract state classes. These abstract classes
require certain modifications. To properly integrate them, it's necessary to implement the FilamentSpatieState
interface and utilize the ProvidesSpatieStateToFilament
trait.
Here's an example of the OrderState
abstract class with the necessary modifications already applied.
<?php namespace App\States; use App\Models\Order; use A909M\FilamentStateFusion\Concerns\StateFusionInfo; use A909M\FilamentStateFusion\Contracts\HasFilamentStateFusion; use Spatie\ModelStates\State; use Spatie\ModelStates\StateConfig; abstract class OrderState extends State implements HasFilamentStateFusion { use StateFusionInfo; public static function config(): StateConfig { return parent::config() ->default(NewState::class) ->allowTransition(NewState::class, ProcessingState::class) ->allowTransition(ProcessingState::class, ShippedState::class) ->allowTransition(ShippedState::class, DeliveredState::class) ->allowTransition([NewState::class, ProcessingState::class], CancelledState::class, ToCancelled::class); } }
Tip
More information about state configuration can be found in the official Spatie documentation.
Transition Preparation
Spatie Laravel model states offer support for custom transition classes. All custom transition classes must implement
the HasFilamentStateFusion
interface and use the StateFusionInfo
trait before they can be used
within Filament.
Here is an example of the ToCancelled
transition class with the necessary modifications in place.
<?php namespace App\States; use App\Models\Order; use Spatie\ModelStates\Transition; final class ToCancelled extends Transition { public function __construct( private readonly Order $order, ) { } public function handle(): Order { $this->order->state = new CancelledState($this->order); $this->order->cancelled_at = now(); $this->order->save(); return $this->order; } }
Tip
For more information about transition configuration, refer to the official Spatie documentation.
Additional Transition Data
Most of the time, additional data is needed before transitioning to a new state. Considering the ToCancelled
transition, it would be beneficial to store a reason explaining why the state transitioned to cancelled state. By adding
a form
method to the transition class, a form will be displayed when initiating the transition.
Here is an example ToCancelled
transition class with the form is place. This transition will display a reason
textarea when the StateFusionAction
or StateFusionTableAction
button is clicked.
<?php namespace App\States; use App\Models\Order; use Spatie\ModelStates\Transition; final class ToCancelled extends Transition { public function __construct( private readonly Order $order, private readonly string $reason = '', ) { } public function handle(): Order { $this->order->state = new CancelledState($this->order); $this->order->cancelled_at = now(); $this->order->cancellation_reason = $this->reason; $this->order->save(); return $this->order; } public function form(): array | Closure | null { return [ Textarea::make('reason') ->required() ->minLength(1) ->maxLength(1000) ->rows(5) ->helperText(__('This reason will be sent to the customer.')), ]; } }
Warning
Since the plug-in needs to create transition instances to determine if there is a form, all constructor properties, except for the model, must have default values.
By default, this plug-in will map the form component names to their constructor property names. Considering the
previous ToCancelled
transition, the reason
textarea input will correspond to the constructor property $reason
. If
you want to make any modifications before creating the transition instance, you can override the static method fill
.
For example, you can prefix the reason
:
<?php namespace App\States; use App\Models\Order; use Illuminate\Support\Arr; use Spatie\ModelStates\Transition; final class ToCancelled extends Transition i { public function __construct( private readonly Order $order, private readonly string $reason = '', ) { } public static function fill(Model $model, array $formData): SpatieTransition { return new self( order: $model, reason: 'The order is cancelled because: ' . Arr::get($formData, 'reason'), ); } public function handle(): Order { $this->order->state = new CancelledState($this->order); $this->order->cancelled_at = now(); $this->order->cancellation_reason = $this->reason; $this->order->save(); return $this->order; } public function form(): array | Closure | null { return [ Textarea::make('reason') ->required() ->minLength(1) ->maxLength(1000) ->rows(5) ->helperText(__('This reason will be sent to the customer.')), ]; } }
Optional Label, Description, Color and Icon
By default, the name of the state class is used as a label (for example, CancelledState
will have the
label Cancelled
), without any assigned description, color or icon. If you desire a different label, description,
color, or icon, you must implement the HasLabel
, HasDescription
, HasColor
, or HasIcon
interface.
Here is an example of the Cancelled
state with HasLabel
, HasDescription
, HasColor
, and HasIcon
implemented.
<?php namespace App\States; 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; final class CancelledState extends OrderState implements HasDescription, HasColor, HasIcon, HasLabel { public function getLabel(): string { return __('Order Cancelled'); } public function getColor(): array { return Color::Red; } public function getIcon(): string { return 'heroicon-o-x-circle'; } public function getDescription(): ?string { return 'Order cancelled, transaction reversed.'; } }
Note
The description is used when utilizing the StateFusionRadio
component.
By default, "Transition to" followed by the name of the destination state is used as the transition label. Like states,
it has no color or icon. If you want a different label, or if you want to use a color or icon; you have to implement
the HasLabel
, HasColor
or HasIcon
interface.
Here is an example ToCancelled
transtition with HasLabel
, HasColor
and HasIcon
implemented.
<?php namespace App\States; use App\Models\Order; use Filament\Support\Colors\Color; use Filament\Support\Contracts\HasColor; use Filament\Support\Contracts\HasIcon; use Filament\Support\Contracts\HasLabel; use Spatie\ModelStates\Transition; final class ToCancelled extends Transition implements HasLabel, HasColor, HasIcon { public function __construct( private readonly Order $order, private readonly string $reason = '', ) { } public function handle(): Order { $this->order->state = new CancelledState($this->order); $this->order->cancelled_at = now(); $this->order->cancellation_reason = $this->reason; $this->order->save(); return $this->order; } public function getLabel(): string { return __('Mark as Cancelled'); } public function getColor(): array { return Color::Red; } public function getIcon(): string { return 'heroicon-o-x-circle'; } public function form(): array | Closure | null { return [ Textarea::make('reason') ->required() ->minLength(1) ->maxLength(1000) ->rows(5) ->helperText(__('This reason will be sent to the customer.')), ]; } }
Usage
$filamentStateFusion = new A909M\FilamentStateFusion(); echo $filamentStateFusion->echoPhrase('Hello, A909M!');
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.