Remember your query results using only one method. Yes, only one.

Overview

Cache Query

Latest Version on Packagist Latest stable test run Codecov coverage Maintainability Sonarcloud Status Laravel Octane Compatibility

Remember your query results using only one method. Yes, only one.

Articles::latest('published_at')->cache()->take(10)->get();

Keep this package free

Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can spread the word!

Requirements

  • PHP 8.0
  • Laravel 9.x

Installation

You can install the package via composer:

composer require laragear/cache-query

Usage

Just use the cache() method to remember the results of a query for a default of 60 seconds.

use Illuminate\Support\Facades\DB;
use App\Models\Article;

DB::table('articles')->latest('published_at')->take(10)->cache()->get();

Article::latest('published_at')->take(10)->cache()->get();

The next time you call the same query, the result will be retrieved from the cache instead of running the SELECT SQL statement in the database, even if the results are empty, null or false.

It's eager load aware. This means that it will cache an eager loaded relation automatically.

use App\Models\User;

User::where('is_author')->with('posts')->cache()->paginate();

Time-to-live

By default, results of a query are cached by 60 seconds, which is mostly enough when your application is getting hammered with the same query results.

You're free to use any number of seconds from now, or just a Carbon instance.

use Illuminate\Support\Facades\DB;
use App\Models\Article;

DB::table('articles')->latest('published_at')->take(10)->cache(120)->get();

Article::latest('published_at')->take(10)->cache(now()->addHour())->get();

You can also use null to set the query results forever.

use App\Models\Article;

Article::latest('published_at')->take(10)->cache(null)->get();

Sometimes you may want to regenerate the results programmatically. To do that, set the time as false. This will repopulate the cache with the new results, even if these were not cached before.

use App\Models\Article;

Article::latest('published_at')->take(10)->cache(false)->get();

Finally, you can bypass the cache entirely using the query builder when() and unless() methods easily, as these are totally compatible with the cache() method.

use App\Models\Article;

Article::latest('published_at')->whereBelongsTo($user)->take(10)->unless(Auth::check(), function ($articles) {
    // If the user is a guest, use the cache to show the latest articles of the given user.
    $articles->cache();
})->get();

Custom Cache Store

You can use any other Cache Store different from the application default by setting a third parameter, or a named parameter.

use App\Models\Article;

Article::latest('published_at')->take(10)->cache(store: 'redis')->get();

Cache Lock (data races)

On multiple processes, the query may be executed multiple times until the first process is able to store the result in the cache, specially when these take more than one second. To avoid this, set the wait parameter with the number of seconds to hold the acquired lock.

use App\Models\Article;

Article::latest('published_at')->take(200)->cache(wait: 5)->get();

The first process will acquire the lock for the given seconds and execute the query. The next processes will wait the same amount of seconds until the first process stores the result in the cache to retrieve it. If the first process takes too much, the second will try again.

If you need a more advanced locking mechanism, use the cache lock directly.

Forgetting results with a key

Cache keys are used to identify multiple queries cached with an identifiable name. These are not mandatory, but if you expect to remove a query from the cache, you will need to identify the query with the key argument.

use App\Models\Article;

Article::latest('published_at')->with('drafts')->take(5)->cache(key: 'latest_articles')->get();

Once done, you can later delete the query results using the CacheQuery facade.

use Laragear\CacheQuery\Facades\CacheQuery;

CacheQuery::forget('latest_articles');

Or you may use the cache-query:forget command with the name of the key from the CLI.

php artisan cache-query:forget latest_articles

# Successfully removed [latest_articles] from the [file] cache store. 

You may use the same key for multiple queries to group them into a single list you can later delete in one go.

use App\Models\Article;
use App\Models\Post;
use Laragear\CacheQuery\Facades\CacheQuery;

Article::latest('published_at')->with('drafts')->take(5)->cache(key: 'latest_articles')->get();
Post::latest('posted_at')->take(10)->cache(key: 'latest_articles')->get();

CacheQuery::forget('latest_articles');

This functionality does not use cache tags, so it will work on any cache store you set, even the file driver!

Configuration

To further configure the package, publish the configuration file:

