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 Dependency Aware Cache Laravel Package

craftcms/laravel-dependency-aware-cache

Laravel cache extension that tracks dependencies and automatically invalidates cached items when related keys change. Useful for keeping derived or aggregated data fresh without manual cache flushing. Designed for straightforward integration with Laravel’s cache system.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require craftcms/laravel-dependency-aware-cache
    

    No additional configuration is required—the package automatically hooks into Laravel’s Cache facade.

  2. First Use Case: Cache a value with a dependency (e.g., a product’s price tied to its updated_at timestamp):

    use CraftCms\DependencyAwareCache\Dependency\FileDependency;
    use Illuminate\Support\Facades\Cache;
    
    // Cache product price with dependency on product file
    Cache::put(
        'product_123_price',
        99.99,
        now()->addHours(1),
        new FileDependency(storage_path('app/products/123.json'))
    );
    
    // Later, when the product file changes, the cache invalidates automatically
    
  3. Where to Look First:

    • Facade: Use Cache or DependencyCache (extended facade with better docblocks).
    • Dependencies: Explore built-in dependencies like TagDependency, FileDependency, or CallbackDependency in src/Dependency.
    • Events: Check TagsInvalidated event in src/Events for observing invalidations.

Implementation Patterns

Usage Patterns

  1. Tag-Based Invalidation (Most Common) Tie cache keys to tags (e.g., user IDs, product categories) and invalidate by tag:

    // Cache user dashboard with dependency on user ID
    Cache::put('user_42_dashboard', $dashboardData, now()->addMinutes(30), new TagDependency('user_42'));
    
    // Invalidate all caches for user 42 (e.g., in a UserObserver)
    TagDependency::invalidate('user_42');
    
  2. File-Based Dependencies Invalidate caches when files change (e.g., config, templates, or JSON data):

    Cache::put(
        'config_menu',
        $menuConfig,
        now()->addHours(1),
        new FileDependency(config_path('menu.php'))
    );
    
  3. Dynamic Dependencies with Callbacks Use CallbackDependency for runtime checks (e.g., cache invalidation when a database record changes):

    Cache::put(
        'active_users_count',
        User::active()->count(),
        now()->addMinutes(5),
        new CallbackDependency(fn() => User::active()->count())
    );
    
  4. Combining Dependencies Use AnyDependency or AllDependencies for complex rules:

    // Invalidate if EITHER the file OR the callback changes
    $dependency = new AnyDependency([
        new FileDependency('path/to/file'),
        new CallbackDependency(fn() => $someCondition),
    ]);
    
    Cache::put('complex_key', $data, null, $dependency);
    
  5. Integration with Eloquent Observers Automatically invalidate caches when models are updated:

    use CraftCms\DependencyAwareCache\Dependency\TagDependency;
    use Illuminate\Database\Eloquent\Model;
    
    Model::observe(function ($model) {
        if ($model->wasChanged('updated_at')) {
            TagDependency::invalidate("model_{$model->getKey()}");
        }
    });
    

Workflows

  1. Cache-as-You-Go Replace manual Cache::remember with dependency-aware caching:

    // Before: Manual invalidation
    $data = Cache::remember("user_{$user->id}_profile", now()->addHours(1), function() use ($user) {
        return $user->profile()->first();
    });
    // After: Dependency-aware
    Cache::put("user_{$user->id}_profile", $user->profile()->first(), now()->addHours(1), new TagDependency("user_{$user->id}"));
    
  2. Bulk Invalidation Invalidate multiple tags at once (e.g., during a cache rebuild):

    TagDependency::invalidate(['user_1', 'user_2', 'product_42']);
    
  3. Fallback to Default Cache Use Laravel’s native cache for non-critical keys:

    if ($isCritical) {
        Cache::put($key, $value, $ttl, $dependency);
    } else {
        Cache::put($key, $value, $ttl); // No dependency
    }
    

