mikebronner/laravel-model-caching
Automatically caches Eloquent model and relationship queries, then invalidates them when data changes—no manual cache keys. Add a trait to your models to cut database load on read-heavy pages with self-invalidating, Laravel-native caching.
13.2.0 requires PHP 8.3 or later (#645). On PHP 8.2, Composer stays on 13.1.11.
$isCachable is typed boolThe trait now declares protected bool $isCachable (#647). A model or builder that declares $isCachable again without the bool type fails with a fatal error when the class loads.
Fix: declare it as protected bool $isCachable.
newBaseQueryBuilder()13.1.8 added newBaseQueryBuilder() to the Cachable trait. It collided with other traits that define the same method, such as CTE support, so it is gone (#640, #651). A trait rule that names Cachable::newBaseQueryBuilder now fails when the class loads:
Cachable::newBaseQueryBuilder as ...Cachable::newBaseQueryBuilder insteadof ...Fix: delete that rule. Other::newBaseQueryBuilder insteadof Cachable still works.
modelCache:clear no longer empties the whole cache storeOn Redis, the command used to wipe the app's entire cache store, or the whole Redis database when the prefix was empty (#645). It now deletes only the package's own entries.
Fix: if a script relied on it to clear everything, add php artisan cache:clear.
These queries miss the cache once after upgrading, then rebuild:
where(), orWhere() and whereNot() queries on models with global scopes (#647).morphTo eager loads onto models with global scopes (#647).withoutGlobalScopesExcept() calls that keep every scope (#647).where clauses (#647).withPivot(), withTimestamps(), a custom as(), using(), with(), or a related model with $with (#647).fromSub(), union and beforeQuery() bindings that are Stringable objects with non-public state (#647).with('stores') (#641, #653).with() (#647), or that forward a macro or custom builder method (#656).null, false and "" used to share a key, as did 1 and "1".$cachePrefix (#651). A cool-down window that is open at upgrade ends early once.These used to be cached under a key that another query could share, so they could return the wrong rows. They now always read from the database:
where() or having() value that cannot be keyed reliably, such as an object serialize() rejects or a value that holds a resource (#647).afterQuery() callback (#647).Cachable (#647).__toString(), or an array json_encode cannot encode (#656).php artisan modelCache:clear after you deploy. Some changed queries keep their old key text, so until the next write to that table they could read an entry the old version wrote.$isCachable and for trait rules that name newBaseQueryBuilder (items 2 and 3).Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.11...13.2.0
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.10...13.2.0
ofMany eager-loaded relations return null on later paginated pages by @mikebronner in https://github.com/mike-bronner/laravel-model-caching/pull/606Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.6...13.1.7
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.5...13.1.6
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.4...13.1.5
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.3...13.1.4
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.2...13.1.3
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.1...13.1.2
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.1.0...13.1.1
Full Changelog: https://github.com/mike-bronner/laravel-model-caching/compare/13.0.6...13.1.0
mikebronner private account to mike-bronner org account.Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/13.0.3...13.0.4
fix: 🐛 Fixed deep clone of builder state and add integration tests. Thanks @mevisoft!
Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/13.0.2...13.0.3
Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/13.0.1...13.0.2
Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/13.0.0...13.0.1
This release adds Laravel 13 support, introduces several powerful new features — including a ModelCache Facade, graceful fallback when the cache backend is down, and smarter cache invalidation — and fixes a batch of edge-case bugs.
composer.json:
composer require mikebronner/laravel-model-caching
.env:
MODEL_CACHE_FALLBACK_TO_DB=true
fallback-to-database option:
php artisan modelCache:publish --config
Laravel 10 dropped — Minimum Laravel version is now 11. If you are still on Laravel 10, stay on v12.x.
PHP 8.1 dropped — Minimum PHP version is now 8.2. If you are still on PHP 8.1, stay on v12.x.
Existing applications on Laravel 11 or 12 with PHP 8.2+ should be able to upgrade without any code changes.
illuminate/* dependencies to accept ^13.0. (#557)ModelCache::invalidate() Facade for programmatic cache flushing without Artisan commands. Accepts a single model class or an array. (#571)MODEL_CACHE_FALLBACK_TO_DB=true, the package logs a warning and falls back to direct database queries if the cache backend (e.g. Redis) is unavailable, instead of throwing an exception. (#574)join(), leftJoin(), etc. now generate cache tags for the joined tables, so writes to joined models correctly invalidate the cache. (#577)delete() or forceDelete() actually removes records (affected rows > 0), avoiding unnecessary invalidation on no-op deletes. (#578)newEloquentBuilder() method now work correctly with the Cachable trait. (#528)attach/detach on morphedByMany relationships now correctly flushes the cache. (#575)lockForUpdate() or sharedLock() now automatically bypass the cache, since locked queries should always hit the database. (#573)belongsToMany()->sync() memory exhaustion — Fixed a memory leak when syncing large pivot datasets. (#569)RowValues where type breaking compatibility with Laravel's cursor pagination. (#562)$fillable interference — The Cachable trait no longer interferes with models that modify $fillable dynamically (e.g. in __construct()). (#564)BelongsToMany relationships using custom pivot models (->using()) now correctly invalidate the cache on attach/detach/sync. (#566)morphTo relationships in eager-load chains. (#579)retrieved event on cache hit — The Eloquent retrieved event now fires correctly when results are served from cache, matching the behavior of uncached queries. (#563)EloquentBuilder import — Added a missing use import in CachedBuilder.php. (#558)SECURITY.md with vulnerability reporting instructions.reorder() caching, delete/forceDelete flush behavior, custom builders, dynamic fillable, lock queries, cursor pagination, MorphTo eager loads, multi-domain pagination, and pivot model observers.Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/12.0.4...13.0.0
Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/12.0.3...12.0.4
Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/12.0.3...12.1.0-RC1
Full Changelog: https://github.com/mikebronner/laravel-model-caching/compare/12.0.2...12.0.3
genealabs/laravel-model-caching to mikebronner/laravel-model-caching, as this is a good time to make a breaking change, so that it properly reflects its new home.query attribute in strict mode. Thanks @daika7ana!whereHaving clauses not being parsed correctly. Thanks @charlie-waddell!JsonContainsKey query type. Thanks @jamesRUS52!null values. Thanks @peter-brennan!attach() and detach() issues after upgrading to Laravel 10. Thanks @jason-klein$total parameter. Thanks @joshuadwire!first if it is an Expression object. Thanks @vheins!How can I help you explore Laravel packages today?