php artisan vendor:publish --provider="Laragear\CacheQuery\CacheQueryServiceProvider" --tag="config"

You will receive the config/cache-query.php config file with the following contents:

<?php

return [
    'store' => env('CACHE_QUERY_STORE'),
    'prefix' => 'cache-query',
];

Cache Store

return  [
    'store' => env('CACHE_QUERY_STORE'),
];

The default cache store to put the queried results. When not issued in the query, this setting will be used. If it's empty or null, the default cache store of your application will be used.

You can easily change this setting using your .env file:

CACHE_QUERY_STORE=redis

Prefix

return  [
    'prefix' => 'cache-query',
];

When storing query hashes and query named keys, this prefix will be appended, which will avoid conflicts with other cached keys. You can change in case it collides with other keys.

Caveats

This cache package does some clever things to always retrieve the data from the cache, or populate it with the results, in an opaque way and using just one method, but this world is far from perfect.

Operations are NOT commutative

Altering the Builder methods order will change the auto-generated cache key. Even if two or more queries are visually the same, the order of statements makes the hash completely different.

For example, given two similar queries in different parts of the application, these both will not share the same cached result:

User::query()->cache()->whereName('Joe')->whereAge(20)->first();
// Cache key: "cache-query|/XreUO1yaZ4BzH2W6LtBSA=="

User::query()->cache()->whereAge(20)->whereName('Joe')->first();
// Cache key: "cache-query|muDJevbVppCsTFcdeZBxsA=="

To avoid this, ensure you always execute the same query, like centralizing the query somewhere in your application.

Cannot delete autogenerated keys

All queries are cached using a BASE64 encoded MD5 hash of the connection name, SQL query and its bindings. This avoids any collision with other queries or different databases, while keeping the cache key shorter than the raw query for a faster lookup in the cache store.

User::query()->cache()->whereAge(20)->whereName('Joe')->first();
// Cache key: "cache-query|muDJevbVppCsTFcdeZBxsA=="

This makes extremely difficult to remove keys from the cache. If you need to invalidate or regenerate the cached results, use a custom key.

PhpStorm stubs

For users of PhpStorm, there is a stub file to aid in macro autocompletion for this package. You can publish them using the phpstorm tag:

php artisan vendor:publish --provider="Laragear\CacheQuery\CacheQueryServiceProvider" --tag="phpstorm"

The file gets published into the .stubs folder of your project. You should point your PhpStorm to these stubs.

How it works?

When you use cache(), it will wrap the connection into a proxy object. It proxies all method calls to it except select() and selectOne().

Once a SELECT statement is executed through the aforementioned methods, it will check if the results are in the cache before executing the query. On cache hit, it will return the cached results, otherwise it will continue execution, save the results using the cache configuration, and return them.

Laravel Octane compatibility

  • There are no singletons using a stale application instance.
  • There are no singletons using a stale config instance.
  • There are no singletons using a stale request instance.
  • There are no static properties written during a request.

There should be no problems using this package with Laravel Octane.

Upgrading

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

License

This specific package version is licensed under the terms of the MIT License, at time of publishing.

Laravel is a Trademark of Taylor Otwell. Copyright © 2011-2022 Laravel LLC.

You might also like...
Sri Lanka Grade Exam Results Bot 📚 can collect Grade 5 O/L A/L Exam Results 📚 in Second Powerd By Sri lanka Department Of Examination 🚀

Sri-Lanka-Exam-Results-Telegram-Bot How to use the bot /start : Start Sri Lanka Grade 5 O/L A/L Exam Results Bot. /help : More information about Sri L

Enable method chaining or fluent expressions for any value and method.

PHP Pipe Operator A (hopefully) temporary solution to implement the pipe operator in PHP. Table of contents Requirements How to install How to use The

Personal CRM. Remember everything about your friends, family and business relationships.
Personal CRM. Remember everything about your friends, family and business relationships.

Personal Relationship Manager Monica is a great open source personal relationship management system. Introduction Purpose Features Who is it for? What

Personal CRM. Remember everything about your friends, family and business relationships.
Personal CRM. Remember everything about your friends, family and business relationships.

Personal Relationship Manager Monica is a great open source personal relationship management system. Introduction Purpose Features Who is it for? What

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

Because I can never remember exactly how to autoload my helpers.php file.

Laravel Helpers File (helpers.php) I add a app/helpers.php file to every project for any custom helpers I might want to create. Everytime I go to add

This Plugin is used to install and activate multiple plugins in one go. I was facing problem uploading plugins one by one so I developed this to solve my problem. Hope you will enjoy using this plugin.

=== Bulk Plugin Installer === Contributors: jawadarshad Donate link: https://jawadarshad.io/ Tags: bulk plugin installer, import multiple plugins, up

A kernel designed to run one and only one application in a virtualized environment
A kernel designed to run one and only one application in a virtualized environment

nanos Nanos is a new kernel designed to run one and only one application in a virtualized environment. It has several constraints on it compared to a

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'

MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way
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

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 )
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

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.

Package to optimize your site automatically which results in a 35%+ optimization
Package to optimize your site automatically which results in a 35%+ optimization

Laravel Page Speed Simple package to minify HTML output on demand which results in a 35%+ optimization. Laravel Page Speed was created by Renato Marin

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

Laravel package for manage your URL redirects in database or other sources to get better SEO results

Laravel 8 and 9 package to manage URL redirections inside your Laravel application using different data sources. It allows a better SEO support for your Laravel site.

Google Search Results PHP API via Serp Api

Google Search Results in PHP This Php API is meant to scrape and parse Google, Bing or Baidu results using SerpApi. The full documentation is availabl

Silverstripe-searchable - Adds to the default Silverstripe search by adding a custom results controller and allowing properly adding custom data objects and custom fields for searching

SilverStripe Searchable Module UPDATE - Full Text Search This module now uses Full Text Support for MySQL/MariaDB databases in version 3.* Adds more c

A program which shows the match days and results of a sport league developed with HTML, PHP and BladeOne technology

league-table Escribe un programa PHP que permita al usuario introducir los nombres de los equipos que participan un una liga de fútbol. Con dichos nom

WebAgency certificate results done by Mickaël Moreau, delivred by Axelo (web-agency.app)

WebAgencyCertificate WebAgency certificate results done by Mickaël Moreau, delivred by Axelo (web-agency.app) Résultat du certificat en pré-production

Comments
  • FIX: Make operations commutative

    FIX: Make operations commutative

    Description

    This fix (or feature?) lets us generate the same cache key, irrespective of the order of the statements and bindings used in the query.

    To make this happen:

    • We first convert the query into an array using str_split()
    • Then we sort both the converted query array and the bindings array using sort()
    • Finally, we implode() the sorted arrays for use in generating the query hash on line 126

    This gives us a commutative hash key for the same query, even the query statements and bindings reordered.

    PS: I'm not sure if this is a fix or a feature :-)

    opened by kheme 6
  • [4.x] Make Operations Commutative

    [4.x] Make Operations Commutative

    Description

    This PR lets us generate the same cache key, irrespective of the order of the statements and bindings used in the query.

    To make this happen:

    • We first convert the query into an array using str_split()
    • Then we sort both the converted query array and the bindings array using sort()
    • Finally, we implode() the sorted arrays for use in generating the query hash on line 126

    This gives us a commutative hash key for the same query, even the query statements and bindings reordered.

    opened by kheme 2
  • [3.0.1] Not working with paginate() method

    [3.0.1] Not working with paginate() method

    PHP & Platform

    8.0.25, Ubuntu 20.04

    Database

    PostgreSQL 13

    Laravel version

    9.37

    Have you done this?

    • [X] I have checked my logs and I'm sure is a bug in this package.
    • [X] I can reproduce this bug in isolation (vanilla Laravel install)
    • [ ] I can suggest a workaround as a Pull Request

    Expectation

    The cache scope should also works with paginate()

    Description

    The paginte() method returns TypeError, but if I change it to simplePaginate method all working fine.

    Reproduction

    $model = Example::query()->cache()->paginate();
    

    Stack trace & logs

    {
     "class": "TypeError",
      "message": "Illuminate\\Database\\Query\\Builder::__construct(): Argument #1 ($connection) must be of type Illuminate\\Database\\ConnectionInterface, Laragear\\CacheQuery\\CacheAwareConnectionProxy given, called in /home/mp/htdocs/backend/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php on line 3482"
    }
    
    bug 
    opened by Kladislav 1
  • [1.x] Forgetting a key returns Array to String exception

    [1.x] Forgetting a key returns Array to String exception

    PHP & Platform

    8.1.3

    Laravel verion

    9.17.0

    Have you done this?

    • [X] I am willing to share my stack trace and logs
    • [X] I can reproduce this bug in isolation (vanilla Laravel install)
    • [ ] I can suggest a workaround as a Pull Request

    Expectation

    Forget key programmatically with Facade

    CacheQuery::forget('offer_details_distinct_quadro');
    

    or

    with artisan command thrown exception

    Description

    Array to string exception

    Reproduction

    $arrayOption = Model::query()->cache(key: 'offer_details_distinct_quadro', ttl: now()->addHour())->distinct()->pluck('name', 'name')
    

    Stack trace & logs

    ErrorException 
    
      Array to string conversion
    
      at vendor/laravel/framework/src/Illuminate/Cache/RedisStore.php:223
        219▕      * @return bool
        220▕      */
        221▕     public function forget($key)
        222▕     {
      ➜ 223▕         return (bool) $this->connection()->del($this->prefix.$key);
        224▕     }
        225▕ 
        226▕     /**
        227▕      * Remove all items from the cache.
    
          +18 vendor frames
    

    Are you a Patreon supporter?

    No, don't give priority to this

    bug 
    opened by Wit3 1
Releases(v3.0.1)
  • v3.0.1(Jun 10, 2022)

  • v3.0.0(Feb 23, 2022)

    This 3.x is a more cleaner implementation of caching queries, as it wraps the Database Connection into a proxy and hears select statements.

    It also supports programmatically caching results forever with null, or regenerating them with false.

    Source code(tar.gz)
    Source code(zip)
  • v2.0.1(Feb 23, 2022)

  • v2.0.0(Feb 18, 2022)

    This new release doesn't break anything, but it changes how it caches results. It simply proxies the underlaying connection for a SELECT statement. Proxying the Database Connection is by far a better implementation of cache interception.

    This version will run in parallel with version 2.0, so you can choose for the foreseeable future which feels better for you, unless 1.x becomes hard to maintain.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Feb 17, 2022)

  • v1.0.1(Feb 16, 2022)

Owner
Laragear
Packages for Laravel
Laragear
Query caching for Laravel

Query caching for Laravel

Dwight Watson 1k Dec 30, 2022
[READ-ONLY] Easy to use Caching library with support for multiple caching backends. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp

CakePHP Caching Library The Cache library provides a Cache service locator for interfacing with multiple caching backends using a simple to use interf

CakePHP 49 Sep 28, 2022
Cache slam defense using a semaphore to prevent dogpile effect.

metaphore PHP cache slam defense using a semaphore to prevent dogpile effect (aka clobbering updates, stampending herd or Slashdot effect). Problem: t

Przemek Sobstel 102 Sep 28, 2022
Zend_Cache backend using Redis with full support for tags

This Zend_Cache backend allows you to use a Redis server as a central cache storage. Tags are fully supported without the use of TwoLevels cache so this backend is great for use on a single machine or in a cluster. Works with any Zend Framework project including all versions of Magento!

Colin Mollenhour 387 Jun 9, 2022
The place to keep your cache.

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 944 Jan 4, 2023
This is a Symfony bundle that lets you you integrate your PSR-6 compliant cache service with the framework

PSR-6 Cache bundle This is a Symfony bundle that lets you you integrate your PSR-6 compliant cache service with the framework. It lets you cache your

null 43 Oct 7, 2021
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
Refresh items in your cache without data races.

Cache Refresh Refresh items in your cache without data races. use Illuminate\Support\Facades\Cache; use Illuminate\Support\Collection; use App\Models\

Laragear 3 Jul 24, 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
Remindle is here to help you remember. Remember everything you want, by the means you prefer, in the frequency you like

platform Personal reminders About Remindle Remindle is a platform which helps you to remember all important events. You can set the means you’d like t

Remindle 4 Dec 23, 2021