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 Model Caching Laravel Package

mikebronner/laravel-model-caching

Speeds up Eloquent by automatically caching model queries and relationships, cutting repetitive database hits. Drop-in package with cache tagging support, configurable cache stores and TTLs, and easy invalidation on model updates—ideal for high-traffic Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require genealabs/laravel-model-caching
    

    (Auto-discovery handles the service provider.)

  2. Apply the Trait: Add Cachable to your base model or individual models:

    use GeneaLabs\LaravelModelCaching\Traits\Cachable;
    
    class Post extends Model
    {
        use Cachable;
    }
    
  3. First Use Case: Query normally—caching and invalidation happen automatically:

    $posts = Post::with('comments')->where('published', true)->paginate();
    

    No manual cache keys or invalidation needed.


Where to Look First

  • README.md: Focus on the "Before & After" section and "What Gets Cached" list.
  • Configuration: Check config/laravel-model-caching.php (publish with php artisan modelCache:publish --config).
  • Model Integration: Start with a single high-traffic model (e.g., Post) to test caching behavior.

First Debugging Steps

  1. Verify Caching: Check if queries are hitting the cache by inspecting the cache store (e.g., Redis CLI: KEYS *). Use dd() on query results to compare execution times.

  2. Check Invalidation: Trigger a model update/delete and verify cache keys disappear:

    php artisan modelCache:clear  # Clears all cached queries
    
  3. Logs: Enable debug logging in config/laravel-model-caching.php:

    'debug' => env('MODEL_CACHE_DEBUG', false),
    

Implementation Patterns

Core Workflow

  1. Apply Trait: Extend Cachable to models that need caching (e.g., Post, User). Avoid applying to models with high write churn (e.g., Comment) unless using cool-down.

  2. Query Patterns:

    • Eager Load Relationships: Always use with() for relationships to cache them:
      $posts = Post::with('comments.tags')->get();
      
    • Avoid select(): Custom column selections bypass caching.
    • Disable Caching Temporarily:
      Post::disableCache()->where('active', false)->get();
      
  3. Invalidation:

    • Automatic: Triggered by save(), delete(), or forceDelete() on cached models.
    • Manual: Use ModelCache::invalidate() for custom logic:
      use GeneaLabs\LaravelModelCaching\Facades\ModelCache;
      
      ModelCache::invalidate(Post::class);
      

Integration Tips

  1. Multi-Tenancy: Use $cachePrefix per model or globally in config:

    class Post extends Model
    {
        use Cachable;
        protected $cachePrefix = 'tenant-' . auth()->id();
    }
    
  2. High-Churn Models: Implement cool-down for models like Comment:

    class Comment extends Model
    {
        use Cachable;
        protected $cacheCooldownSeconds = 300; // 5-minute cooldown
    }
    

    Activate in queries:

    Comment::withCacheCooldownSeconds()->create([...]);
    
  3. Transactions: Cache invalidation is deferred until the transaction commits. Manually flush if needed:

    DB::transaction(function () {
        Post::create([...]);
        // Cache is not flushed yet
    });
    ModelCache::flush(); // Force flush
    
  4. Testing: Use disableCache() in tests to avoid stale data:

    $this->withoutModelCaching(function () {
        Post::factory()->create();
    });
    
  5. Cache Store Isolation: Dedicate a Redis/Memcached instance for model caching by configuring a custom store in config/cache.php:

    'model-cache' => [
        'driver' => 'redis',
        'connection' => 'model_cache',
    ],
    

    Then set:

    MODEL_CACHE_STORE=model-cache
    

Advanced Patterns

  1. Dynamic Cache Keys: Override getCacheKey() in your model for custom key logic:

    public function getCacheKey()
    {
        return 'custom:key:' . $this->id;
    }
    
  2. Conditional Caching: Disable caching for specific queries using a closure:

    $posts = Post::when(fn () => !request()->wantsJson(), function ($query) {
        return $query->cached();
    })->get();
    
  3. Cache Warmers: Pre-load cache during low-traffic periods (e.g., cron jobs):

    Post::with('comments')->get(); // Warms cache
    
  4. Event-Based Invalidation: Listen to model events for granular control:

    Post::saved(function ($post) {
        ModelCache::invalidate(Post::class);
    });
    

Gotchas and Tips

Pitfalls

  1. Lazy-Loaded Relationships: Only eager-loaded (with()) relationships are cached. Lazy loads bypass the cache:

    $post = Post::find(1);
    $post->comments; // Not cached!
    
  2. Raw Queries: Bypass cache if using DB::table() or query builder without Eloquent:

    DB::table('posts')->get(); // Not cached!
    
  3. Transactions: Cache invalidation is deferred until the transaction commits. Use ModelCache::flush() manually if needed.

  4. DynamoDB Quirks:

    • Stale Data: DynamoDB uses logical invalidation (TTL-based cleanup). Expect temporary stale rows.
    • Performance: High-churn models may see increased table size until TTL removes stale rows.
    • Fallback: Enable MODEL_CACHE_FALLBACK_TO_DB=true to avoid read failures during outages.
  5. Cool-Down Misuse: Forgetting to call withCacheCooldownSeconds() means the cooldown is ignored:

    // ❌ No cooldown activated
    Comment::create([...]);
    
    // ✅ Cooldown activated
    Comment::withCacheCooldownSeconds()->create([...]);
    
  6. Multi-Database Keying: Disable use-database-keying if you share cache across databases manually:

    'use-database-keying' => false,
    

Debugging Tips

  1. Cache Key Inspection: Log cache keys to understand what’s being cached:

    Post::addGlobalCacheListener(function ($key, $value) {
        \Log::debug("Cached: {$key}");
    });
    
  2. Redis CLI: Inspect cached queries in Redis:

    redis-cli keys "*"
    redis-cli get "posts:active:page:1"
    
  3. Disable Caching: Temporarily disable caching to isolate issues:

    Post::disableCache()->get();
    

    Or globally:

    MODEL_CACHE_ENABLED=false
    
  4. Check Invalidation: Verify invalidation works by:

    • Updating a model.
    • Checking if the cache key disappears:
      php artisan modelCache:clear  # Clear all
      php artisan tinker
      >>> \Cache::has('posts:active:page:1')  # Should return false
      
  5. Cool-Down Debugging: Check if cool-down is active:

    $comment = Comment::withCacheCooldownSeconds()->create([...]);
    \Log::debug($comment->freshTimestamp()); // Should show cooldown metadata
    

Configuration Quirks

  1. Cache Prefix:

    • Global prefix in config/laravel-model-caching.php:
      'cache-prefix' => 'app_',
      
    • Per-model override:
      protected $cachePrefix = 'tenant_' . $this->tenantId;
      
  2. Fallback Behavior:

    • Enable fallback-to-database to avoid exceptions during cache outages:
      MODEL_CACHE_FALLBACK_TO_DB=true
      
    • Logs warnings when falling back.
  3. DynamoDB TTL:

    • Ensure TTL is enabled on the expires_at attribute in DynamoDB.
    • Long-lived TTL (years) may delay physical cleanup of stale rows.
  4. Debug Mode: Enable debug logging for troubleshooting:

    'debug' => true,
    

    Logs cache hits/misses and invalidation events.


Extension Points

  1. Custom Cache Store: Extend the package to support additional stores (e.g., ArangoDB) by implementing GeneaLabs\LaravelModelCaching\Contracts\CacheStore.

  2. Event Listeners: Hook into cache events for custom logic:

    ModelCache::listen('beforeInvalid
    
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.
terminal42/code-quality-tools
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