Integration Tips

  1. Leverage Events Listen for TagsInvalidated to log or trigger side effects:

    use CraftCms\DependencyAwareCache\Events\TagsInvalidated;
    use Illuminate\Support\Facades\Event;
    
    Event::listen(TagsInvalidated::class, function (TagsInvalidated $event) {
        Log::info("Invalidated tags: " . implode(', ', $event->tags));
    });
    
  2. Custom Dependencies Extend Dependency for domain-specific logic:

    class StockLevelDependency extends Dependency
    {
        public function __construct(public int $productId)
        {
        }
    
        public function getDependencies(): array
        {
            return [Stock::where('product_id', $this->productId)->value('last_updated')];
        }
    }
    
  3. Testing Mock dependencies in tests:

    $this->mock(TagDependency::class)
        ->shouldReceive('invalidate')
        ->once()
        ->with('user_42');
    
  4. Performance Tuning

    • Avoid overusing CallbackDependency in high-traffic areas (runtime checks add overhead).
    • Prefer TagDependency for most use cases (lightweight and efficient).
    • Use FileDependency sparingly (file system checks can be slow).

Gotchas and Tips

Pitfalls

  1. Serialization Issues

    • Problem: Closures or non-serializable objects in CallbackDependency may fail silently.
    • Fix: Use UnsignedSerializableClosure or ensure dependencies are serializable:
      $dependency = new CallbackDependency(
          new UnsignedSerializableClosure(fn() => $someData)
      );
      
  2. Race Conditions

    • Problem: If multiple processes invalidate the same tag simultaneously, you might miss some invalidations.
    • Fix: Use Laravel’s Cache::tags() as a fallback for critical paths.
  3. Memory Leaks

    • Problem: Storing large dependencies (e.g., complex objects) in cache keys can bloat memory.
    • Fix: Keep dependencies lightweight (e.g., use IDs or hashes instead of full objects).
  4. Unexpected Invalidation

    • Problem: CallbackDependency or FileDependency may invalidate caches unpredictably (e.g., file timestamps changing due to permissions).
    • Fix: Add logging to debug invalidation triggers:
      TagDependency::invalidate('user_42');
      Log::debug('Manually invalidated user_42 caches');
      
  5. Laravel Cache Tags Conflict

    • Problem: If you mix this package with Laravel’s native Cache::tags(), invalidation may behave unexpectedly.
    • Fix: Stick to one approach per cache key or use AnyDependency to combine both:
      $dependency = new AnyDependency([
          new TagDependency('user_42'),
          new \Illuminate\Cache\TaggedCache::TAG_PREFIX . 'user_42',
      ]);
      
  6. Driver Limitations

    • Problem: Some cache drivers (e.g., file-based) may not support dependency-aware invalidation efficiently.
    • Fix: Benchmark performance across drivers (Redis/Memcached are best for this package).

Debugging

  1. Check Invalidation Triggers Listen for TagsInvalidated events to trace invalidations:

    Event::listen(TagsInvalidated::class, function ($event) {
        dd($event->tags); // Debug invalidated tags
    });
    
  2. Verify Dependencies Ensure dependencies are correctly registered:

    $cache = Cache::store();
    $item = $cache->get('test_key');
    // Check if dependencies are attached
    dd($cache->getDependencies('test_key'));
    
  3. Test Edge Cases

    • Empty Dependencies: Ensure caches work without dependencies.
    • Non-Existent Tags: Test invalidating tags that don’t exist.
    • Concurrent Writes: Simulate race conditions in tests.

Config Quirks

  1. Default Store The package replaces the default cache store automatically. To use a specific store:

    Cache::store('redis')->put($key, $value, $ttl, $dependency);
    
  2. Event Dispatching Ensure TagsInvalidated events are enabled in config/cache.php:

    'events' => [
        'tags_invalidated' => true,
    ],
    
  3. Laravel 10+ Compatibility

    • If using Laravel 10+, ensure the
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor