PHPackages                             miradnan/laravel-model-caching - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. miradnan/laravel-model-caching

ActiveLibrary[Database &amp; ORM](/categories/database)

miradnan/laravel-model-caching
==============================

Adding cache for Laravel Eloquent queries

2.1(6y ago)815.9k↓18.8%2MITPHPPHP &gt;=7.3

Since Apr 14Pushed 4y ago2 watchersCompare

[ Source](https://github.com/miradnan/laravel-model-caching)[ Packagist](https://packagist.org/packages/miradnan/laravel-model-caching)[ Docs](https://github.com/miradnan/laravel-model-caching)[ RSS](/packages/miradnan-laravel-model-caching/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (5)Versions (2)Used By (0)

Laravel Eloquent Query &amp; Table Cache
========================================

[](#laravel-eloquent-query--table-cache)

Laravel Query &amp; Table Cache. This package helps adding caching to queries and tables at model level. It directly runs at Eloquent level, making use of cache before retrieving the data from the DB.

This package adds caching support for **all** query methods.

```
$ composer require miradnan/laravel-model-caching
```

Each model that will accept query-by-query caching will have to use the `miradnan\QueryCache\Traits\QueryCacheable` trait.

```
use miradnan\QueryCache\Traits\QueryCacheable;

class Post extends Model
{
    use QueryCacheable;

    ...
}
```

```
use miradnan\QueryCache\Traits\TableCacheable;

class Country extends Model
{
    use TableCacheable;

    ...
}
```

Showcase
--------

[](#showcase)

Query Cache has the ability to track the SQL used and use it as a key in the cache storage, making the caching query-by-query a breeze.

```
use miradnan\QueryCache\Traits\QueryCacheable;

class Article extends Model
{
    use QueryCacheable;

    public $cacheFor = 3600;
    ...
}

// SELECT * FROM articles ORDER BY created_at DESC LIMIT 1;
$latestArticle = Article::latest()->first();

// SELECT * FROM articles WHERE published = 1;
$publishedArticles = Article::wherePublished(true)->get();
```

In the above example, both queries have different keys in the cache storage, thus it doesn't matter what query we handle. By default, caching is disabled unless specifying a value for `$cacheFor`. As long as `$cacheFor` is existent and is greater than `0`, all queries will be cached.

It is also possible to enable caching for specific queries. This is the recommended way because it is easier to manage each query.

```
$postsCount = Post::cacheFor(60 * 60)->count();

// Using a DateTime instance like Carbon works perfectly fine!
$postsCount = Post::cacheFor(now()->addDays(1))->count();
```

Cache Tags &amp; Cache Invalidation
-----------------------------------

[](#cache-tags--cache-invalidation)

Some caching stores accept tags. This is really useful if you plan on tagging your cached queries and invalidate only some of the queries when needed.

```
$shelfOneBooks = Book::whereShelf(1)->cacheFor(60)->cacheTags(['shelf:1'])->get();
$shelfTwoBooks = Book::whereShelf(2)->cacheFor(60)->cacheTags(['shelf:2'])->get();

// After flushing the cache for shelf:1, the query of$shelfTwoBooks will still hit the cache if re-called again.
Book::flushQueryCache(['shelf:1']);

// Flushing also works for both tags, invalidating them both, not just the one tagged with shelf:1
Book::flushQueryCache(['shelf:1', 'shelf:2']);
```

Be careful tho - specifying cache tags does not change the behaviour of key storage. For example, the following two queries, altough the use the same tag, they have different keys stored in the caching database.

```
$alice = Kid::whereName('Alice')->cacheFor(60)->cacheTags(['kids'])->first();
$bob = Kid::whereName('Bob')->cacheFor(60)->cacheTags(['kids'])->first();
```

Relationship Caching
--------------------

[](#relationship-caching)

Relationships are just another queries. They can be intercepted and modified before the database is hit with the query. The following example needs the `Order` model (or the model associated with the `orders` relationship) to include the `QueryCacheable` trait.

```
$user = User::with(['orders' => function ($query) {
    return $query->cacheFor(60 * 60)->cacheTags(['my:orders']);
}])->get();

// This comes from the cache if existed.
$orders = $user->orders;
```

Cache Keys
----------

[](#cache-keys)

The package automatically generate the keys needed to store the data in the cache store. However, prefixing them might be useful if the cache store is used by other applications and/or models and you want to manage the keys better to avoid collisions.

```
$bob = Kid::whereName('Bob')->cacheFor(60)->cachePrefix('kids_')->first();
```

If no prefix is specified, the string `leqc` is going to be used.

Cache Drivers
-------------

[](#cache-drivers)

By default, the trait uses the default cache driver. If you want to **force** a specific one, you can do so by calling `cacheDriver()`:

```
$bob = Kid::whereName('Bob')->cacheFor(60)->cacheDriver('dynamodb')->first();
```

Disable caching
---------------

[](#disable-caching)

If you enabled caching (either by model variable or by the `cacheFor` scope), you can also opt to disable it mid-builder.

```
$uncachedBooks = Book::dontCache()->get();
$uncachedBooks = Book::doNotCache()->get(); // same thing
```

Equivalent Methods and Variables
--------------------------------

[](#equivalent-methods-and-variables)

You can use the methods provided in this documentation query-by-query, or you can set defaults for each one in the model; using the methods query-by-query will overwrite the defaults. While settings defaults is not mandatory (excepting for `$cacheFor` that will enable caching on **all** queries), it can be useful to avoid using the chained methods on each query.

```
class Book extends Model
{
    public $cacheFor = 3600; // equivalent of ->cacheFor(3600)

    public $cacheTags = ['books']; // equivalent of ->cacheTags(['books'])

    public $cachePrefix = 'books_' // equivalent of ->cachePrefix('books_');

    public $cacheDriver = 'dynamodb'; // equivalent of ->cacheDriver('dynamodb');
}
```

Implement the caching method to your own Builder class
------------------------------------------------------

[](#implement-the-caching-method-to-your-own-builder-class)

Since this package modifies the `newBaseQueryBuilder()` in the model, having multiple traits that modify this function will lead to an overlap.

This can happen in case you are creating your own Builder class for another database drivers or simply to ease out your app query builder for more flexibility.

To solve this, all you have to do is to add the `\miradnan\QueryCache\Traits\QueryCacheModule` trait and the `\miradnan\QueryCache\Contracts\QueryCacheModuleInterface` interface to your `Builder` class. Make sure that the model will no longer use the original `QueryCacheable` trait.

```
use miradnan\QueryCache\Traits\QueryCacheModule;
use Illuminate\Database\Query\Builder as BaseBuilder; // the base laravel builder
use miradnan\QueryCache\Contracts\QueryCacheModuleInterface;

// MyCustomBuilder.php
class MyCustomBuilder implements QueryCacheModuleInterface
{
    use QueryCacheModule;

    // the rest of the logic here.
}

// MyBuilderTrait.php
trait MyBuilderTrait
{
    protected function newBaseQueryBuilder()
    {
        return new MyCustomBuilder(
            //
        );
    }
}

// app/CustomModel.php
class CustomModel extends Model
{
    use MyBuilderTrait;
}

CustomModel::cacheFor(30)->customGetMethod();
```

Generating your own key
-----------------------

[](#generating-your-own-key)

This is how the default key generation function looks like:

```
public function generatePlainCacheKey(string $method = 'get', $id = null, $appends = null): string
{
    $name = $this->connection->getName();

    // Count has no Sql, that's why it can't be used ->toSql()
    if ($method === 'count') {
        return $name.$method.$id.serialize($this->getBindings()).$appends;
    }

    return $name.$method.$id.$this->toSql().serialize($this->getBindings()).$appends;
}
```

In some cases, like implementing your own Builder for MongoDB for example, you might not want to use the `toSql()` and use your own method of generating per-sql key. You can do so by overwriting the `MyCustomBuilder` class `generatePlainCacheKey()` with your own one.

It is, however, highly recommended to use the most of the variables provided by the function to avoid cache overlapping issues.

```
class MyCustomBuilder implements QueryCacheModuleInterface
{
    use QueryCacheModule;

    public function generatePlainCacheKey(string $method = 'get', $id = null, $appends = null): string
    {
        $name = $this->connection->getName();

        // Using ->myCustomSqlString() instead of ->toSql()
        return $name.$method.$id.$this->myCustomSqlString().serialize($this->getBindings()).$appends;
    }
}
```

Implementing cache for other functions than get()
-------------------------------------------------

[](#implementing-cache-for-other-functions-than-get)

Since all of the Laravel Eloquent functions are based on it, the builder that comes with this package replaces only the `get()` one:

```
class Builder
{
    public function get($columns = ['*'])
    {
        if (! $this->shouldAvoidCache()) {
            return $this->getFromQueryCache('get', $columns);
        }

        return parent::get($columns);
    }
}
```

In case that you want to cache your own methods from your custom builder or, for instance, your `count()` method doesn't rely on `get()`, you can replace it using this syntax:

```
class MyCustomBuilder
{
    public function count()
    {
        if (! $this->shouldAvoidCache()) {
            return $this->getFromQueryCache('count');
        }

        return parent::count();
    }
}
```

In fact, you can also replace any eloquent method within your builder if you use `$this->shouldAvoidCache()` check and retrieve the cached data using `getFromQueryCache()` method, passing the method name as string, and, optionally, an array of columns that defaults to `['*']`.

Notice that the `getFromQueryCache()` method accepts a method name and a `$columns` parameter. If your method doesn't implement the `$columns`, don't pass it.

Note that some functions like `getQueryCacheCallback()` may come with an `$id` parameter. The default behaviour of the package doesn't use it, since the query builder uses `->get()` by default that accepts only columns.

However, if your builder replaces functions like `find()`, `$id` is needed and you will also have to replace the `getQueryCacheCallback()` like so:

```
class MyCustomBuilder
{
    public function getQueryCacheCallback(string $method = 'get', $columns = ['*'], $id = null)
    {
        return function () use ($method, $columns, $id) {
            $this->avoidCache = true;

            // the function for find() caching
            // accepts different params
            if ($method === 'find') {
                return $this->find($id, $columns);
            }

            return $this->{$method}($columns);
        };
    }

    public function find($id, $columns = ['*'])
    {
        // implementing the same logic
        if (! $this->shouldAvoidCache()) {
            return $this->getFromQueryCache('find', $columns, $id);
        }

        return parent::find($id, $columns);
    }
}
```

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity33

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

2226d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/942e30897e453d260236b53bb7d75225ee9b0864982ddf717201506d69dd0ea6?d=identicon)[miradnan](/maintainers/miradnan)

---

Top Contributors

[![miradnan](https://avatars.githubusercontent.com/u/397415?v=4)](https://github.com/miradnan "miradnan (1 commits)")

---

Tags

laravelsqleloquentcachingqueryremembermodel caching

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/miradnan-laravel-model-caching/health.svg)

```
[![Health](https://phpackages.com/badges/miradnan-laravel-model-caching/health.svg)](https://phpackages.com/packages/miradnan-laravel-model-caching)
```

###  Alternatives

[rennokki/laravel-eloquent-query-cache

Adding cache on your Laravel Eloquent queries' results is now a breeze.

1.1k4.0M14](/packages/rennokki-laravel-eloquent-query-cache)[watson/rememberable

Query caching for Laravel

1.1k5.2M13](/packages/watson-rememberable)[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.2M13](/packages/reedware-laravel-relation-joins)[mehdi-fathi/eloquent-filter

Eloquent Filter adds custom filters automatically to your Eloquent Models in Laravel.It's easy to use and fully dynamic, just with sending the Query Strings to it.

450191.6k1](/packages/mehdi-fathi-eloquent-filter)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
