mkd/laravel-state-management
Installation
Run composer require mkd/laravel-state-management to add the package to your Laravel project.
Generate a Store
Use the Artisan command php artisan store:make [StoreName] (e.g., php artisan store:make UserStore) to scaffold a new store in app/Stores/.
Define State
In the generated store, define $attributes (e.g., user, settings) and optionally $casts (e.g., 'user' => User::class).
Access State Inject the store into a service or controller:
public function __construct(private UserStore $userStore) {}
Access state via $this->userStore->user.
Set Initial State
Define defaults in boot() (e.g., Auth::user()):
public function boot(): void
{
$this->user = Auth::user();
}
Example: User Authentication State
UserStore to manage logged-in user data.Auth::user() calls.$this->persist().State Initialization
boot() or via constructor.public function boot(): void
{
$this->settings = [
'theme' => 'dark',
'notifications' => [],
];
}
Casting Attributes
$casts to automatically transform state (e.g., JSON, collections):
protected $casts = [
'user' => User::class,
'roles' => RoleCollection::class,
];
Persistence
$this->persist(); // Uses default driver (cache by default)
$this->persist('file'); // Specify driver
$this->rehydrate();
Custom Methods
toggleTheme()):
public function toggleTheme(): void
{
$this->settings['theme'] = $this->settings['theme'] === 'dark' ? 'light' : 'dark';
}
Dependency Injection
AppServiceProvider for global access:
$this->app->singleton(UserStore::class, fn() => new UserStore());
RehydrateStateMiddleware).UserUpdated).$store = $this->app->make(UserStore::class);
$store->forceSet('user', $fakeUser);
State Overwriting
$attributes; use $this->set() or $this->merge() to preserve casts.$this->attributes['user'] = $user;$this->set('user', $user);Persistence Drivers
cache; ensure the driver is configured in config/state-management.php.storage_path('framework/state') is writable.Circular References
User ↔ Role) may cause serialization errors.->toArray() or exclude relations in casts.Singleton Scope
rehydrate():
\Log::debug('State after rehydrate:', $this->toArray());
php artisan state:clear to reset all stores.Custom Drivers
StateDriver to support new backends (e.g., Redis):
class RedisStateDriver extends StateDriver
{
public function persist(array $state): void
{
Redis::set('state:user', json_encode($state));
}
}
config/state-management.php.Store Events
StatePersisted/StateRehydrated events:
event(new StatePersisted($store, $state));
Dynamic Attributes
dynamicAttributes() to lazy-load state:
public function dynamicAttributes(): array
{
return ['user' => fn() => Auth::user()];
}
#[Attribute]
class StoreAttribute {}
persist() calls in bulk operations.defaultState() for critical stores:
public function defaultState(): array
{
return ['user' => null, 'settings' => []];
}
How can I help you explore Laravel packages today?