Weave 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

Cacheable Laravel Package

rinvex/cacheable

Rinvex Cacheable adds automatic query caching to Laravel Eloquent models through a simple drop-in trait. It supports cache tags, configurable TTL, and smart invalidation on create, update, and delete, reducing database load with no extra code.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm version constraints first. The package is archived, so check its composer.json before anything else:

composer show rinvex/cacheable --all   # inspect supported illuminate/* versions
composer require rinvex/cacheable

If you're on a modern Laravel, the illuminate/* constraints will almost certainly refuse to resolve. Decide up front whether you're forking (vendor branch + updated constraints + type-signature fixes in the trait) or abandoning the idea. For a legacy app on Laravel 5.x/6.x it will typically install cleanly.

Publish and configure the cache engine. The package relies on cache tags for invalidation, so the store must support them:

// config/rinvex.cacheable.php (name/tag may differ — check the provider)
return [
    'engine'   => 'redis',   // redis, memcached, or array — NOT file/database
    'lifetime' => 10080,     // minutes
    'prefix'   => 'app:cacheable',
];

Attach the trait to a model:

use Rinvex\Cacheable\Cacheable;

class Country extends Model
{
    use Cacheable;
}

(Some versions spell the trait Cachable; confirm against src/ before importing.)

First use case: read-mostly reference data. Countries, currencies, settings, categories, permission lists — anything you read constantly and write rarely. Attach the trait, then verify you're actually getting hits:

DB::enableQueryLog();
Country::find(1);
Country::find(1);
Country::where('iso2', 'US')->first();
Country::where('iso2', 'US')->first();
count(DB::getQueryLog()); // should be 2, not 4

Where to look first: the trait source (src/*.php) for the boot-style event hooks, the published config, and the getCacheKey() implementation. Those three files tell you the entire behaviour model — everything else is Laravel cache semantics you already know.

Implementation Patterns

Treat it as a query-result cache, not an entity/identity map. The package remembers the result of finder/where calls keyed on the query shape, then flushes the whole model's tag on any saved/deleted/restored event. That makes it excellent for Country::all()-style lookups and poor for tables you write to frequently.

Bulk writes silently bypass invalidation. This is the pattern you'll hit within a week:

// BAD: no model events fire, cache stays stale
Country::where('active', false)->update(['active' => true]);

// GOOD: one event per model, tag flush happens
Country::where('active', false)->get()->each->update(['active' => true]);

// Or flush explicitly after the bulk op
Cache::tags((new Country)->getCacheCollectionTag())->flush();

Use transactions carefully. Model events fire inside the transaction, so the cache is repopulated with pre-commit data that other processes can read. On Laravel 8+ set public $afterCommit = true; on the model, or wrap writes with DB::afterCommit(fn () => $model->flushCache()).

Multi-tenant / multi-database keys. Override the trait's key helper so cache entries don't leak across tenants:

protected function getCacheKey(): string
{
    return parent::getCacheKey().':'.tenant()->id;
}

(Method name varies by version — read the trait.)

Cache aggregates yourself. The package won't cache eager-loaded relations or computed DTOs. Standard pattern: cache the ID list with Cache::remember, then hydrate — or cache the fully-built array/DTO and only fall back to Eloquent on miss.

Tune lifetime per model. Reference data gets a long TTL (day+); anything user-facing gets a short one, or you skip the trait entirely and use Cache::remember with explicit forget calls in observers.

Testing. Force the array store so tests are hermetic and fast:

protected function setUp(): void
{
    parent::setUp();
    config(['rinvex.cacheable.engine' => 'array']);
    Cache::flush();
}

Deploy warm-up. Seed hot keys after cache:clear (a small artisan command that calls Country::all(), Setting::all(), etc.) so you don't take a cold-cache hit on the first requests.

Gotchas and Tips

It's abandoned — budget for that. No Laravel 9/10/11 support, no PHP 8.1+ fixes, no security patches. If you adopt it, fork it into your own VCS namespace, pin the constraint, and own the maintenance. Compare against genealabs/laravel-model-caching (also bumpy, but more current) or plain Cache::remember + observers before committing.

Tag support is non-negotiable. file and database cache drivers throw on Cache::tags(). If your config silently falls back to default and that's file, invalidation fails at runtime. Explicitly set engine => 'redis'.

Every write flushes the entire model tag. One User::save() invalidates all cached User queries — different where clauses, pagination counts, all of it. Write-heavy models get near-zero benefit and constant churn. Restrict the trait to lookup tables.

Watch the cache key. Keys derived from serialized query state can collide or blow up with complex bindings (closures, whereHas, Carbon instances, select() differences). Inspect the generated keys in Redis (SCAN app:cacheable:*) when debugging mysterious misses or wrong results.

Stale class shape after deploys. Cached models are serialized; adding/removing attributes, $appends, or changing toArray() can leave older cache entries inconsistent. Bump the config prefix on every deploy, or run the package's flush command (if present) as part of your release script.

Raw query builder bypasses everything. DB::table('countries')->get(), insert(), and raw SQL never touch the trait. Any code path that writes via the query builder must call the flush manually.

Soft deletes and timestamps. Verify that restore() and deleted_at updates actually trigger a flush in your version — test it, don't assume.

Debugging workflow: enable query logging around a single request; count hits vs. statements. Use Telescope's cache panel or Redis MONITOR for a few seconds to see keys touched on write. Log getCacheKey() output for the queries that misbehave.

Extension points worth knowing: the published config (engine, lifetime, prefix), the per-model key helper, and the model event hooks — that's the whole surface area. If you need bypass-on-demand, there's no clean API; go through DB::table() or flush first.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons