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.

<?php
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.

<?php
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.

$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
Caching extension for the Intervention Image Class

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

null 616 Dec 30, 2022
A simple HTML minifier for Laravel 5, 6 & 7.

Laravel HTMLMin Laravel HTMLMin is currently maintained by Raza Mehdi, and is a simple HTML minifier for Laravel. It utilises Mr Clay's Minify package

null 1k Jan 4, 2023
A minimal package to help you make your laravel application cleaner and faster.

Laravel Widgetize ?? ?? "cleaner code" ➕ "easy caching" ?? ?? Built with ❤️ for every smart laravel developer ?? Introduction What is a widget object

Iman 883 Dec 28, 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
Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes and constraints by adding them as a subquery.

Laravel Eloquent Scope as Select Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes an

Protone Media 75 Dec 7, 2022
MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way

Mysql Optimizer mysql optimizer also known as MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query

null 2 Nov 20, 2021
MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way. ( WEBSITE VERSION )

Mysql Optimizer mysql optimizer also known as MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query

null 3 Feb 14, 2022
Facebook Query Builder: A query builder for nested requests in the Facebook Graph API

A query builder that makes it easy to create complex & efficient nested requests to Facebook's Graph API to get lots of specific data back with one request.

Sammy Kaye Powers 92 Dec 18, 2022
Speed up a Laravel app by caching the entire response

Speed up an app by caching the entire response This Laravel package can cache an entire response. By default it will cache all successful get-requests

Spatie 2.1k Jan 4, 2023
Stash view is a composer package for Laravel which caches views using Russian Doll Caching methodology.

Stash View Stash view is a composer package for Laravel which caches views using Russian Doll Caching methodology. What is Russian Doll Caching ? It i

Bhushan Gaikwad 18 Nov 20, 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
Michael Pratt 307 Dec 23, 2022
Caching extension for the Intervention Image Class

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

null 616 Dec 30, 2022
Libraries and scripts for crawling the TYPO3 page tree. Used for re-caching, re-indexing, publishing applications etc.

Libraries and scripts for crawling the TYPO3 page tree. Used for re-caching, re-indexing, publishing applications etc.

AOE 0 Sep 14, 2021
An account management Panel based on Laravel7 framework. Include multiple payment, account management, system caching, admin notification, products models, and more.

ProxyPanel 简体中文 Support but not limited to: Shadowsocks,ShadowsocksR,ShadowsocksRR,V2Ray,Trojan,VNET Demo Demo will always on dev/latest code, rather

null 17 Sep 3, 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