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

Infinity Cache Laravel Package

morilog/infinity-cache

Infinity Cache for Laravel makes it easy to cache expensive Eloquent query results and keep them fresh: cached data is automatically invalidated when the underlying models change, so you get the speed of caching without stale reads or manual cache-busting code.

View on GitHub
Deep Wiki
Context7

Getting Started

Install (Laravel 5.1/5.2 era — read the compatibility note below first):

composer require morilog/infinity-cache

There is no package auto-discovery (this predates Laravel 5.5). Register the provider manually in config/app.php:

'providers' => [
    // ...
    Morilog\InfinityCache\InfinityCacheServiceProvider::class,
],

Publish and review the config so you know which cache store and TTL it defaults to:

php artisan vendor:publish --provider="Morilog\InfinityCache\InfinityCacheServiceProvider"

Where to look first: read the package's README.md and its src/ directory before writing any code. The surface area is small — a trait, a service provider, a config file, and a query-builder wrapper — and the README is the only authoritative source for exact method names. Do not assume the API matches what you'd expect from a modern package.

First use case: pick a single hot read path — a homepage sidebar, a category listing, a find() on a detail page — and cache only that. The intended pattern is to opt a model in with the trait and route reads through a cache-aware entry point:

use Morilog\InfinityCache\InfinityCacheTrait;

class Post extends Model
{
    use InfinityCacheTrait;
}

Then measure with and without caching before rolling it out further. This package's value proposition is infinite TTL plus automatic invalidation on model writes — so the first thing you want to prove is that a save()/delete() actually clears the key you just populated.

Implementation Patterns

Cache the read, not the whole app. Treat this as a targeted optimization for specific expensive queries, not a global Eloquent decorator. A workable workflow:

  1. Identify queries that are read-heavy and write-light (categories, settings, published posts, nav menus).
  2. Add the trait to those models only.
  3. Route reads through the package's cache-aware entry point so keys are derived consistently.
  4. Verify invalidation by writing to the model and re-reading.
  5. Add a monitoring step (hit rate, key count) before expanding scope.

Service-layer wrapping. Because the package is old and loosely documented, do not scatter its calls through controllers. Wrap it in your own repository/service so you can swap the implementation later:

class PostRepository
{
    public function publishedForHomepage(int $limit = 10)
    {
        // cache-aware read path provided by the trait
        return Post::cache()->where('status', 'published')
            ->orderByDesc('published_at')
            ->limit($limit)
            ->get();
    }
}

That indirection is the single most valuable pattern here — it means the day you migrate off this package (which you should plan for), you change one class.

Write-path invalidation. The package hooks Eloquent model events. Keep that contract intact by never bypassing the model layer for writes on cached entities:

  • ✅ $post->update([...]), $post->save(), $post->delete()
  • ❌ Post::where(...)->update([...]) — mass updates skip model events in Eloquent generally
  • ❌ DB::table('posts')->update(...) — bypasses everything
  • ❌ raw SQL, imports, or queue workers writing directly

If you legitimately need mass updates, wrap them with an explicit flush:

DB::transaction(function () {
    Post::where('status', 'draft')->update(['status' => 'archived']);
    // explicitly clear this model's cache namespace afterwards
});

Pre-warming. Infinite-TTL caches are cold on deploy and after a flush. Add a small artisan command or a post-deploy step that renders the hot pages (or calls your repository methods once) so the first real user isn't the one paying the query cost.

Grouped invalidation. If the package's store supports cache tags, group related models (e.g. posts, post:42, category:7) so a category rename can invalidate all dependent post listings. If it doesn't support tags on your chosen store, you're stuck with per-key invalidation — design your key strategy accordingly, and prefer coarse keys ("the homepage list") over fine-grained ones so there are fewer things to invalidate correctly.

Combination with eager loading. Cache the final hydrated collection, including relationships you need. Caching the parent query and then lazy-loading relations on each request defeats most of the benefit and risks N+1 inside the cached path.

Testing. Point the test environment at the array store, and flush between tests. Assert both halves of the contract:

public function test_post_cache_invalidates_on_save()
{
    $post = factory(Post::class)->create();
    $this->assertSame('A', app(PostRepository::class)->first($post->id)->title);

    $post->update(['title' => 'B']);
    $this->assertSame('B', app(PostRepository::class)->first($post->id)->title);
}

Gotchas and Tips

Treat this as abandoned software. Last release February 2016, 31 stars, zero dependents. Its composer.json will constrain illuminate/* to the Laravel 5.x line, which means it will not install on Laravel 6+ without --ignore-platform-reqs hacks, and it predates PHP 8 type-safety changes. Before you invest, run composer require in a throwaway app and confirm it resolves at all. If it doesn't, stop here.

Infinite TTL is the whole risk model. There is no natural expiry to save you from a missed invalidation. Every code path that mutates a cached model is now load-bearing. Enumerate them before shipping:

  • model events,
  • mass updates,
  • seeders and data imports,
  • queue jobs,
  • admin panels or third-party tools writing to the same tables,
  • direct DB access by other services.

Cache store must support tags. Tag-based invalidation requires Redis, Memcached, or the array store. The file and database drivers do not support tags and will either error or silently misbehave. Check the package's expected store against your config/cache.php default before anything else.

Bindings and key derivation. Query-derived cache keys are typically built from the SQL plus bindings. Watch for:

  • binding order sensitivity — two logically identical queries with different where() ordering may produce different keys,
  • Carbon/DateTime objects serialized into keys,
  • null vs empty string bindings,
  • pagination — confirm the page number is part of the key, otherwise page 2 serves page 1's results.

Serialization of models. Cached entries hold serialized Eloquent instances. If you later rename a column, change a cast, or remove an attribute, deserializing a stale cached model can produce confusing errors or silently missing data. Flush the cache on every deploy that touches a cached model's schema or casts.

Never cache authenticated or per-user scopes under a shared key. Anything downstream of Auth::id(), tenant IDs, or permission checks must either be excluded or have the user/tenant baked into the key. Getting this wrong is a data-leak bug, not a performance bug.

Unbounded growth. "Infinity" also describes the key space if you cache per-ID lookups without eviction. Monitor your Redis memory. If the package offers per-call TTL overrides, use a finite TTL for high-cardinality keys (per-post detail pages) and reserve infinite TTL for low-cardinality, high-value keys (site settings, nav).

Debugging technique. When something looks stale, don't guess — inspect the store directly:

redis-cli --scan --pattern '*posts*' | head -50

Then write to the model and confirm those keys disappear. If they don't, the write path bypassed Eloquent. Also check whether a saved/deleted listener is being suppressed by a transaction that rolls back, or by an observer registered after the package's.

Extension points. The trait is the natural place to override. If you need custom key generation, tenant scoping, or logging, override the relevant method in your model (or better, in a shared base model) rather than patching the vendor directory. Avoid editing vendor/ — it will be lost on the next composer install.

Migration path — plan it now. For a Laravel project today, the same problem is solved by maintained alternatives: genealabs/laravel-model-caching for model-level caching with automatic invalidation, or plain Cache::remember() / Cache::flexible() (Laravel 11+) inside a repository for query-level caching. Given this package's age and adoption, the pragmatic recommendation is: prototype with it only if you're pinned to Laravel 5.x, and otherwise implement the invalidation pattern yourself in ~50 lines inside a repository class. You'll get the same benefit with a supported dependency and full control over the key strategy.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings