Query caching for Laravel

Overview

Rememberable, Laravel 5 query cache

Total Downloads Latest Stable Version Latest Unstable Version License

Rememberable is an Eloquent trait for Laravel that adds remember() query methods. This makes it super easy to cache your query results for an adjustable amount of time.

// Get a the first user's posts and remember them for a day.
User::first()->remember(now()->addDay())->posts()->get();

// You can also pass the number of seconds if you like (before Laravel 5.8 this will be interpreted as minutes).
User::first()->remember(60 * 60 * 24)->posts()->get();

It works by simply remembering the SQL query that was used and storing the result. If the same query is attempted while the cache is persisted it will be retrieved from the store instead of hitting your database again.

Installation

Install using Composer, just as you would anything else.

composer require watson/rememberable

The easiest way to get started with Eloquent is to create an abstract App\Model which you can extend your application models from. In this base model you can import the rememberable trait which will extend the same caching functionality to any queries you build off your model.


namespace App;

use Watson\Rememberable\Rememberable;
use Illuminate\Database\Eloquent\Model as Eloquent;

abstract class Model extends Eloquent
{
    use Rememberable;
}

Now, just ensure that your application models from this new App\Model instead of Eloquent.


namespace App;

class Post extends Model
{
    //
}

Alternatively, you can simply apply the trait to each and every model you wish to use remember() on.

Usage

Using the remember method is super simple. Just pass the number of seconds you want to store the result of that query in the cache for, and whenever the same query is called within that time frame the result will be pulled from the cache, rather than from the database again.

// Remember the number of users for an hour.
$users = User::remember(60 * 60)->count();

Cache tags

If you want to tag certain queries you can add cacheTags('tag_name') to your query. Please notice that cache tags are not supported by all cache drivers.

// Remember the number of users for an hour and tag it with 'user_queries'
User::remember(60 * 60)->cacheTags('user_queries')->count();

Cache prefix

