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

elipzis/laravel-cacheable-model

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require elipzis/laravel-cacheable-model
    

    Publish the config file (optional):

    php artisan vendor:publish --tag="cacheable-model-config"
    
  2. Enable Caching for a Model: Add the Cacheable trait to your Eloquent model:

    use ElipZis\Cacheable\Models\Traits\Cacheable;
    
    class Product extends Model
    {
        use Cacheable;
    }
    
  3. First Use Case: Immediately start querying the model—caching works automatically:

    $products = Product::query()->where('category', 'electronics')->get();
    // Subsequent identical queries will return cached results
    

Key Configuration

  • TTL (Time-To-Live): Default 300 seconds (5 minutes). Override per model via getCacheableProperties().
  • Prefix: Default 'cacheable'. Customize to avoid key collisions.
  • Logging: Enable via config for debugging (e.g., cache hits/misses).

Implementation Patterns

Core Workflow

  1. Query Execution: The package intercepts all QueryBuilder calls (e.g., get(), first(), find()) and checks for cached results.

    // Cached if identical query exists
    Product::where('price', '>', 100)->get();
    
  2. Cache Invalidation: Automatically flushes cache on:

    • create()
    • update()
    • delete()
    • Explicit flushCache() calls:
      Product::query()->flushCache();
      
  3. Dynamic Configuration: Override defaults per model:

    public function getCacheableProperties(): array
    {
        return [
            'ttl' => 600, // 10-minute cache
            'prefix' => 'products',
        ];
    }
    

Advanced Patterns

  • Bypass Caching: Use withoutCache() for uncached queries (e.g., admin dashboards):

    Product::query()->withoutCache()->get();
    
  • Tagged Cache: Leverage Laravel’s cache tags for bulk invalidation (requires CacheableQueryBuilder v0.5.0+):

    // Tag queries with 'products:electronics'
    Product::where('category', 'electronics')->get();
    // Flush all tagged entries
    Cache::tags('products:electronics')->flush();
    
  • Complex Queries: Supports whereIn, orWhere, join, and raw expressions. Test edge cases like whereNull:

    Product::whereNull('deleted_at')->get(); // Works in v0.6.0+
    

Integration Tips

  • Cache Drivers: Prioritize Redis or Memcached for high-throughput systems. Fallback to file/database if needed.
  • Monitoring: Enable logging to track cache efficiency:
    'logging' => [
        'enabled' => true,
        'channel' => 'cache',
        'level' => 'debug',
    ],
    
  • Testing: Mock CacheableQueryBuilder in unit tests to isolate logic:
    $this->partialMock(Product::class, CacheableQueryBuilder::class);
    

Gotchas and Tips

Pitfalls

  1. Performance Overhead:

    • Issue: Query interception adds ~1–5ms per request. Benchmark before applying to all models.
    • Fix: Reserve for read-heavy, rarely updated models (e.g., product catalogs).
  2. Cache Key Collisions:

    • Issue: Default identifier (id) may not uniquely represent queries with orderBy or limit.
    • Fix: Extend getCacheKey() in your model:
      protected function getCacheKey(): string
      {
          return md5($this->toCacheKeyArray() . serialize($this->query->getQuery()->orders));
      }
      
  3. Stale Data:

    • Issue: Cache invalidation may lag if updates happen outside Laravel (e.g., cron jobs).
    • Fix: Use flushCache() in observers or listeners:
      Product::observe(ProductObserver::class);
      // In observer:
      Product::query()->flushCache();
      
  4. Query Builder Limitations:

    • Issue: Complex queries (e.g., subqueries, raw SQL) may not cache correctly.
    • Fix: Test thoroughly or disable caching for such queries.

Debugging Tips

  • Cache Misses: Enable logging to identify uncached queries:

    'logging' => ['enabled' => true, 'channel' => 'cache'],
    

    Check logs for CacheableQueryBuilder debug entries.

  • Key Inspection: Dump the cache key to verify uniqueness:

    dd(Product::query()->where('price', '>', 100)->getCacheKey());
    
  • Tagged Cache Issues: Ensure tags are consistent:

    // Avoid:
    Product::where('category', 'electronics')->get(); // Tag: 'cacheable:products:where:category,electronics'
    // Prefer:
    Product::tagged('products:electronics')->get(); // Explicit tag
    

Extension Points

  1. Custom Cache Stores: Bind a custom store in CacheableServiceProvider:

    $this->app->bind('cache.store', function () {
        return Cache::store('redis')->getStore();
    });
    
  2. Event Hooks: Listen for cache events (e.g., CacheableCached, CacheableMissed) via Laravel events:

    Event::listen(CacheableCached::class, function ($event) {
        Log::debug("Cached query: {$event->query}");
    });
    
  3. Query Whitelisting: Exclude specific queries from caching by overriding shouldCache():

    protected function shouldCache(): bool
    {
        return !str_contains($this->toCacheKeyArray(), 'admin_');
    }
    

Configuration Quirks

  • TTL Granularity: Set per-model TTLs for dynamic data (e.g., ttl => 60 for stock levels).
  • Prefix Scope: Use namespaced prefixes to avoid conflicts in multi-tenant apps:
    'prefix' => 'tenant1_products',
    
  • Logging Channel: Direct logs to a dedicated channel (e.g., cache) for easier filtering.

Pro Tips

  • Warm-Up Cache: Pre-load critical queries in a command:
    Product::query()->where('featured', true)->get(); // Populates cache
    
  • Cache Stampede Protection: Use Cache::remember() for fallback logic:
    $products = Cache::remember('featured_products', 300, function () {
        return Product::where('featured', true)->get();
    });
    
  • Partial Caching: Cache only specific attributes:
    Product::with(['images' => function ($query) {
        $query->cached(true); // Hypothetical; use package features instead
    }])->get();
    
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.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony