Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel State Management Laravel Package

mkd/laravel-state-management

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Run composer require mkd/laravel-state-management to add the package to your Laravel project.

  2. 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/.

  3. Define State In the generated store, define $attributes (e.g., user, settings) and optionally $casts (e.g., 'user' => User::class).

  4. Access State Inject the store into a service or controller:

    public function __construct(private UserStore $userStore) {}
    

    Access state via $this->userStore->user.

  5. Set Initial State Define defaults in boot() (e.g., Auth::user()):

    public function boot(): void
    {
        $this->user = Auth::user();
    }
    

First Use Case

Example: User Authentication State

  • Create UserStore to manage logged-in user data.
  • Inject into controllers to avoid repeated Auth::user() calls.
  • Persist state across requests using $this->persist().

Implementation Patterns

Core Workflows

  1. State Initialization

    • Define defaults in boot() or via constructor.
    • Example:
      public function boot(): void
      {
          $this->settings = [
              'theme' => 'dark',
              'notifications' => [],
          ];
      }
      
  2. Casting Attributes

    • Use $casts to automatically transform state (e.g., JSON, collections):
      protected $casts = [
          'user' => User::class,
          'roles' => RoleCollection::class,
      ];
      
  3. Persistence

    • Save state to cache/disk:
      $this->persist(); // Uses default driver (cache by default)
      $this->persist('file'); // Specify driver
      
    • Rehydrate on demand:
      $this->rehydrate();
      
  4. Custom Methods

    • Add logic to stores (e.g., toggleTheme()):
      public function toggleTheme(): void
      {
          $this->settings['theme'] = $this->settings['theme'] === 'dark' ? 'light' : 'dark';
      }
      
  5. Dependency Injection

    • Bind stores in AppServiceProvider for global access:
      $this->app->singleton(UserStore::class, fn() => new UserStore());
      

Integration Tips

  • Middleware: Rehydrate state in middleware (e.g., RehydrateStateMiddleware).
  • Events: Trigger state updates via events (e.g., UserUpdated).
  • Testing: Mock stores in tests:
    $store = $this->app->make(UserStore::class);
    $store->forceSet('user', $fakeUser);
    

Gotchas and Tips

Pitfalls

  1. State Overwriting

    • Avoid manually reassigning $attributes; use $this->set() or $this->merge() to preserve casts.
    • ❌ Bad: $this->attributes['user'] = $user;
    • ✅ Good: $this->set('user', $user);
  2. Persistence Drivers

    • Defaults to cache; ensure the driver is configured in config/state-management.php.
    • For file persistence, verify storage_path('framework/state') is writable.
  3. Circular References

    • Casting to Eloquent models with circular relationships (e.g., UserRole) may cause serialization errors.
    • Fix: Use ->toArray() or exclude relations in casts.
  4. Singleton Scope

    • Stores are application-wide singletons. Avoid storing request-specific data unless explicitly managed.

Debugging

  • Check Rehydration
    • Log state before/after rehydrate():
      \Log::debug('State after rehydrate:', $this->toArray());
      
  • Clear Persisted State
    • Use php artisan state:clear to reset all stores.

Extension Points

  1. Custom Drivers

    • Extend 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));
          }
      }
      
    • Register in config/state-management.php.
  2. Store Events

    • Listen for StatePersisted/StateRehydrated events:
      event(new StatePersisted($store, $state));
      
  3. Dynamic Attributes

    • Use dynamicAttributes() to lazy-load state:
      public function dynamicAttributes(): array
      {
          return ['user' => fn() => Auth::user()];
      }
      

Pro Tips

  • Type Safety: Use PHP 8.2+ attributes for stricter typing:
    #[Attribute]
    class StoreAttribute {}
    
  • Performance: Batch persist() calls in bulk operations.
  • Fallbacks: Define defaultState() for critical stores:
    public function defaultState(): array
    {
        return ['user' => null, 'settings' => []];
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope