You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can **[spread the word!](http://twitter.com/share?text=I%20am%20using%20this%20cool%20PHP%20package&url=https://github.com%2FLaragear%2FCacheQuery&hashtags=PHP,Laravel)**
19
+
Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can **spread the word in social media**
20
20
21
21
## Requirements
22
22
23
-
* Laravel 10 or later
23
+
* Laravel 11 or later
24
24
25
25
## Installation
26
26
@@ -30,6 +30,12 @@ You can install the package via composer:
30
30
composer require laragear/cache-query
31
31
```
32
32
33
+
## How it works?
34
+
35
+
This library wraps the connection into a proxy object. It proxies all method calls to it except `select()` and `selectOne()`.
36
+
37
+
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.
38
+
33
39
## Usage
34
40
35
41
Just use the `cache()` method to remember the results of a query for a default of 60 seconds.
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`.
52
+
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`. You may also desire to [not cache empty results](#cache-except-empty-results).
47
53
48
-
It's **eager load aware**. This means that it will cache an eager loaded relation automatically.
54
+
It's **eager load aware**. This means that it will cache an eager loaded relation automatically, but [you may also disable this](#eager-loaded-queries).
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.
85
+
### Stale while revalidate
86
+
87
+
You may take advantage of [Laravel Flexible Caching mechanism](https://laravel.com/docs/cache#swr) by issuing an array of values as first argument. (...) _The first value in the array represents the number of seconds the cache is considered fresh, while the second value defines how long it can be served as stale data before recalculation is necessary_.
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.
95
+
The above example will refresh the query results if there is 60 seconds lefts until the data dies.
96
+
97
+
## Advanced caching
98
+
99
+
You may use a callback to further change the query caching. The callback receives a `Laragear\CacheQuery\Cache` instance that allows to change how to cache the data.
90
100
91
101
```php
92
-
use App\Models\Article;
102
+
use Laragear\CacheQuery\Cache;
103
+
use App\Models\User;
93
104
94
-
Article::latest('published_at')->whereBelongsTo($user)->take(10)->unless(Auth::check(), function ($articles) {
95
-
// If the user is a guest, use the cache to show the latest articles of the given user.
Alternatively, you can create and configure an instance outside the query, and then pass it as an argument. You can do this with the `for()` method or `flexible()` method
101
111
102
-
You can use any other Cache Store different from the application default by setting a third parameter, or a named parameter.
You may want to forcefully regenerate the queried cache when the underlying data changes, or because other reason. For that, use the `regenWhen()` and a condition that evaluates to `true`, and `regenUnless()` for a condition that evaluates to `false`. If you pass a callback, it will be executed before retrieving the results from the cache.
By default, the `cache()` method will cache _any_ result from the query, empty or not. You can disable this with the `exceptEmpty()` method, which will only cache non-empty results.
141
+
142
+
```php
143
+
use Laragear\CacheQuery\Cache;
144
+
145
+
Cache::for(300)->exceptEmpty();
146
+
```
111
147
112
-
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. Take, for example, 1,000 users reading the latest 10 post of a site at the same time will call the database 1,000 times.
148
+
### Eager loaded queries
113
149
114
-
To avoid this, set the `wait` parameter with the number of seconds to hold the acquired lock.
150
+
You may disable caching Eager Loaded Queries with the `exceptNested()` method. With that, only the query that invokes the `cache()` method will be cached.
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.
158
+
For example, in this query, only the `User`querywill be cached, while the `posts` won't.
123
159
124
-
> If you need a more advanced locking mechanism, use the [cache lock](https://laravel.com/docs/cache#managing-locks-across-processes) directly.
You may take advantage of [Laravel Flexible Caching mechanism](https://laravel.com/docs/11.x/cache#swr) by issuing an array of values as first argument. (...) _The first value in the array represents the number of seconds the cache is considered fresh, while the second value defines how long it can be served as stale data before recalculation is necessary_.
173
+
By default, the cached results use your application default cache store. You may change the default store using the `store()` method.
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.
183
+
If you plan to remove a query from the cache, you will need to identify the query with the `as()` method and an identifiable key name.
> This functionality does not use cache tags, so it will work on any cache store you set, even the `file` driver!
176
226
177
227
## Custom Hash Function
@@ -184,13 +234,13 @@ This can be done in the `register()` method of your `AppServiceProvider`.
184
234
namespace App\Providers;
185
235
186
236
use Illuminate\Support\ServiceProvider;
187
-
use Laragear\CacheQuery\CacheAwareConnectionProxy;
237
+
use Laragear\CacheQuery\Proxy;
188
238
189
239
class AppServiceProvider extends ServiceProvider
190
240
{
191
241
public function register()
192
242
{
193
-
CacheAwareConnectionProxy::$queryHasher = function ($connection, $query, $bindings) {
243
+
Proxy::$queryHasher = function ($connection, $query, $bindings) {
194
244
// ...
195
245
}
196
246
}
@@ -213,6 +263,7 @@ You will receive the `config/cache-query.php` config file with the following con
213
263
return [
214
264
'store' => env('CACHE_QUERY_STORE'),
215
265
'prefix' => 'cache-query',
266
+
'commutative' => false
216
267
];
217
268
```
218
269
@@ -242,38 +293,37 @@ return [
242
293
243
294
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.
244
295
245
-
## Caveats
246
-
247
-
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.
248
-
249
-
### Operations are **NOT** commutative
296
+
### Commutative operations
250
297
251
-
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.
298
+
```php
299
+
return [
300
+
'commutative' => false
301
+
]
302
+
```
252
303
253
-
For example, given two similar queries in different parts of the application, these both will **not** share the same cached result:
304
+
When _hashing_queries, the default [hasher function](#custom-hash-function) will create different hashes even on visually different queries.
To avoid this, ensure you always execute the same query, or centralize the query somewhere in your application (like using a [query scope](https://laravel.com/docs/11.x/eloquent#query-scopes)).
264
-
265
-
> **Note** This is by design. Ordering the query bindings would make operations commutative, but also disrupt [query-index optimizations](https://use-the-index-luke.com/sql/where-clause/the-equals-operator/concatenated-keys). Consider this not a bug, but a _feature_.
266
-
267
-
### Cannot delete autogenerated keys
268
-
269
-
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 even from different databases, and also makes the cache lookup faster thanks to a shorter cache key.
314
+
By setting `commutative` to `true`, the function will always sort the query elements so similar queries share the same hash.
This makes extremely difficult to remove keys from the cache. If you need to invalidate or regenerate the cached results, [use a custom key](#forgetting-results-with-a-key).
324
+
> [!TIP]
325
+
>
326
+
> This can be also overridden using your own [custom hash function](#custom-hash-function).
The file gets published into the `.stubs` folder of your project. You should point your [PhpStorm to these stubs](https://www.jetbrains.com/help/phpstorm/php.html#advanced-settings-area).
287
337
288
-
## How it works?
289
-
290
-
When you use `cache()`, it will wrap the connection into a proxy object. It proxies all method calls to it except `select()` and `selectOne()`.
291
-
292
-
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.
293
-
294
338
## Laravel Octane compatibility
295
339
296
340
- There are no singletons using a stale application instance.
0 commit comments