|
| 1 | +Laravel Eloquent Query Cache |
| 2 | +=================================== |
| 3 | + |
| 4 | +Laravel Eloquent Query Cache (LEQC; Le QC; Le Query Cache) is a package that brings the `remember()` functionality that has been removed from Laravel a long time ago. |
| 5 | +This package helps adding caching functionalities directly on the Eloquent level, making use of cache before retrieving the data from the DB. |
| 6 | + |
| 7 | +This package adds caching support for **all** query methods. |
| 8 | + |
| 9 | +## Installing the package |
| 10 | +Hop into your console and install the package via Composer: |
| 11 | + |
| 12 | +```bash |
| 13 | +$ composer require rennokki/rennokki/laravel-eloquent-query-cache |
| 14 | +``` |
| 15 | + |
| 16 | +Each model that will accept query-by-query caching will have to use the `Rennokki\QueryCache\Traits\QueryCacheable` trait. |
| 17 | + |
| 18 | +```php |
| 19 | +use Rennokki\QueryCache\Traits\QueryCacheable; |
| 20 | + |
| 21 | +class Podcast extends Model |
| 22 | +{ |
| 23 | + use QueryCacheable; |
| 24 | + |
| 25 | + ... |
| 26 | +} |
| 27 | +``` |
| 28 | + |
| 29 | +## Showcase |
| 30 | +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. |
| 31 | + |
| 32 | +```php |
| 33 | +use Rennokki\QueryCache\Traits\QueryCacheable; |
| 34 | + |
| 35 | +class Article extends Model |
| 36 | +{ |
| 37 | + use QueryCacheable; |
| 38 | + |
| 39 | + $cacheFor = 3600; // cache time, in seconds |
| 40 | + ... |
| 41 | +} |
| 42 | + |
| 43 | +// SELECT * FROM articles ORDER BY created_at DESC LIMIT 1; |
| 44 | +$latestArticle = Article::latest()->first(); |
| 45 | + |
| 46 | +// SELECT * FROM articles WHERE published = 1; |
| 47 | +$publishedArticles = Article::wherePublished(true)->get(); |
| 48 | +``` |
| 49 | + |
| 50 | +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. |
| 51 | + |
| 52 | +It is also possible to enable caching for specific queries. This is the recommended way because it is easier to manage each query. |
| 53 | + |
| 54 | +```php |
| 55 | +$postsCount = Post::cacheFor(60 * 60)->count(); |
| 56 | + |
| 57 | +// Using a DateTime instance like Carbon works perfectly fine! |
| 58 | +$postsCount = Post::cacheFor(now()->addDays(1))->count(); |
| 59 | +``` |
| 60 | + |
| 61 | +## Cache Tags & Cache Invalidation |
| 62 | +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. |
| 63 | + |
| 64 | +```php |
| 65 | +$shelfOneBooks = Book::whereShelf(1)->cacheFor(60)->cacheTags(['shelf:1'])->get(); |
| 66 | +$shelfTwoBooks = Book::whereShelf(2)->cacheFor(60)->cacheTags(['shelf:2'])->get(); |
| 67 | + |
| 68 | +// After flushing the cache for shelf:1, the query of$shelfTwoBooks will still hit the cache if re-called again. |
| 69 | +Book::flushQueryCache(['shelf:1']); |
| 70 | +``` |
| 71 | + |
| 72 | +Be careful tho - specifying cache tags does not change the behaviour of key storage. |
| 73 | +For example, the following two queries, altough the use the same tag, they have different keys stored in the caching database. |
| 74 | + |
| 75 | +```php |
| 76 | +$alice = Kid::whereName('Alice')->cacheFor(60)->cacheTags(['kids'])->first(); |
| 77 | +$bob = Kid::whereName('Bob')->cacheFor(60)->cacheTags(['kids'])->first(); |
| 78 | +``` |
| 79 | + |
| 80 | +In case you want to invalidate all the cache, don't specify an argument for the `flushQueryCache()` method: |
| 81 | + |
| 82 | +```php |
| 83 | +Problem::flushQueryCache(); // bye-bye problems! |
| 84 | +``` |
| 85 | + |
| 86 | +## Relationship Caching |
| 87 | +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. |
| 88 | + |
| 89 | +```php |
| 90 | +$user = User::with(['orders' => function ($query) { |
| 91 | + return $query->cacheFor(60 * 60)->cacheTags(['my:orders']); |
| 92 | +}])->get(); |
| 93 | + |
| 94 | +// This comes from the cache if existed. |
| 95 | +$orders = $user->orders; |
| 96 | +``` |
| 97 | + |
| 98 | +## Cache Keys |
| 99 | +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. |
| 100 | + |
| 101 | +```php |
| 102 | +$bob = Kid::whereName('Bob')->cacheFor(60)->prefix('kids_')->first(); |
| 103 | +``` |
| 104 | + |
| 105 | +If no prefix is specified, the string `leqc` is going to be used. |
| 106 | + |
| 107 | +## Cache Drivers |
| 108 | +By default, the trait uses the default cache driver. If you want to **force** a specific one, you can do so by calling `cacheDriver()`: |
| 109 | + |
| 110 | +```php |
| 111 | +$bob = Kid::whereName('Bob')->cacheFor(60)->cacheDriver('dynamodb')->first(); |
| 112 | +``` |
| 113 | + |
| 114 | +## Disable caching |
| 115 | +If you enabled caching (either by model variable or by the `cacheFor` scope), you can also opt to disable it mid-builder. |
| 116 | +```php |
| 117 | +$uncachedBooks = Book::dontCache()->get(); |
| 118 | +$uncachedBooks = Book::doNotCache()->get(); // same thing |
| 119 | +``` |
| 120 | + |
| 121 | +## Equivalent Methods and Variables |
| 122 | +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. |
| 123 | +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. |
| 124 | + |
| 125 | +```php |
| 126 | +class Book extends Model |
| 127 | +{ |
| 128 | + public $cacheFor = 3600; // equivalent of ->cacheFor(3600) |
| 129 | + |
| 130 | + public $cacheTags = ['books']; // equivalent of ->cacheTags(['books']) |
| 131 | + |
| 132 | + public $cachePrefix = 'books_' // equivalent of ->cachePrefix('books_'); |
| 133 | + |
| 134 | + public $cacheDriver = 'dynamodb'; // equivalent of ->cacheDriver('dynamodb'); |
| 135 | +} |
| 136 | +``` |
0 commit comments