If you want a unique prefix added to the cache key for each of your queries (say, if your cache doesn't support tagging), you can add prefix('prefix') to your query.

// Remember the number of users for an hour and prefix the key with 'users'
User::remember(60 * 60)->prefix('users')->count();

Alternatively, you can add the $rememberCachePrefix property to your model to always use that cache prefix.

Cache driver

If you want to use a custom cache driver (defined in config/cache.php) you can add cacheDriver('cacheDriver') to your query.

// Remember the number of users for an hour using redis as cache driver
User::remember(60 * 60)->cacheDriver('redis')->count();

Alternatively, you can add the $rememberCacheDriver property to your model to always use that cache driver.

Model wide cache tag

You can set a cache tag for all queries of a model by setting the $rememberCacheTag property with an unique string that should be used to tag the queries.

Relationships

Validating works by caching queries on a query-by-query basis. This means that when you perform eager-loading those additional queries will not be cached as well unless explicitly specified. You can do that by using a callback with your eager-loads.

", "1") ->with(['posts' => function ($q) { $q->remember(60 * 60); }]) ->remember(60 * 60) ->take(5) ->get(); ">
$users = User::where("id", ">", "1")
    ->with(['posts' => function ($q) { $q->remember(60 * 60); }])
    ->remember(60 * 60)
    ->take(5)
    ->get();

Always enable

You can opt-in to cache all queries of a model by setting the $rememberFor property with the number of seconds you want to cache results for. Use this feature with caution as it could lead to unexpected behaviour and stale data in your app if you're not familiar with how it works.

Cache flushing

Based on the architecture of the package it's not possible to delete the cache for a single query. But if you tagged any queries using cache tags, you are able to flush the cache for the tag:

User::flushCache('user_queries');

If you used the $rememberCacheTag property you can use the method without a parameter and the caches for the tag set by $rememberCacheTag are flushed:

User::flushCache();

Skipping cache

If you need to disable cache for a particular query, you can use the dontRemember method:

User::latest()->dontRemember()->get();
Comments
  • Doesn't work on L5.1

    Doesn't work on L5.1

    Using for instance:

    $users = User::where("id", ">", "1")->remember(10)->take(5)->get();

    Gives the expected result (no errors). But reloading the page, I see that mysql simply fires the 5 queries again and again....

    opened by digixweb 16
  • Remove generated cache by rememberable

    Remove generated cache by rememberable

    Sometimes I want to force a refresh of the cache that has been set by rememberable. Something like: Cache::forget('key'); However I don't know the key and if this way is possible at all?

    opened by digixweb 10
  • Call to undefined method: remember() (individual model)

    Call to undefined method: remember() (individual model)

    I am using the Repository pattern and want to test this trait out on just one problematic model for starters.

    I have HotelSearchRepository.php which includes chainable methods. The top of the file looks like this:

    namespace App\Repositories\Eloquent;
    
    use Watson\Rememberable\Rememberable;
    use App\Repositories\Contracts\EventLocationRepositoryInterface;
    use App\Repositories\Contracts\HotelSearchRepositoryInterface;
    
    class HotelSearchRepository extends Repository implements HotelSearchRepositoryInterface
    {
        use Rememberable;
    ...
    

    I am chaining methods for my search functionality like so:

        public function search($terms = [])
        {
            $this->terms = $terms;
    
            return $this
                ->withMinSleepingRooms($this->term('min_sleeping_rooms'))
                ->withMaxSleepingRooms($this->term('max_sleeping_rooms'))
                ->withMinMeetingRooms($this->term('min_meeting_rooms'))
                ->withMinLargestMeetingRoomSqFt($this->term('min_largest_meeting_room_sq_ft'))
                ->withStarsMatching($this->term('stars'))
                ->withBrands($this->term('brands'))
                ->nearLocations($this->term('locations'), $this->term('radius'), $this->term('radius_units'))
                ->withRelatedModels()
                ->complete();
        }
    

    So the method I'm including the remember trait on is here:

        private function withRelatedModels()
        {
            $this->model = $this->model->with(['propertyType' => function ($q) {
                return $q->remember(10);
            }]);
    
            return $this;
        }
    

    I am only attempting to cache the propertyType query at this point. However, I get the exception: Call to undefined method Illuminate\Database\Query\Builder::remember().

    I have tried this as well, to no avail.

        private function withRelatedModels()
        {
            $this->model = $this->model->with(['propertyType' => function ($q) {
                return $q->remember(10);
            }])->remember(10);
    
            return $this;
        }
    

    What am I doing wrong here?

    opened by nateritter 8
  • Laravel 7 support

    Laravel 7 support

    Hi,

    Is there a reason why Laravel 7 is no longer supported? Shouldn't the requirements be similar to "^7.0|^8.0"? Looks like this commit attempted to do it (c897403148cd011f2eec494e7914137efbde1ddc) but the syntax was wrong. This commit (bb5b31537b05f135c7afd7fad3d4a8a2cc0c1886) gets rid of Laravel 7 support

    opened by benjamindoe 7
  • Builder requires $minutes to be int

    Builder requires $minutes to be int

    https://github.com/dwightwatson/rememberable/blob/master/src/Query/Builder.php#L81

    In that line, the Builder checks if $minutes < 0 This is not an error BUT:

    According to the Laravel documentation, the remember() method requires 3 types for the first argument:

    • int
    • float
    • \DateTime

    (See https://laravel.com/api/5.4/Illuminate/Cache/Repository.html#method_remember)

    Is it possible to change this line so it checks for a DateTime instance?

    What I want to achieve is the following:

    Model::remember(Carbon::now()->addSeconds(30))->get();
    

    This is just an example. Basically, in some cases it would be more practicable to have the possibilty to enter the expiration date as a DateTime, not in minutes (for example, if I want to use seconds instead or maybe one month as a DateTime instead of 43200 (minutes)).

    opened by Ponjimon 6
  • Way to disable caching (e.g. in dev environment)?

    Way to disable caching (e.g. in dev environment)?

    Just asking, is there a way to disable all caching from just one point? Just came across a few issues that would've been solved had I remembered I was caching things.

    opened by ghost 5
  • Switch to SHA256 instead of MD5

    Switch to SHA256 instead of MD5

    There are far better alternatives to md5, which don't have surprisingly feasible collisions.

    This will cause people who update to have to re-fetch their query data, and their existing md5'd data will go stale and may not be removed if it was remembered forever.

    Except for that, this is reasonably backwards compatible (as in it will only break if a user is relying on the query cache entirely because all tables/data have been removed, and so on).

    opened by ameliaikeda 5
  • [Proposal] Add `$rememberFor` property check, to enable always caching a model

    [Proposal] Add `$rememberFor` property check, to enable always caching a model

    Love this package!

    This PR adds a check for a $rememberFor property on the model, and if it is set, automatically adds a call to remember($this->rememberFor) to the Builder.

    This way, one can set the $rememberFor property on the model, and all queries involving a SELECT for that model will back cached.

    Cheers!

    opened by hipsterjazzbo 5
  • Multiple cache tags?

    Multiple cache tags?

    Is there a way to set multiple cache tags for a query? (Sorry, first time doing something like this.) If not, is there a way to flush tags using regular expressions? (e.g. flush all tags with "user:1") Thank you for this BTW! Was looking for remember() and was not disappointed.

    opened by ghost 4
  • Add a prefix to the cache key.

    Add a prefix to the cache key.

    This means that people on, say, Redis can drop all keys that match rememberable:*, and people with taggable stores can still identify rememberable cache entries.

    opened by ameliaikeda 4
  • Proposal: New Major Version

    Proposal: New Major Version

    Sticking this one in an issue so it's a little easier to keep track of.

    There's a few things that would be really nice for this project that would require a new major version, and one of my PRs requires that anyway, so I thought I'd bring up discussion here.

    • [x] Switch from md5 to sha256 for cache keys (#27)
    • [x] Use a (configurable) cache prefix (#28)
    • [ ] Add tests for the Query Builder
    • [ ] Configure travis-ci
    opened by ameliaikeda 4
  • Redis memory issue

    Redis memory issue

    Hello, We have a problem where Redis key created by this package is using alot of memory. It's named like this : br-local:5f58eab33aae5665049267:standard_ref and contains values like this: redis Even when using flushCache() method, these records are not cleared... Is this normal behavior?

    opened by WolFZonE 3
  • flush morphToMany not working

    flush morphToMany not working

    Project.php

    class Project extends Model
    {	
        use Rememberable;
    
        public $rememberCacheTag = 'project_queries';
        public $rememberFor = 60*60*24;
    	
        public function users()
        {
            return $this->morphToMany(User::class, 'model','model_has_users');
        }
    

    User.php

    class User extends Authenticatable
        {
            use Rememberable;
        
            public $rememberCacheTag = 'user_queries';
            public $rememberFor = 60*60*24;
            
        public function projects()
        {
            return $this->hasMany(Project::class);
        }
    

    Now this works:

    Cache::flush();
    

    And this does not:

    Project::flushCache('project_queries');
    

    Project::find(1)->name (refreshed) Project::find(1)->users (not refreshed)

    help!?

    opened by hen3b182 3
  • Unable to flush withCount()

    Unable to flush withCount()

    If i query a realtion with withCount() the counting is never been refreshed, even after flushing the cache. The counting only works if I add dontRemember() to the query...

    opened by jetwes 2
  • Nested Eager Loading - Not Supported

    Nested Eager Loading - Not Supported

    I tried to use the cache with nested eager loading, but didn't cache that part of the query:

    $query->with(['feedback.profile' => function ($query) {
    	//Cache
    	$cacheTime = 60;
    	$query->remember($cacheTime);
    }]);
    

    It does however work with a simple eager loading:

    $query->with(['feedback' => function ($query) {
    	//Cache
    	$cacheTime = 60;
    	$query->remember($cacheTime);
    }]);
    
    opened by NeoMarine 1
  • `paginate()` doeesn't cache the main record

    `paginate()` doeesn't cache the main record

    The setup is phpunit & array cache driver. And I've tapped in to the cache using:

    $cache = \Cache::store();
    

    The line below:

    $paginator = SomeModel::paginate($perPage)->load('relation');
    

    After that, I've found that there are two entries in the cache: the aggregate & relation. The main model (record) is missed.

    While traced a bit, I was led to the line, which traced back to query builder (not eloquent builder) getCountForPagination()

    public function getCountForPagination($columns = ['*'])
    {
        $this->backupFieldsForCount();
    
        $this->aggregate = ['function' => 'count', 'columns' => $this->clearSelectAliases($columns)];
    
        $results = $this->get();    // <<<<<< THIS LINE
    
        $this->aggregate = null;
    
        $this->restoreFieldsForCount();
    
        if (isset($this->groups)) {
            return count($results);
        }
    
        return isset($results[0]) ? (int) array_change_key_case((array) $results[0])['aggregate'] : 0;
    }
    
    

    Then the subsequent call to forPage()->get() will not hit the cache. Because the $cacheMinutes property was set to null in the closure returned by getCacheCallback(). Which ends up failing the non-null test in get().

    public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null)
    {
        $page = $page ?: Paginator::resolveCurrentPage($pageName);
    
        $total = $this->getCountForPagination($columns);
    
        $results = $this->forPage($page, $perPage)->get($columns);   // <<<<<<< THIS WON'T HIT CACHE
    
        return new LengthAwarePaginator($results, $total, $perPage, $page, [
            'path' => Paginator::resolveCurrentPath(),
            'pageName' => $pageName,
        ]);
    }
    
    
    opened by eidng8 2
Owner
Dwight Watson
#gsd
Dwight Watson
Query caching for Laravel

Query caching for Laravel

Dwight Watson 1k Dec 30, 2022
A thin PSR-6 cache wrapper with a generic interface to various caching backends emphasising cache tagging and indexing.

Apix Cache, cache-tagging for PHP Apix Cache is a generic and thin cache wrapper with a PSR-6 interface to various caching backends and emphasising ca

Apix 111 Nov 26, 2022
Yii Caching Library - Redis Handler

Yii Caching Library - Redis Handler This package provides the Redis handler and implements PSR-16 cache. Requirements PHP 7.4 or higher. Installation

Yii Software 4 Oct 9, 2022
Simple Yet Powerful PHP Caching Class

The PHP high-performance object caching system ever. phpFastCache is a high-performance, distributed object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load. phpFastCache dropped the database load to almost nothing, yielding faster page load times for users, better resource utilization. It is simple yet powerful

Khoa Bui 28 Aug 19, 2022
Stash - A PHP Caching Library

Stash - A PHP Caching Library Stash makes it easy to speed up your code by caching the results of expensive functions or code. Certain actions, like d

Tedious Developments 943 Dec 15, 2022
Caching extension for the Intervention Image Class

Intervention Image Cache extends the Intervention Image Class package to be capable of image caching functionality.

null 616 Dec 30, 2022
Stash makes it easy to speed up your code by caching the results of expensive functions or code

Stash - A PHP Caching Library Stash makes it easy to speed up your code by caching the results of expensive functions or code. Certain actions, like d

Tedious Developments 943 Dec 15, 2022
DataLoaderPhp is a generic utility to be used as part of your application's data fetching layer to provide a simplified and consistent API over various remote data sources such as databases or web services via batching and caching.

DataLoaderPHP is a generic utility to be used as part of your application's data fetching layer to provide a simplified and consistent API over various remote data sources such as databases or web services via batching and caching.

Webedia - Overblog 185 Nov 3, 2022
The next-generation caching layer for PHP

The next-generation caching layer for PHP

CacheWerk 115 Dec 25, 2022
Symfony Bundle for the Stash Caching Library

TedivmStashBundle The TedivmStashBundle integrates the Stash caching library into Symfony, providing a powerful abstraction for a range of caching eng

Tedious Developments 86 Aug 9, 2022
Remember your query results using only one method. Yes, only one.

Cache Query Remember your query results using only one method. Yes, only one. Articles::latest('published_at')->cache()->take(10)->get(); Keep this pa

Laragear 182 Dec 28, 2022
Make laravel/passport client cacheable.

Laravel Passport Cache Client Make laravel/passport client cacheable. Installing $ composer require overtrue/laravel-passport-cache-client -vvv Usage

安正超 16 Aug 13, 2022
LaraCache is an ORM based package for Laravel to create, update and manage cache items based on model queries

LaraCache Using this package, you can cache your heavy and most used queries. All you have to do is to define the CacheEntity objects in the model and

Mostafa Zeinivand 202 Dec 19, 2022
Simple artisan command to debug your redis cache. Requires PHP 8.1 & Laravel 9

?? php artisan cache:debug Simple artisan command to debug your redis cache ?? Installation You can install the package via composer: composer require

Juan Pablo Barreto 19 Sep 18, 2022
The Missing check on Laravel Request Unicity.

Motivation This laravel package will allow you to execute a code once in the current request based on the key provided. Installation composer require

Inani El Houssain 8 Oct 27, 2022
Caching implementation with a variety of storage options, as well as codified caching strategies for callbacks, classes, and output

laminas-cache Laminas\Cache provides a general cache system for PHP. The Laminas\Cache component is able to cache different patterns (class, object, o

Laminas Project 69 Jan 7, 2023
This Magento extension provides a Real Full Page Caching for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

This Magento extension provides a Real Full Page Caching (FPC) for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

Hugues Alary 95 Feb 11, 2022
Query caching for Laravel

Rememberable, Laravel 5 query cache Rememberable is an Eloquent trait for Laravel that adds remember() query methods. This makes it super easy to cach

Dwight Watson 1k Dec 30, 2022
Query caching for Laravel

Query caching for Laravel

Dwight Watson 1k Dec 30, 2022
SphinxQL Query Builder generates SphinxQL, a SQL dialect, which is used to query the Sphinx search engine. (Composer Package)

Query Builder for SphinxQL About This is a SphinxQL Query Builder used to work with SphinxQL, a SQL dialect used with the Sphinx search engine and it'

FoolCode 318 Oct 21, 2022