├── .gitattributes
├── .github
└── workflows
│ └── run-tests.yml
├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── config
└── config.php
├── phpunit.xml
├── src
├── Actions
│ ├── DeleteCacheAction.php
│ ├── DeleteGroupCacheAction.php
│ ├── Support
│ │ └── UpdateDeleteCache.php
│ ├── UpdateCacheAction.php
│ └── UpdateGroupCacheAction.php
├── Cache.php
├── CacheEntity.php
├── Commands
│ ├── DeleteCacheCommand.php
│ ├── DeleteGroupCacheCommand.php
│ ├── UpdateCacheCommand.php
│ └── UpdateGroupCacheCommand.php
├── DTOs
│ ├── CacheData.php
│ ├── CacheEvent.php
│ ├── CacheStatus.php
│ └── CommandData.php
├── Exceptions
│ ├── CacheEntityDoesNotExist.php
│ ├── CacheGroupNotExist.php
│ ├── CacheGroupValueIsNotValid.php
│ ├── EntityIsNotAllowed.php
│ ├── ModelDoesntUseLaraCacheTrait.php
│ └── ModelDoestNotExist.php
├── Facades
│ └── LaraCache.php
├── Jobs
│ ├── RefreshCache.php
│ └── UpdateLaraCacheModelsList.php
├── LaraCache.php
├── LaraCacheServiceProvider.php
├── Observers
│ └── LaraCacheObserver.php
├── Traits
│ ├── InteractsWithCache.php
│ └── LaraCache.php
└── Utils
│ ├── CacheEnum.php
│ └── Helpers.php
└── tests
├── Feature
├── CacheDefaultValueTest.php
├── CacheEntityTest.php
├── CacheExpirationTest.php
├── CraeteCacheTest.php
├── DeleteCacheCommandTest.php
├── DeleteCacheTest.php
├── DeleteGroupCacheCommandTest.php
├── HelpersTest.php
├── QueueCacheTest.php
├── RestoreCacheTest.php
├── RetrieveCacheTest.php
├── UpdateCacheCommandTest.php
├── UpdateCacheTest.php
├── UpdateGroupCacheCommandTest.php
└── UpdateLaraCacheModelsListTest.php
├── Pest.php
├── TestCase.php
├── TestSupport
└── TestModels
│ ├── QueueTestModel.php
│ ├── TestModel.php
│ ├── TestModel2.php
│ └── TestUser.php
└── Unit
├── CacheStatusTest.php
├── CommandDataTest.php
├── DeleteCacheActionTest.php
├── DeleteGroupCacheActionTest.php
├── UpdateCacheActionTest.php
└── UpdateGroupCacheActionTest.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/workflows/run-tests.yml:
--------------------------------------------------------------------------------
1 | name: Run Tests
2 |
3 | on:
4 | - push
5 | - pull_request
6 |
7 | jobs:
8 | tests:
9 | runs-on: ${{ matrix.os }}
10 |
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | os: [ubuntu-latest]
15 | php: [8.0, 8.1, 8.2, 8.3, 8.4]
16 | laravel: ['8.*', '9.*', '10.*', '11.*', '12.*']
17 | coverage: [none]
18 | dependency-version: [prefer-stable]
19 | include:
20 | - laravel: 10.*
21 | testbench: 8.*
22 | - laravel: 9.*
23 | testbench: 7.*
24 | - laravel: 8.*
25 | testbench: 6.*
26 | - laravel: 11.*
27 | testbench: 9.*
28 | - laravel: 12.*
29 | testbench: 10.*
30 | exclude:
31 | - laravel: 10.*
32 | php: 8.0
33 | - laravel: 11.*
34 | php: 8.0
35 | - laravel: 11.*
36 | php: 8.1
37 | - laravel: 12.*
38 | php: 8.0
39 | - laravel: 12.*
40 | php: 8.1
41 |
42 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.os }} - ${{ matrix.dependency-version }}
43 |
44 | steps:
45 | - name: Update apt
46 | run: sudo apt-get update --fix-missing
47 |
48 | - name: Checkout code
49 | uses: actions/checkout@v4
50 |
51 | - name: Cache dependencies
52 | uses: actions/cache@v4
53 | with:
54 | path: ~/.composer/cache/files
55 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
56 |
57 | - name: Setup PHP
58 | uses: shivammathur/setup-php@v2
59 | with:
60 | php-version: ${{ matrix.php }}
61 | extensions: dom, curl, libxml, mbstring, zip, pcntl, sqlite3, pdo_sqlite, bcmath, fileinfo, xdebug
62 | tools: composer:v2
63 | ini-values: xdebug.mode="coverage"
64 | coverage: xdebug
65 |
66 | - name: Install dependencies
67 | run: |
68 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
69 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
70 |
71 | - name: Execute tests
72 | run: composer test:ci
73 |
74 | - name: Upload coverage
75 | uses: codecov/codecov-action@v1
76 | with:
77 | token: ${{ secrets.CODECOV_TOKEN }}
78 | file: ./coverage.xml
79 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | vendor
3 | .idea
4 | .phpunit.result.cache
5 | coverage.xml
6 | composer.lock
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Mostafa Zeinivand
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LaraCache
2 |
3 | [](https://github.com/mostafaznv/laracache/actions)
4 | [](https://app.codecov.io/gh/mostafaznv/laracache)
5 | [](https://scrutinizer-ci.com/g/mostafaznv/laracache)
6 | [](https://github.com/mostafaznv/laracache/blob/master/LICENSE)
7 | [](https://packagist.org/packages/mostafaznv/laracache)
8 | [](https://packagist.org/packages/mostafaznv/laracache)
9 |
10 | 
11 |
12 | Using this package, you can cache your heavy and most used queries.
13 |
14 | All you have to do is to define the `CacheEntity` objects in the model and specify a valid name and ttl for them.
15 |
16 | LaraCache will handle the rest of process automatically. It will create and update cache entities based on ttl that you've defined for each entity.
17 |
18 | Manually updating the cache entities of models after dispatching model events (creating, updating and deleting) isn't required, LaraCache manages them in the background and ensures the most up-to-date version of each cache entity.
19 |
20 | In addition to the core LaraCache package, I have developed a complementary package called [Nova LaraCache](https://github.com/mostafaznv/nova-laracache). Nova LaraCache seamlessly integrates LaraCache with [Laravel Nova](https://nova.laravel.com), the administration panel for Laravel applications. It offers a user-friendly interface within the Laravel Nova administration panel, enabling users to conveniently moderate and manage cache entities.
21 |
22 |
23 | ----
24 | I am on an open-source journey 🚀, and I wish I could solely focus on my development path without worrying about my financial situation. However, as life is not perfect, I have to consider other factors.
25 |
26 | Therefore, if you decide to use my packages, please kindly consider making a donation. Any amount, no matter how small, goes a long way and is greatly appreciated. 🍺
27 |
28 | [](https://mostafaznv.github.io/donate)
29 |
30 | ----
31 |
32 |
33 | ## Requirements:
34 |
35 | - PHP 8.0.2 or higher
36 | - Laravel 8.40.0 or higher
37 |
38 |
39 | ## Installation
40 |
41 | 1. ##### Install the package via composer:
42 | ```shell
43 | composer require mostafaznv/laracache
44 | ```
45 |
46 | 2. ##### Publish config file:
47 | ```shell
48 | php artisan vendor:publish --provider="Mostafaznv\LaraCache\LaraCacheServiceProvider"
49 | ```
50 |
51 | 3. ##### Done
52 |
53 |
54 | ## Usage
55 |
56 | 1. ##### Add LaraCache trait to the model
57 | ```php
58 | cache(function() {
79 | return Article::query()->latest()->get();
80 | }),
81 |
82 | CacheEntity::make('latest')
83 | ->validForRestOfDay()
84 | ->cache(function() {
85 | return Article::query()->latest()->first();
86 | })
87 | ];
88 | }
89 | }
90 | ```
91 |
92 | 2. ##### Retrieve Cache
93 | ```php
94 | use App\Models\Article;
95 | use Mostafaznv\LaraCache\Facades\LaraCache;
96 |
97 |
98 | $cache = Article::cache()->get('latest');
99 | // or
100 | $cache = LaraCache::retrieve(Article::class, 'latest');
101 | ```
102 |
103 |
104 | ## Table of Contents:
105 | - [Installation](#installation)
106 | - [Install the package via composer](#install-the-package-via-composer)
107 | - [Publish config file](#publish-config-file)
108 | - [Usage](#usage)
109 | - [CacheEntity Methods](#cacheentity-methods)
110 | - [Disable/Enable Cache](#disableenable-cache)
111 | - [Enable](#enable)
112 | - [Disable](#disable)
113 | - [Update Cache Manually](#update-cache-manually)
114 | - [Update an Entity](#update-an-entity)
115 | - [Update all Entities](#update-all-entities)
116 | - [Update all LaraCache Entities](#update-all-laracache-entities)
117 | - [Delete Cache Manually](#delete-cache-manually)
118 | - [Delete an Entity](#delete-an-entity)
119 | - [Delete an Entity Forever](#delete-an-entity-forever)
120 | - [Delete all Model Entities](#delete-all-model-entities)
121 | - [Delete all Model Entities Forever](#delete-all-model-entities-forever)
122 | - [Delete all LaraCache Entities](#delete-all-laracache-entities)
123 | - [Artisan Commands](#artisan-commands)
124 | - [Update Cache](#update-cache)
125 | - [Delete Cache](#delete-cache)
126 | - [Group Operations](#group-operations)
127 | - [Laravel Nova Support](#laravel-nova-support)
128 | - [Config Properties](#config-properties)
129 | - [Complete Example](#complete-example)
130 |
131 |
132 |
133 | ## CacheEntity Methods
134 |
135 | | method | Arguments | description |
136 | |----------------------|-------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
137 | | setDriver | driver (type: `string`) | Specifies custom driver for cache entity |
138 | | isQueueable | status (type: `bool`, default: 'true')
onConnection (type: `string`, default: '')
onQueue (type: `string`, default: '') | This option specifies whether the cache operation should be performed in the background or not.
**Note**: By using the `onConnection` and `onQueue` arguments, you have the ability to specify custom connection and queue names for each cache entity. |
139 | | refreshAfterCreate | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after create a record |
140 | | refreshAfterUpdate | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after update a record |
141 | | refreshAfterDelete | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after delete a record |
142 | | refreshAfterRestore | status (type: `bool`, default: `true`) | Specifies if the cache should refresh after restore a record |
143 | | forever | | Specifies that the cache should be valid forever |
144 | | validForRestOfDay | | Specify that cache entity should be valid till end of day |
145 | | validForRestOfWeek | | Specify that cache entity should be valid till end of week |
146 | | ttl | seconds (type: `int`) | Specifies cache time to live in second |
147 | | setDefault | defaultValue (type: `mixed`) | Specifies default value for the case that cache entity doesn't have any value |
148 | | cache | Closure | **Main** part of each cache entity. defines cache content |
149 |
150 |
151 | ## Disable/Enable Cache
152 |
153 | If you want to disable/enable cache, you can do it in the following two ways:
154 |
155 | ### Disable
156 |
157 | ```php
158 | use App\Models\Article;
159 | use Mostafaznv\LaraCache\Facades\LaraCache;
160 |
161 |
162 | Article::cache()->disable();
163 | // or
164 | LaraCache::disable(Article::class);
165 | ```
166 |
167 |
168 | ### Enable
169 |
170 | ```php
171 | use App\Models\Article;
172 | use Mostafaznv\LaraCache\Facades\LaraCache;
173 |
174 |
175 | Article::cache()->enable();
176 | // or
177 | LaraCache::enable(Article::class);
178 | ```
179 |
180 | ## Update Cache Manually
181 |
182 | Sometimes you want to update cache entities manually.
183 |
184 | ### Update an Entity
185 |
186 | ```php
187 | use App\Models\Article;
188 | use Mostafaznv\LaraCache\Facades\LaraCache;
189 |
190 |
191 | Article::cache()->update('latest');
192 | // or
193 | LaraCache::update(Article::class, 'latest');
194 | ```
195 |
196 | ### Update all Entities
197 |
198 | ```php
199 | use App\Models\Article;
200 | use Mostafaznv\LaraCache\Facades\LaraCache;
201 |
202 |
203 | Article::cache()->updateAll();
204 | // or
205 | LaraCache::updateAll(Article::class);
206 | ```
207 |
208 | ### Update all LaraCache Entities
209 |
210 | This will update all cache entities that stored using LaraCache (across all models)
211 |
212 | ```php
213 | use App\Models\Article;
214 | use Mostafaznv\LaraCache\Facades\LaraCache;
215 |
216 |
217 | LaraCache::updateAll();
218 | ```
219 |
220 | ## Delete Cache Manually
221 |
222 | Sometimes you want to delete cache entities manually. using these methods, you can do it.
223 |
224 | ### Delete an Entity
225 |
226 | Using this feature, you can delete cache entities temporary. after spending ttl, cache entity will be generated again.
227 |
228 | ```php
229 | use App\Models\Article;
230 | use Mostafaznv\LaraCache\Facades\LaraCache;
231 |
232 |
233 | Article::cache()->delete('latest');
234 | // or
235 | LaraCache::delete(Article::class, 'latest');
236 | ```
237 |
238 | ### Delete an Entity Forever
239 |
240 | Using this feature, you can delete cache entities permanently. Cache item will be deleted forever and whenever you try to retrieve it, you will get null (or default value).
241 |
242 |
243 |
244 | ```php
245 | use App\Models\Article;
246 | use Mostafaznv\LaraCache\Facades\LaraCache;
247 |
248 |
249 | Article::cache()->delete('latest', true);
250 | // or
251 | LaraCache::delete(Article::class, 'latest', true);
252 | ```
253 |
254 | > Note: Cache Entity will update after creating or updating records in your model
255 |
256 |
257 | ### Delete all Model Entities
258 |
259 | ```php
260 | use App\Models\Article;
261 | use Mostafaznv\LaraCache\Facades\LaraCache;
262 |
263 |
264 | Article::cache()->deleteAll();
265 | // or
266 | LaraCache::deleteAll(Article::class);
267 | ```
268 |
269 |
270 |
271 | ### Delete all Model Entities Forever
272 |
273 | ```php
274 | use App\Models\Article;
275 | use Mostafaznv\LaraCache\Facades\LaraCache;
276 |
277 |
278 | Article::cache()->deleteAll(true);
279 | // or
280 | LaraCache::deleteAll(Article::class, true);
281 | ```
282 |
283 |
284 |
285 | ### Delete all LaraCache Entities
286 |
287 | This will delete all cache entities that stored using LaraCache (across all models)
288 |
289 | ```php
290 | use App\Models\Article;
291 | use Mostafaznv\LaraCache\Facades\LaraCache;
292 |
293 | LaraCache::deleteAll();
294 | // forever
295 | LaraCache::deleteAll(forever: true);
296 | ```
297 |
298 |
299 |
300 |
301 | ## Artisan Commands
302 | This feature allows you to update or delete multiple cache entities of one or more models from the console command. This means you can programmatically control the cache data outside the caching cycle.
303 |
304 | You can also create groups of models and their entities in the config file and easily update or delete all their entities at once.
305 |
306 | ### Update Cache
307 | ```shell
308 | # updates all entities of article model
309 | php artisan laracache:update -m Article
310 |
311 | # updates specified entities of article model
312 | php artisan laracache:update -m Article -e latest -e featured
313 |
314 | # updates all entities of article and product models
315 | php artisan laracache:update -m Article -m Product
316 |
317 | # defines model with full namespace
318 | php artisan laracache:update -m "Domain\Article\Models\Article"
319 | ```
320 |
321 | ### Delete Cache
322 | ```shell
323 | # deletes all entities of article model
324 | php artisan laracache:delete -m Article
325 |
326 | # deletes specified entities of article model
327 | php artisan laracache:delete -m Article -e latest -e featured
328 |
329 | # deletes all entities of article and product models
330 | php artisan laracache:delete -m Article -m Product
331 |
332 | # defines model with full namespace
333 | php artisan laracache:delete -m "Domain\Article\Models\Article"
334 | ```
335 |
336 | > **Note**: If you don't specify any entity, all entities will be operated.
337 |
338 | > **Note**: If you specify multiple models, you can't specify any entity and all entities of all models will be operated.
339 |
340 |
341 | ### Group Operations
342 | ```shell
343 | # updates all entities of models that are in group-1
344 | php artisan laracache:update-group group-1
345 |
346 | # deletes all entities of models that are in group-1
347 | php artisan laracache:delete-group group-1
348 | ```
349 |
350 | This is an example of a group configuration:
351 | ```php
352 | # config/laracache.php
353 | return [
354 | // ...
355 | 'groups' => [
356 | 'group-1' => [
357 | [
358 | 'model' => \App\Models\User::class,
359 | 'entities' => [
360 | 'users.latest', 'users.featured'
361 | ],
362 | ],
363 | [
364 | 'model' => \App\Models\Article::class,
365 | 'entities' => [],
366 | ]
367 | ],
368 |
369 | 'group-2' => [
370 | [
371 | 'model' => \App\Models\Article::class,
372 | 'entities' => [
373 | 'featured-list', 'latest'
374 | ],
375 | ],
376 | [
377 | 'model' => \App\Models\User::class,
378 | 'entities' => ['users.latest'],
379 | ]
380 | ],
381 | ]
382 | ];
383 | ```
384 |
385 | ## Laravel Nova Support
386 | [Nova LaraCache](https://github.com/mostafaznv/nova-laracache) is a powerful Laravel Nova package that extends the functionalities of LaraCache by integrating it seamlessly with Laravel Nova. It provides an intuitive interface within the Laravel Nova administration panel, allowing users to effortlessly moderate and manage cache entities.
387 |
388 | With Nova LaraCache, users can conveniently monitor cache expiration dates, review cache entity contents, regenerate cache items, and delete specific cache entries.
389 |
390 | To unlock the cache management capabilities provided by Nova LaraCache, please refer to the installation instructions and consult the LaraCache [documentation](https://github.com/mostafaznv/nova-laracache) for guidance on creating cache entities for each model.
391 |
392 | ## Config Properties
393 |
394 | | method | Type | description |
395 | |-------------------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
396 | | driver | string (default: `null`) | The default mechanism for handling cache storage.
If you keep this option `null`, LaraCache will use the default cache storage from `config/cache.php` |
397 | | laracache-list | string (default: `laracache.list`) | LaraCache uses a separate list to store name of all entities. using these keys, we can perform some actions to all entities (such as update or delete them) |
398 | | first-day-of-week | integer (default: `0`) | In some regions, saturday is first day of the week and in another regions it may be different. you can change the first day of a week by changing this property |
399 | | last-day-of-week | integer (default: `6`) | In some regions, friday is last day of the week and in another regions it may be different. you can change the last day of a week by changing this property |
400 | | queue.status | bool (default: `false`) | Sometimes caching process is very heavy, so you have to queue the process and do it in background. |
401 | | queue.name | string (default: `default`) | You have the option to set custom name for the queue process. This name will be used when invoking the `onQueue` method while dispatching the queue job. |
402 | | queue.connection | string (default: `null`) | You have the option to set custom connection for the queue process. This connection will be used when invoking the `onConnection` method while dispatching the queue job. |
403 | | groups | array (default: `[]`) | You can group some entities and perform some operations on them |
404 |
405 |
406 | ## Complete Example
407 | ```php
408 | forever()
429 | ->setDriver('redis')
430 | ->cache(function() {
431 | return Article::query()->latest()->get();
432 | }),
433 |
434 | CacheEntity::make('list.day')
435 | ->isQueueable()
436 | ->validForRestOfDay()
437 | ->cache(function() {
438 | return Article::query()->latest()->get();
439 | }),
440 |
441 | CacheEntity::make('list.week')
442 | ->isQueueable(true, 'redis', 'low')
443 | ->validForRestOfWeek()
444 | ->cache(function() {
445 | return Article::query()->latest()->get();
446 | }),
447 |
448 | CacheEntity::make('list.ttl')
449 | ->ttl(120)
450 | ->cache(function() {
451 | return Article::query()->latest()->get();
452 | }),
453 |
454 | CacheEntity::make('latest')
455 | ->forever()
456 | ->cache(function() {
457 | return Article::query()->latest()->first();
458 | }),
459 |
460 | CacheEntity::make('latest.no-create')
461 | ->refreshAfterCreate(false)
462 | ->cache(function() {
463 | return Article::query()->latest()->first();
464 | }),
465 |
466 | CacheEntity::make('latest.no-update')
467 | ->refreshAfterUpdate(false)
468 | ->cache(function() {
469 | return Article::query()->latest()->first();
470 | }),
471 |
472 | CacheEntity::make('latest.no-delete')
473 | ->refreshAfterDelete(false)
474 | ->cache(function() {
475 | return Article::query()->latest()->first();
476 | }),
477 |
478 | CacheEntity::make('latest.no-restore')
479 | ->refreshAfterRestore(false)
480 | ->cache(function() {
481 | return Article::query()->latest()->first();
482 | }),
483 |
484 | CacheEntity::make('empty.array')
485 | ->setDefault('empty value')
486 | ->cache(fn() => []),
487 | ];
488 | }
489 | }
490 | ```
491 |
492 | ----
493 | I am on an open-source journey 🚀, and I wish I could solely focus on my development path without worrying about my financial situation. However, as life is not perfect, I have to consider other factors.
494 |
495 | Therefore, if you decide to use my packages, please kindly consider making a donation. Any amount, no matter how small, goes a long way and is greatly appreciated. 🍺
496 |
497 | [](https://mostafaznv.github.io/donate)
498 |
499 | ----
500 |
501 |
502 |
503 | ## License
504 |
505 | This software is released under [The MIT License (MIT)](LICENSE).
506 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mostafaznv/laracache",
3 | "description": "LaraCache is a customizable cache trait to cache queries on model's events",
4 | "keywords": [
5 | "laravel",
6 | "eloquent",
7 | "orm",
8 | "cache",
9 | "redis",
10 | "memcache",
11 | "laravel 8",
12 | "laravel 9",
13 | "nova 4",
14 | "mostafaznv"
15 | ],
16 | "license": "MIT",
17 | "support": {
18 | "issues": "https://github.com/mostafaznv/laracache/issues",
19 | "source": "https://github.com/mostafaznv/laracache",
20 | "docs": "https://github.com/mostafaznv/laracache/blob/master/README.md"
21 | },
22 | "authors": [
23 | {
24 | "name": "mostafaznv",
25 | "email": "mostafa.zeinivand@gmail.com"
26 | }
27 | ],
28 | "minimum-stability": "dev",
29 | "prefer-stable": true,
30 | "require": {
31 | "php": "^8.0.2",
32 | "laravel/framework": "^8.40.0|^9.0|^10.0|^11.0|^12.0"
33 | },
34 | "require-dev": {
35 | "phpunit/phpunit": "^9.5.10|^10.0|^11.5.3",
36 | "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0|^10.0",
37 | "pestphp/pest": "^1.20|^2.34|^3.7",
38 | "spatie/pest-plugin-test-time": "^1.0|^2.1"
39 | },
40 | "autoload": {
41 | "psr-4": {
42 | "Mostafaznv\\LaraCache\\": "src/"
43 | },
44 | "files": [
45 | "src/Utils/Helpers.php"
46 | ]
47 | },
48 | "autoload-dev": {
49 | "psr-4": {
50 | "Mostafaznv\\LaraCache\\Tests\\": "tests"
51 | }
52 | },
53 | "scripts": {
54 | "test": "vendor/bin/pest",
55 | "test:ci": "vendor/bin/pest --coverage --coverage-text --coverage-clover=coverage.xml"
56 | },
57 | "config": {
58 | "sort-packages": true,
59 | "allow-plugins": {
60 | "pestphp/pest-plugin": true
61 | }
62 | },
63 | "extra": {
64 | "laravel": {
65 | "providers": [
66 | "Mostafaznv\\LaraCache\\LaraCacheServiceProvider"
67 | ]
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/config/config.php:
--------------------------------------------------------------------------------
1 | null,
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Cache List Key
21 | |--------------------------------------------------------------------------
22 | |
23 | | LaraCache uses a separate list to store name of all entities. using these
24 | | keys, we can perform some actions to all entities (such as update or delete them)
25 | |
26 | */
27 |
28 | 'laracache-list' => 'laracache.list',
29 |
30 | /*
31 | |--------------------------------------------------------------------------
32 | | First Day of Week
33 | |--------------------------------------------------------------------------
34 | |
35 | | In some regions, saturday is first day of the week and in another regions
36 | | it may be different
37 | |
38 | */
39 |
40 | 'first-day-of-week' => \Carbon\Carbon::SUNDAY,
41 |
42 | /*
43 | |--------------------------------------------------------------------------
44 | | Last Day of Week
45 | |--------------------------------------------------------------------------
46 | |
47 | | In some regions, friday is last day of the week and in another regions
48 | | it may be different
49 | |
50 | */
51 |
52 | 'last-day-of-week' => \Carbon\Carbon::SATURDAY,
53 |
54 | /*
55 | |--------------------------------------------------------------------------
56 | | Queue
57 | |--------------------------------------------------------------------------
58 | |
59 | | Sometimes caching process is very heavy, so you have to queue the process and do it in background.
60 | |
61 | */
62 |
63 | 'queue' => [
64 | 'status' => false,
65 | 'name' => 'default',
66 | 'connection' => null
67 | ],
68 |
69 | /*
70 | |--------------------------------------------------------------------------
71 | | Groups
72 | |--------------------------------------------------------------------------
73 | |
74 | | You can group some entities and perform some actions on them.
75 | |
76 | | Example:
77 | | 'groups' => [
78 | | 'group-1' => [
79 | | [
80 | | 'model' => \App\Models\User::class,
81 | | 'entities' => [
82 | | 'featured', 'latest', 'popular'
83 | | ],
84 | | ],
85 | | [
86 | | 'model' => \App\Models\Article::class,
87 | | 'entities' => [],
88 | | ]
89 | | ],
90 | |
91 | | 'group-2' => [
92 | | [
93 | | 'model' => \App\Models\Product::class,
94 | | 'entities' => [
95 | | 'latest', 'popular'
96 | | ],
97 | | ],
98 | | [
99 | | 'model' => \App\Models\Article::class,
100 | | 'entities' => [],
101 | | ]
102 | | ],
103 | | ],
104 | |
105 | */
106 |
107 | 'groups' => [],
108 | ];
109 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | src/
7 |
8 |
9 |
10 |
11 | tests
12 |
13 |
14 |
15 |
16 |
17 | ./src
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/Actions/DeleteCacheAction.php:
--------------------------------------------------------------------------------
1 | models) > 1) {
13 | foreach ($data->models as $model) {
14 | $this->deleteAll($model);
15 | }
16 | }
17 | else {
18 | $model = $data->models[0];
19 |
20 | empty($data->entities)
21 | ? $this->deleteAll($model)
22 | : $this->delete($model, $data->entities);
23 | }
24 | }
25 |
26 | /**
27 | * @param \Mostafaznv\LaraCache\Traits\LaraCache $model
28 | * @return void
29 | */
30 | private function deleteAll(string $model): void
31 | {
32 | $entities = [];
33 |
34 | foreach ($model::cacheEntities() as $entity) {
35 | $entities[] = $entity->name;
36 | }
37 |
38 | $this->delete($model, $entities);
39 | }
40 |
41 | /**
42 | * @param \Mostafaznv\LaraCache\Traits\LaraCache $model
43 | * @param array $entities
44 | * @return void
45 | */
46 | private function delete(string $model, array $entities): void
47 | {
48 | $this->console?->warn(
49 | sprintf('>> Deleting cache entities in [%s] model', class_basename($model))
50 | );
51 |
52 | foreach ($entities as $entity) {
53 | $this->console?->line('— ' . $this->title($entity));
54 |
55 | $model::cache()->delete($entity);
56 |
57 | $this->console?->info('Deleted');
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Actions/DeleteGroupCacheAction.php:
--------------------------------------------------------------------------------
1 | group($group);
12 |
13 | foreach ($group as $item) {
14 | DeleteCacheAction::make($this->console)->run($item);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Actions/Support/UpdateDeleteCache.php:
--------------------------------------------------------------------------------
1 | makeCommandDataFromGroupItem($item, $groupName);
49 | }
50 |
51 | return $data;
52 | }
53 | else {
54 | throw CacheGroupValueIsNotValid::make($groupName);
55 | }
56 | }
57 |
58 | private function makeCommandDataFromGroupItem(mixed $item, string $groupName): CommandData
59 | {
60 | if (isset($item['model']) and is_string($item['model']) and isset($item['entities'])) {
61 | return CommandData::make(
62 | models: [$item['model']],
63 | entities: $item['entities']
64 | );
65 | }
66 | else {
67 | throw CacheGroupValueIsNotValid::make($groupName);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Actions/UpdateCacheAction.php:
--------------------------------------------------------------------------------
1 | models) > 1) {
13 | foreach ($data->models as $model) {
14 | $this->updateAll($model);
15 | }
16 | }
17 | else {
18 | $model = $data->models[0];
19 |
20 | empty($data->entities)
21 | ? $this->updateAll($model)
22 | : $this->update($model, $data->entities);
23 | }
24 | }
25 |
26 | /**
27 | * @param \Mostafaznv\LaraCache\Traits\LaraCache $model
28 | * @return void
29 | */
30 | private function updateAll(string $model): void
31 | {
32 | $entities = [];
33 |
34 | foreach ($model::cacheEntities() as $entity) {
35 | $entities[] = $entity->name;
36 | }
37 |
38 | $this->update($model, $entities);
39 | }
40 |
41 | /**
42 | * @param \Mostafaznv\LaraCache\Traits\LaraCache $model
43 | * @param array $entities
44 | * @return void
45 | */
46 | private function update(string $model, array $entities): void
47 | {
48 | $this->console?->warn(
49 | sprintf('>> Updating cache entities in [%s] model', class_basename($model))
50 | );
51 |
52 | foreach ($entities as $entity) {
53 | $this->console?->line('— ' . $this->title($entity));
54 |
55 | $model::cache()->update($entity);
56 |
57 | $this->console?->info('Updated');
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Actions/UpdateGroupCacheAction.php:
--------------------------------------------------------------------------------
1 | group($group);
12 |
13 | foreach ($group as $item) {
14 | UpdateCacheAction::make($this->console)->run($item);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Cache.php:
--------------------------------------------------------------------------------
1 | retrieve($name);
17 |
18 | if ($withCacheData) {
19 | return $cache;
20 | }
21 |
22 | return $cache->value;
23 | }
24 |
25 | public function update(string $name): CacheData
26 | {
27 | $this->updateLaraCacheModelsList();
28 |
29 | return $this->updateCacheEntity($name);
30 | }
31 |
32 | public function updateAll(): void
33 | {
34 | $this->updateLaraCacheModelsList();
35 |
36 | foreach ($this->model::cacheEntities() as $entity) {
37 | $this->updateCacheEntity(
38 | name: $entity->name,
39 | entity: $entity
40 | );
41 | }
42 | }
43 |
44 | public function delete(string $name, bool $forever = false): CacheData
45 | {
46 | return $this->deleteCacheEntity($name, $forever);
47 | }
48 |
49 | public function deleteAll(bool $forever = false): void
50 | {
51 | foreach ($this->model::cacheEntities() as $entity) {
52 | $this->deleteCacheEntity($entity->name, $forever, $entity);
53 | }
54 | }
55 |
56 | public function refresh(CacheEvent $event): void
57 | {
58 | if ($this->model::$isEnabled) {
59 | $this->updateLaraCacheModelsList();
60 |
61 | foreach ($this->model::cacheEntities() as $entity) {
62 | if ($entity->isQueueable) {
63 | $this->initCache($entity, $entity->getTtl());
64 |
65 | RefreshCache::dispatch($this->model, $entity->name, $event)
66 | ->onConnection($entity->queueConnection)
67 | ->onQueue($entity->queueName);
68 | }
69 | else {
70 | $this->updateCacheEntity($entity->name, $event, $entity);
71 | }
72 | }
73 | }
74 | }
75 |
76 | public function disable(): void
77 | {
78 | $this->model::$isEnabled = false;
79 | }
80 |
81 | public function enable(): void
82 | {
83 | $this->model::$isEnabled = true;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/CacheEntity.php:
--------------------------------------------------------------------------------
1 | name = $name;
119 | $this->driver = config('laracache.driver') ?? config('cache.default');
120 |
121 | $queue = config('laracache.queue');
122 |
123 | if (is_array($queue)) {
124 | $this->isQueueable = $queue['status'] ?? false;
125 | $this->queueName = $queue['name'] ?? 'default';
126 | $this->queueConnection = $queue['connection'] ?? config('queue.default');
127 | }
128 | else {
129 | $this->isQueueable = (bool)$queue;
130 | $this->queueName = 'default';
131 | $this->queueConnection = config('queue.default');
132 | }
133 | }
134 |
135 | /**
136 | * Create a new cache entity.
137 | *
138 | * @param string $name
139 | * @return CacheEntity
140 | */
141 | public static function make(string $name): CacheEntity
142 | {
143 | return new static($name);
144 | }
145 |
146 | /**
147 | * Specify custom driver for cache entity
148 | *
149 | * @param string $driver
150 | * @return $this
151 | */
152 | public function setDriver(string $driver): CacheEntity
153 | {
154 | $this->driver = $driver;
155 |
156 | return $this;
157 | }
158 |
159 | /**
160 | * Specify if cache operation should perform in background or not
161 | *
162 | * @param bool $status
163 | * @param string $onConnection
164 | * @param string $onQueue
165 | * @return $this
166 | */
167 | public function isQueueable(bool $status = true, string $onConnection = '', string $onQueue = ''): CacheEntity
168 | {
169 | $this->isQueueable = $status;
170 |
171 | if ($onConnection) {
172 | $this->queueConnection = $onConnection;
173 | }
174 |
175 | if ($onQueue) {
176 | $this->queueName = $onQueue;
177 | }
178 |
179 | return $this;
180 | }
181 |
182 | /**
183 | * Specify that the cache should refresh after create a model instance
184 | *
185 | * @param bool $status
186 | * @return $this
187 | */
188 | public function refreshAfterCreate(bool $status = true): CacheEntity
189 | {
190 | $this->refreshAfterCreate = $status;
191 |
192 | return $this;
193 | }
194 |
195 | /**
196 | * Specify that the cache should refresh after update a model instance
197 | *
198 | * @param bool $status
199 | * @return $this
200 | */
201 | public function refreshAfterUpdate(bool $status = true): CacheEntity
202 | {
203 | $this->refreshAfterUpdate = $status;
204 |
205 | return $this;
206 | }
207 |
208 | /**
209 | * Specify that the cache should refresh after delete a model instance
210 | *
211 | * @param bool $status
212 | * @return $this
213 | */
214 | public function refreshAfterDelete(bool $status = true): CacheEntity
215 | {
216 | $this->refreshAfterDelete = $status;
217 |
218 | return $this;
219 | }
220 |
221 | /**
222 | * Specify that the cache should refresh after restore a model instance
223 | *
224 | * @param bool $status
225 | * @return $this
226 | */
227 | public function refreshAfterRestore(bool $status = true): CacheEntity
228 | {
229 | $this->refreshAfterRestore = $status;
230 |
231 | return $this;
232 | }
233 |
234 | /**
235 | * Specify that cache entity should exist there forever
236 | *
237 | * @return $this
238 | */
239 | public function forever(): CacheEntity
240 | {
241 | $this->forever = true;
242 | $this->validForRestOfDay = false;
243 | $this->validForRestOfWeek = false;
244 | $this->ttl = 0;
245 |
246 | return $this;
247 | }
248 |
249 | /**
250 | * Specify that cache entity should exist there till end of day
251 | *
252 | * @return $this
253 | */
254 | public function validForRestOfDay(): CacheEntity
255 | {
256 | $this->validForRestOfDay = true;
257 | $this->validForRestOfWeek = false;
258 | $this->forever = false;
259 | $this->ttl = 0;
260 |
261 | return $this;
262 | }
263 |
264 | /**
265 | * Specify that cache entity should exist there till end of week
266 | *
267 | * @return $this
268 | */
269 | public function validForRestOfWeek(): CacheEntity
270 | {
271 | $this->validForRestOfDay = false;
272 | $this->validForRestOfWeek = true;
273 | $this->forever = false;
274 | $this->ttl = 0;
275 |
276 | return $this;
277 | }
278 |
279 | /**
280 | * Specify cache time to live in second
281 | *
282 | * @param int $seconds
283 | * @return $this
284 | */
285 | public function ttl(int $seconds): CacheEntity
286 | {
287 | $this->ttl = max($seconds, 0);
288 | $this->forever = $this->ttl === 0;
289 | $this->validForRestOfDay = false;
290 | $this->validForRestOfWeek = false;
291 |
292 | return $this;
293 | }
294 |
295 | /**
296 | * Set default value of cache entity
297 | *
298 | * @param mixed $defaultValue
299 | * @return $this
300 | */
301 | public function setDefault(mixed $defaultValue): CacheEntity
302 | {
303 | $this->default = $defaultValue;
304 |
305 | return $this;
306 | }
307 |
308 | /**
309 | * Get TTL
310 | *
311 | * @return int
312 | * @internal
313 | */
314 | public function getTtl(): int
315 | {
316 | if ($this->forever) {
317 | return 0;
318 | }
319 |
320 | if ($this->validForRestOfDay) {
321 | return day_ending_seconds();
322 | }
323 |
324 | if ($this->validForRestOfWeek) {
325 | return week_ending_seconds();
326 | }
327 |
328 | return $this->ttl;
329 | }
330 |
331 | /**
332 | * Specify cache closure
333 | *
334 | * @param Closure $closure
335 | * @return $this
336 | */
337 | public function cache(Closure $closure): CacheEntity
338 | {
339 | $this->cacheClosure = $closure;
340 |
341 | return $this;
342 | }
343 | }
344 |
--------------------------------------------------------------------------------
/src/Commands/DeleteCacheCommand.php:
--------------------------------------------------------------------------------
1 | option('model');
18 | $entities = $this->option('entity');
19 |
20 | DeleteCacheAction::make($this)->run(
21 | CommandData::make($models, $entities)
22 | );
23 |
24 |
25 | return SymfonyCommand::SUCCESS;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Commands/DeleteGroupCacheCommand.php:
--------------------------------------------------------------------------------
1 | run(
17 | $this->argument('group')
18 | );
19 |
20 | return SymfonyCommand::SUCCESS;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Commands/UpdateCacheCommand.php:
--------------------------------------------------------------------------------
1 | option('model');
18 | $entities = $this->option('entity');
19 |
20 | UpdateCacheAction::make($this)->run(
21 | CommandData::make($models, $entities)
22 | );
23 |
24 |
25 | return SymfonyCommand::SUCCESS;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Commands/UpdateGroupCacheCommand.php:
--------------------------------------------------------------------------------
1 | run(
17 | $this->argument('group')
18 | );
19 |
20 | return SymfonyCommand::SUCCESS;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/DTOs/CacheData.php:
--------------------------------------------------------------------------------
1 | addSeconds($ttl)->unix() : null;
20 |
21 | return new static($status, $expiration, $value);
22 | }
23 |
24 | public static function fromCache(CacheEntity $entity, string $prefix, int $ttl = 0): self
25 | {
26 | $name = $prefix . '.' . $entity->name;
27 | $value = Cache::store($entity->driver)->get($name, $entity->default);
28 |
29 | if ($value === $entity->default) {
30 | return self::make(CacheStatus::NOT_CREATED(), $ttl, $entity->default);
31 | }
32 |
33 | return $value;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/DTOs/CacheEvent.php:
--------------------------------------------------------------------------------
1 | 1 and count($entities)) {
22 | throw EntityIsNotAllowed::make();
23 | }
24 |
25 | $m = [];
26 |
27 | foreach ($models as $model) {
28 | $m[] = self::model($model);
29 | }
30 |
31 | return new static($m, $entities);
32 | }
33 |
34 |
35 | private static function model(?string $model): string
36 | {
37 | if ($model) {
38 | if (self::modelExists($model)) {
39 | return $model;
40 | }
41 |
42 | // @codeCoverageIgnoreStart
43 | $defaultPath = "App\\Models\\$model";
44 |
45 | if (self::modelExists($defaultPath)) {
46 | return $defaultPath;
47 | }
48 | // @codeCoverageIgnoreEnd
49 | }
50 |
51 | throw ModelDoestNotExist::make($model);
52 | }
53 |
54 | private static function modelExists(string $model): bool
55 | {
56 | if (class_exists($model)) {
57 | if (method_exists($model, 'cache')) {
58 | return true;
59 | }
60 |
61 | throw ModelDoesntUseLaraCacheTrait::make($model);
62 | }
63 |
64 | return false;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Exceptions/CacheEntityDoesNotExist.php:
--------------------------------------------------------------------------------
1 | model);
25 |
26 | $model->cache()->update($this->name, $this->event);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Jobs/UpdateLaraCacheModelsList.php:
--------------------------------------------------------------------------------
1 | driver = config('laracache.driver') ?: config('cache.default');
24 | $this->key = self::LARACACHE_MODELS_LIST;
25 |
26 | $this->connection = config('laracache.queue.connection', config('queue.default'));
27 | $this->queue = config('laracache.queue.name', 'default');
28 | }
29 |
30 |
31 | public function handle(): void
32 | {
33 | $list = Cache::driver($this->driver)->get($this->key, []);
34 | $list[] = $this->model;
35 |
36 | Cache::driver($this->driver)->forever(
37 | key: 'laracache.models',
38 | value: array_unique($list)
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/LaraCache.php:
--------------------------------------------------------------------------------
1 | update($name, $event, $entity);
22 | }
23 |
24 | /**
25 | * Update All Cache Entities
26 | *
27 | * @param mixed $model
28 | */
29 | public function updateAll(mixed $model = null): void
30 | {
31 | if ($model) {
32 | $model::cache()->updateAll();
33 | }
34 | else {
35 | $list = self::list();
36 |
37 | /** @var mixed $model */
38 | foreach ($list as $model => $entities) {
39 | $model::cache()->updateAll();
40 | }
41 | }
42 | }
43 |
44 | /**
45 | * Delete Cache Entity
46 | *
47 | * @param mixed $model
48 | * @param string $name
49 | * @param bool $forever
50 | * @return mixed
51 | */
52 | public function delete(mixed $model, string $name, bool $forever = false): mixed
53 | {
54 | return $model::cache()->delete($name, $forever);
55 | }
56 |
57 | /**
58 | * Delete All Cache Entities
59 | *
60 | * @param mixed $model
61 | * @param bool $forever
62 | */
63 | public function deleteAll(mixed $model = null, bool $forever = false): void
64 | {
65 | if ($model) {
66 | $model::cache()->deleteAll($forever);
67 | }
68 | else {
69 | $list = self::list();
70 |
71 | /** @var mixed $model */
72 | foreach ($list as $model => $entities) {
73 | $model::cache()->deleteAll($forever);
74 | }
75 | }
76 | }
77 |
78 | /**
79 | * Retrieve Cache
80 | *
81 | * @param mixed $model
82 | * @param string $name
83 | * @param bool $withCacheData
84 | * @return mixed
85 | */
86 | public function retrieve(mixed $model, string $name, bool $withCacheData = false): mixed
87 | {
88 | return $model::cache()->get($name, $withCacheData);
89 | }
90 |
91 | /**
92 | * Disable refresh cache on all events
93 | *
94 | * @param $model
95 | */
96 | public function disable($model): void
97 | {
98 | $model::cache()->disable();
99 | }
100 |
101 | /**
102 | * Enable refresh cache on all events
103 | *
104 | * @param $model
105 | */
106 | public function enable($model): void
107 | {
108 | $model::cache()->enable();
109 | }
110 |
111 | /**
112 | * Retrieve List of All Cache Entities
113 | *
114 | * @return array
115 | */
116 | public function list(): array
117 | {
118 | $laracacheListKey = config('laracache.laracache-list');
119 | $driver = config('laracache.driver') ?? config('cache.default');
120 |
121 | return Cache::store($driver)->get($laracacheListKey, []);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/LaraCacheServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->runningInConsole()) {
16 | $this->publishes([__DIR__ . '/../config/config.php' => config_path('laracache.php')], 'config');
17 | }
18 |
19 | $this->commands([
20 | UpdateCacheCommand::class,
21 | DeleteCacheCommand::class,
22 | UpdateGroupCacheCommand::class,
23 | DeleteGroupCacheCommand::class
24 | ]);
25 | }
26 |
27 | public function register(): void
28 | {
29 | $this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'laracache');
30 |
31 | $this->app->bind('laracache', function () {
32 | return new LaraCache;
33 | });
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Observers/LaraCacheObserver.php:
--------------------------------------------------------------------------------
1 | cache()->refresh(CacheEvent::CREATED());
12 | }
13 |
14 | public function updated(mixed $model): void
15 | {
16 | if (!$this->isRestored($model)) {
17 | $model->cache()->refresh(CacheEvent::UPDATED());
18 | }
19 | }
20 |
21 | public function deleted(mixed $model): void
22 | {
23 | $model->cache()->refresh(CacheEvent::DELETED());
24 | }
25 |
26 | public function restored(mixed $model): void
27 | {
28 | $model->cache()->refresh(CacheEvent::RESTORED());
29 | }
30 |
31 | private function isRestored(mixed $model): bool
32 | {
33 | return $model->wasChanged('deleted_at')
34 | and is_null($model->deleted_at)
35 | and !$model->originalIsEquivalent('deleted_at');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Traits/InteractsWithCache.php:
--------------------------------------------------------------------------------
1 | prefix = Str::kebab(class_basename($model));
24 | $this->model = $model;
25 | $this->laracacheListKey = config('laracache.laracache-list');
26 | }
27 |
28 |
29 | private function getEntityFullName(CacheEntity $entity): string
30 | {
31 | return $this->prefix . '.' . $entity->name;
32 | }
33 |
34 | private function findCacheEntity(string $name, ?CacheEntity $entity = null): CacheEntity
35 | {
36 | if ($entity) {
37 | return $entity;
38 | }
39 |
40 | foreach ($this->model::cacheEntities() as $cacheEntity) {
41 | if ($cacheEntity->name === $name) {
42 | return $cacheEntity;
43 | }
44 | }
45 |
46 | throw CacheEntityDoesNotExist::make($name, $this->model);
47 | }
48 |
49 | private function entityIsCallable(CacheEntity $entity, ?CacheEvent $event = null): bool
50 | {
51 | return is_null($event)
52 | or ($event->equals(CacheEvent::CREATED()) and $entity->refreshAfterCreate)
53 | or ($event->equals(CacheEvent::UPDATED()) and $entity->refreshAfterUpdate)
54 | or ($event->equals(CacheEvent::DELETED()) and $entity->refreshAfterDelete)
55 | or ($event->equals(CacheEvent::RESTORED()) and $entity->refreshAfterRestore);
56 | }
57 |
58 | private function callCacheClosure(CacheEntity $entity, int $ttl, bool $delete = false): CacheData
59 | {
60 | if ($delete) {
61 | return CacheData::make(CacheStatus::DELETED(), $ttl, $entity->default);
62 | }
63 |
64 | $value = $entity->cacheClosure ? call_user_func($entity->cacheClosure) : null;
65 |
66 | return CacheData::make(
67 | status: CacheStatus::CREATED(),
68 | ttl: $ttl,
69 | value: $value ?: $entity->default
70 | );
71 | }
72 |
73 | private function updateCacheEntitiesList(CacheEntity $entity): void
74 | {
75 | $name = $this->getEntityFullName($entity);
76 | $list = Cache::store($entity->driver)->get($this->laracacheListKey);
77 |
78 | if (is_array($list)) {
79 | if (isset($list[$this->model]) and is_array($list[$this->model])) {
80 | if (!in_array($name, $list[$this->model])) {
81 | $list[$this->model][] = $name;
82 | }
83 | }
84 | else {
85 | $list[$this->model] = [$name];
86 | }
87 | }
88 | else {
89 | $list = [
90 | $this->model => [$name]
91 | ];
92 | }
93 |
94 | Cache::store($entity->driver)->forever($this->laracacheListKey, $list);
95 | }
96 |
97 | private function putCacheIntoCacheStorage(CacheData $cache, string $driver, string $name, int $ttl): bool
98 | {
99 | if (is_null($cache->expiration)) {
100 | return Cache::store($driver)->forever($name, $cache);
101 | }
102 |
103 | return Cache::store($driver)->put($name, $cache, $ttl);
104 | }
105 |
106 | private function initCache(CacheEntity $entity, int $ttl): void
107 | {
108 | $name = $this->getEntityFullName($entity);
109 | $cache = CacheData::fromCache($entity, $this->prefix, $ttl);
110 |
111 | if ($cache->status->equals(CacheStatus::NOT_CREATED())) {
112 | $cache->value = $entity->default;
113 | }
114 |
115 | $cache->status = CacheStatus::CREATING();
116 |
117 | $this->putCacheIntoCacheStorage($cache, $entity->driver, $name, $ttl);
118 | }
119 |
120 | private function storeCache(CacheData $cache, CacheEntity $entity, int $ttl): void
121 | {
122 | $name = $this->getEntityFullName($entity);
123 |
124 | $this->putCacheIntoCacheStorage($cache, $entity->driver, $name, $ttl);
125 | $this->updateCacheEntitiesList($entity);
126 | }
127 |
128 | private function updateLaraCacheModelsList(): void
129 | {
130 | UpdateLaraCacheModelsList::dispatch($this->model);
131 | }
132 |
133 | private function updateCacheEntity(string $name, ?CacheEvent $event = null, CacheEntity $entity = null): CacheData
134 | {
135 | $entity = $this->findCacheEntity($name, $entity);
136 |
137 | if ($this->entityIsCallable($entity, $event)) {
138 | $ttl = $entity->getTtl();
139 |
140 | $this->initCache($entity, $ttl);
141 | $cache = $this->callCacheClosure($entity, $ttl);
142 | $this->storeCache($cache, $entity, $ttl);
143 |
144 | return $cache;
145 | }
146 |
147 | return CacheData::fromCache($entity, $this->prefix);
148 | }
149 |
150 | private function deleteCacheEntity(string $name, bool $deleteForever = false, CacheEntity $entity = null): CacheData
151 | {
152 | $entity = $this->findCacheEntity($name, $entity);
153 | $ttl = !$deleteForever ? $entity->getTtl() : 0;
154 | $cache = $this->callCacheClosure($entity, $ttl, true);
155 | $this->storeCache($cache, $entity, $ttl);
156 |
157 | return $cache;
158 | }
159 |
160 | private function retrieve(string $name): CacheData
161 | {
162 | $entity = $this->findCacheEntity($name);
163 | $cache = CacheData::fromCache($entity, $this->prefix);
164 |
165 | if ($cache->status->equals(CacheStatus::NOT_CREATED())) {
166 | if ($entity->isQueueable) {
167 | $this->initCache($entity, $entity->getTtl());
168 |
169 | RefreshCache::dispatch($this->model, $entity->name, CacheEvent::RETRIEVED())
170 | ->onConnection($entity->queueConnection)
171 | ->onQueue($entity->queueName);
172 |
173 | return CacheData::fromCache($entity, $this->prefix, $entity->ttl);
174 | }
175 |
176 | return $this->updateCacheEntity($name, null, $entity);
177 | }
178 |
179 | return $cache;
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/src/Traits/LaraCache.php:
--------------------------------------------------------------------------------
1 | value;
17 | }
18 |
19 | public function equals(self $other): bool
20 | {
21 | return get_class($this) === get_class($other) and $this->getValue() === $other->getValue();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Utils/Helpers.php:
--------------------------------------------------------------------------------
1 | clone()->addWeeks($weeks);
16 | $end = $end->endOfWeek(config('laracache.last-day-of-week'));
17 |
18 | return $end->endOfDay()->diffInSeconds($now, true);
19 | }
20 | }
21 |
22 | if (!function_exists('day_ending_seconds')) {
23 | /**
24 | * Calculate time to end of the day in seconds
25 | *
26 | * @param int $days
27 | * @return int
28 | */
29 | function day_ending_seconds(int $days = 0): int
30 | {
31 | $days = max($days, 0);
32 |
33 | $now = now();
34 | $end = $now->clone()->addDays($days);
35 |
36 | return $end->endOfDay()->diffInSeconds($now, true);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/Feature/CacheDefaultValueTest.php:
--------------------------------------------------------------------------------
1 | get('empty.number');
7 |
8 | expect($cache)->toBe('empty value');
9 | });
10 |
11 | it('will return default value if cache content is an empty array', function() {
12 | $cache = TestModel::cache()->get('empty.array');
13 |
14 | expect($cache)->toBe('empty value');
15 | });
16 |
17 | it('will return default value if cache content is an empty string', function() {
18 | $cache = TestModel::cache()->get('empty.string');
19 |
20 | expect($cache)->toBe('empty value');
21 | });
22 |
23 | it('will return default value if cache content is false', function() {
24 | $cache = TestModel::cache()->get('empty.bool');
25 |
26 | expect($cache)->toBe('empty value');
27 | });
28 |
29 | it('will return default value if cache content is null', function() {
30 | $cache = TestModel::cache()->get('empty.null');
31 |
32 | expect($cache)->toBe('empty value');
33 | });
34 |
--------------------------------------------------------------------------------
/tests/Feature/CacheEntityTest.php:
--------------------------------------------------------------------------------
1 | entity = CacheEntity::make('test-name');
7 | });
8 |
9 |
10 | it('will make cache entity using factory', function() {
11 | expect($this->entity)->toBeInstanceOf(CacheEntity::class)
12 | ->name->toBe('test-name');
13 | });
14 |
15 | it('will set driver if to default cache driver if laracache.driver is null', function() {
16 | config()->set('cache.default', 'fake-driver');
17 |
18 | $entity = CacheEntity::make('test-name');
19 |
20 | expect($entity->driver)->toBe('fake-driver');
21 | });
22 |
23 | it('will set driver if laracache.driver is set', function() {
24 | config()->set('laracache.driver', 'fake-driver');
25 |
26 | $entity = CacheEntity::make('test-name');
27 |
28 | expect($entity->driver)->toBe('fake-driver');
29 | });
30 |
31 | it('will set is-queueable by default if laracache.queue is boolean', function() {
32 | expect($this->entity->isQueueable)->toBeFalse();
33 |
34 | config()->set('laracache.queue', true);
35 |
36 | $entity = CacheEntity::make('test-name');
37 |
38 | expect($entity->isQueueable)->toBeTrue();
39 | });
40 |
41 | it('will set is-queueable by default', function() {
42 | expect($this->entity->isQueueable)->toBeFalse();
43 |
44 | config()->set('laracache.queue.status', true);
45 |
46 | $entity = CacheEntity::make('test-name');
47 |
48 | expect($entity->isQueueable)->toBeTrue();
49 | });
50 |
51 | it('will set custom queue status', function() {
52 | expect($this->entity->isQueueable)->toBeFalse();
53 |
54 | $this->entity->isQueueable();
55 | expect($this->entity->isQueueable)->toBeTrue();
56 |
57 | $this->entity->isQueueable(false);
58 | expect($this->entity->isQueueable)->toBeFalse();
59 | });
60 |
61 | it('will set queue name and connection by default', function() {
62 | expect($this->entity->queueName)->toBe('default')
63 | ->and($this->entity->queueConnection)->toBe('database');
64 | });
65 |
66 | it('will set queue name and connection by default with deprecated config file', function() {
67 | config()->set('laracache.queue', true);
68 |
69 | $entity = CacheEntity::make('test-name');
70 |
71 | expect($entity->queueName)->toBe('default')
72 | ->and($entity->queueConnection)->toBe('database');
73 | });
74 |
75 | it('will set custom queue name and connection using config file', function() {
76 | expect($this->entity->queueName)->toBe('default')
77 | ->and($this->entity->queueConnection)->toBe('database');
78 |
79 | config()->set('laracache.queue.name', 'test-queue');
80 | config()->set('laracache.queue.connection', 'test-connection');
81 |
82 | $entity = CacheEntity::make('test-name');
83 |
84 | expect($entity->queueName)->toBe('test-queue')
85 | ->and($entity->queueConnection)->toBe('test-connection');
86 | });
87 |
88 | it('will set custom queue name and connection using entity method', function() {
89 | expect($this->entity->queueName)->toBe('default')
90 | ->and($this->entity->queueConnection)->toBe('database');
91 |
92 | $entity = CacheEntity::make('test-name')
93 | ->isQueueable(true, 'test-connection', 'test-queue');
94 |
95 | expect($entity->queueName)->toBe('test-queue')
96 | ->and($entity->queueConnection)->toBe('test-connection');
97 | });
98 |
99 | it('will set specific driver for entity', function() {
100 | expect($this->entity->driver)->toBe('array');
101 |
102 | $this->entity->setDriver('fake-driver');
103 |
104 | expect($this->entity->driver)->toBe('fake-driver');
105 | });
106 |
107 | it('will set refresh after create correctly', function() {
108 | expect($this->entity->refreshAfterCreate)->toBeTrue();
109 |
110 | $this->entity->refreshAfterCreate(false);
111 | expect($this->entity->refreshAfterCreate)->toBeFalse();
112 |
113 | $this->entity->refreshAfterCreate(true);
114 | expect($this->entity->refreshAfterCreate)->toBeTrue();
115 | });
116 |
117 | it('will set refresh after update correctly', function() {
118 | expect($this->entity->refreshAfterUpdate)->toBeTrue();
119 |
120 | $this->entity->refreshAfterUpdate(false);
121 | expect($this->entity->refreshAfterUpdate)->toBeFalse();
122 |
123 | $this->entity->refreshAfterUpdate(true);
124 | expect($this->entity->refreshAfterUpdate)->toBeTrue();
125 | });
126 |
127 | it('will set refresh after delete correctly', function() {
128 | expect($this->entity->refreshAfterDelete)->toBeTrue();
129 |
130 | $this->entity->refreshAfterDelete(false);
131 | expect($this->entity->refreshAfterDelete)->toBeFalse();
132 |
133 | $this->entity->refreshAfterDelete(true);
134 | expect($this->entity->refreshAfterDelete)->toBeTrue();
135 | });
136 |
137 | it('will set refresh after restore correctly', function() {
138 | expect($this->entity->refreshAfterRestore)->toBeTrue();
139 |
140 | $this->entity->refreshAfterRestore(false);
141 | expect($this->entity->refreshAfterRestore)->toBeFalse();
142 |
143 | $this->entity->refreshAfterRestore(true);
144 | expect($this->entity->refreshAfterRestore)->toBeTrue();
145 | });
146 |
147 | it('will set forever property correctly', function() {
148 | $this->entity->validForRestOfDay();
149 |
150 | expect($this->entity)
151 | ->forever->toBeFalse()
152 | ->validForRestOfDay->toBeTrue()
153 | ->validForRestOfWeek->toBeFalse()
154 | ->ttl->toBe(0);
155 |
156 | $this->entity->forever();
157 |
158 | expect($this->entity)
159 | ->forever->toBeTrue()
160 | ->validForRestOfDay->toBeFalse()
161 | ->validForRestOfWeek->toBeFalse()
162 | ->ttl->toBe(0);
163 | });
164 |
165 | it('will set cache expire to till the end of day', function() {
166 | expect($this->entity)
167 | ->forever->toBeTrue()
168 | ->validForRestOfDay->toBeFalse();
169 |
170 | $this->entity->validForRestOfDay();
171 |
172 | expect($this->entity)
173 | ->forever->toBeFalse()
174 | ->validForRestOfDay->toBeTrue()
175 | ->validForRestOfWeek->toBeFalse()
176 | ->ttl->toBe(0);
177 | });
178 |
179 | it('will set cache expire to till the week of day', function() {
180 | expect($this->entity)
181 | ->forever->toBeTrue()
182 | ->validForRestOfWeek->toBeFalse();
183 |
184 | $this->entity->validForRestOfWeek();
185 |
186 | expect($this->entity)
187 | ->forever->toBeFalse()
188 | ->validForRestOfDay->toBeFalse()
189 | ->validForRestOfWeek->toBeTrue()
190 | ->ttl->toBe(0);
191 | });
192 |
193 | it('will set ttl correctly', function() {
194 | expect($this->entity->forever)->toBeTrue();
195 |
196 | $this->entity->ttl(120);
197 |
198 | expect($this->entity)
199 | ->forever->toBeFalse()
200 | ->validForRestOfDay->toBeFalse()
201 | ->validForRestOfWeek->toBeFalse()
202 | ->ttl->toBe(120);
203 | });
204 |
205 | it('will enable forever flag if ttl is zero', function() {
206 | $this->entity->validForRestOfDay();
207 |
208 | expect($this->entity)
209 | ->forever->toBeFalse()
210 | ->validForRestOfDay->toBeTrue();
211 |
212 | $this->entity->ttl(0);
213 |
214 | expect($this->entity)
215 | ->forever->toBeTrue()
216 | ->validForRestOfDay->toBeFalse()
217 | ->ttl->toBe(0);
218 | });
219 |
220 | it('will set cache default value', function() {
221 | expect($this->entity->default)->toBeNull();
222 |
223 | $this->entity->setDefault([]);
224 | expect($this->entity->default)->tobe([]);
225 |
226 | $this->entity->setDefault(0);
227 | expect($this->entity->default)->tobe(0);
228 |
229 | $object = new stdClass;
230 | $this->entity->setDefault($object);
231 | expect($this->entity->default)->tobe($object);
232 | });
233 |
234 | it('will set cache function correctly', function() {
235 | expect($this->entity->cacheClosure)->toBeNull();
236 |
237 | $this->entity->cache(function() {
238 | return 'test-value';
239 | });
240 |
241 | expect($this->entity->cacheClosure)->toBeInstanceOf(Closure::class);
242 |
243 | $this->entity->cache(fn() => 'return-value');
244 |
245 | expect($this->entity->cacheClosure)->toBeInstanceOf(Closure::class);
246 | });
247 |
--------------------------------------------------------------------------------
/tests/Feature/CacheExpirationTest.php:
--------------------------------------------------------------------------------
1 | freeze('2022-05-17 12:43:34');
8 | createModel();
9 | });
10 |
11 | it('will store cache entity forever', function() {
12 | $cache = TestModel::cache()->get('list.forever', true);
13 |
14 | expect($cache->value)->toHaveCount(1)
15 | ->and($cache->expiration)->toBeNull();
16 | });
17 |
18 | it('will store cache till end of day', function() {
19 | $cache = TestModel::cache()->get('list.day', true);
20 |
21 | expect($cache->value)->toHaveCount(1)
22 | ->and($cache->expiration)->toBe(1652831999);
23 | });
24 |
25 | it('will store cache till end of week', function() {
26 | $cache = TestModel::cache()->get('list.week', true);
27 |
28 | expect($cache->value)->toHaveCount(1)
29 | ->and($cache->expiration)->toBe(1653177599);
30 | });
31 |
32 | it('will store cache with ttl', function() {
33 | $cache = TestModel::cache()->get('list.ttl', true);
34 |
35 | expect($cache->value)->toHaveCount(1)
36 | ->and($cache->expiration)->toBe(1652791534);
37 | });
38 |
--------------------------------------------------------------------------------
/tests/Feature/CraeteCacheTest.php:
--------------------------------------------------------------------------------
1 | get($name);
13 |
14 | expect($facadeCache)->toBeNull()
15 | ->and($cache)->toBeNull();
16 |
17 | createModel();
18 |
19 | $facadeCache = Cache::get($fullName);
20 | $cache = TestModel::cache()->get($name);
21 |
22 | expect($facadeCache->value->name)->toBe('test-name')
23 | ->and($cache)->name->toBe('test-name');
24 | });
25 |
26 | it('will not create cache after creating record if refresh-after-create flag is false', function() {
27 | $fullName = 'test-model.latest.no-create';
28 |
29 | $hasCache = Cache::has($fullName);
30 | expect($hasCache)->toBeFalse();
31 |
32 | $model = createModel();
33 |
34 | $hasCache = Cache::has($fullName);
35 | expect($hasCache)->toBeFalse();
36 |
37 |
38 | $model->name = 'new-test-name';
39 | $model->save();
40 |
41 | $hasCache = Cache::has($fullName);
42 | expect($hasCache)->toBeTrue();
43 | });
44 |
45 | it('will not create cache if cache is disabled', function() {
46 | TestModel::cache()->disable();
47 |
48 | $hasCache = Cache::has('latest');
49 | expect($hasCache)->toBeFalse();
50 |
51 | createModel();
52 |
53 | $hasCache = Cache::has('latest');
54 | expect($hasCache)->toBeFalse();
55 |
56 | TestModel::cache()->enable();
57 | });
58 |
59 | it('will not create cache if cache is disabled - facade', function() {
60 | LaraCache::disable(TestModel::class);
61 |
62 | $hasCache = Cache::has('latest');
63 | expect($hasCache)->toBeFalse();
64 |
65 | createModel();
66 |
67 | $hasCache = Cache::has('latest');
68 | expect($hasCache)->toBeFalse();
69 |
70 | LaraCache::enable(TestModel::class);
71 | });
72 |
73 | it('will store all cache entities in laracache.list', function() {
74 | $list = LaraCache::list();
75 | expect($list)->toBeArray()->toHaveCount(0);
76 |
77 | createModel();
78 |
79 | $list = LaraCache::list();
80 | expect($list)->toHaveCount(1)
81 | ->and($list[TestModel::class])->toHaveCount(16)
82 | ->and($list[TestModel::class])->toContain(
83 | 'test-model.list.ttl', 'test-model.empty.number', 'test-model.latest.no-update'
84 | );
85 | });
86 |
--------------------------------------------------------------------------------
/tests/Feature/DeleteCacheCommandTest.php:
--------------------------------------------------------------------------------
1 | 'test-model 1',
12 | 'content' => 'content 1'
13 | ],
14 | [
15 | 'name' => 'test-model 2',
16 | 'content' => 'content 2'
17 | ]
18 | ];
19 |
20 | foreach ($records as $record) {
21 | TestModel::query()->create($record);
22 | TestModel2::query()->create($record);
23 | }
24 |
25 | $this->created = CacheStatus::CREATED();
26 | $this->deleted = CacheStatus::DELETED();
27 | });
28 |
29 |
30 | it('will delete all entities of all models if multiple models sent to the action', function() {
31 | $names = [
32 | 'list.day', 'list.week', 'list.forever', 'latest'
33 | ];
34 |
35 | foreach ($names as $name) {
36 | $cache = TestModel::cache()->get($name, true);
37 | expect($cache->status->equals($this->created))->toBeTrue();
38 |
39 | $cache = TestModel2::cache()->get($name, true);
40 | expect($cache->status->equals($this->created))->toBeTrue();
41 | }
42 |
43 | Artisan::call('laracache:delete', [
44 | '--model' => [
45 | TestModel::class, TestModel2::class
46 | ]
47 | ]);
48 |
49 | foreach ($names as $name) {
50 | $cache = TestModel::cache()->get($name, true);
51 | expect($cache->status->equals($this->deleted))->toBeTrue();
52 |
53 | $cache = TestModel2::cache()->get($name, true);
54 | expect($cache->status->equals($this->deleted))->toBeTrue();
55 | }
56 | });
57 |
58 | it('will delete all entities of passed model if entities argument is empty', function() {
59 | $names = [
60 | 'list.day', 'list.week', 'list.forever', 'latest'
61 | ];
62 |
63 | foreach ($names as $name) {
64 | $cache = TestModel::cache()->get($name, true);
65 | expect($cache->status->equals($this->created))->toBeTrue();
66 | }
67 |
68 | Artisan::call('laracache:delete', [
69 | '-m' => [
70 | TestModel::class
71 | ]
72 | ]);
73 |
74 | foreach ($names as $name) {
75 | $cache = TestModel::cache()->get($name, true);
76 | expect($cache->status->equals($this->deleted))->toBeTrue();
77 | }
78 | });
79 |
80 | it('will delete only specified entities if one model is sent to the action', function() {
81 | $names = [
82 | 'list.week', 'list.forever', 'latest'
83 | ];
84 |
85 | $cache = TestModel::cache()->get('list.day', true);
86 | expect($cache->status->equals($this->created))->toBeTrue();
87 |
88 | Artisan::call('laracache:delete', [
89 | '--model' => [
90 | TestModel::class
91 | ],
92 | '--entity' => [
93 | 'list.day'
94 | ]
95 | ]);
96 |
97 | foreach ($names as $name) {
98 | $cache = TestModel::cache()->get($name, true);
99 | expect($cache->status->equals($this->created))->toBeTrue();
100 | }
101 |
102 | $cache = TestModel::cache()->get('list.day', true);
103 | expect($cache->status->equals($this->deleted))->toBeTrue();
104 | });
105 |
106 | it('will print the name of deleted cache entities in the console', function() {
107 | $entities = [
108 | 'list.week', 'list.forever', 'latest'
109 | ];
110 |
111 | $names = [
112 | "List Week\nDeleted", "List Forever\nDeleted", "Latest"
113 | ];
114 |
115 |
116 | Artisan::call('laracache:delete', [
117 | '--model' => [
118 | TestModel::class
119 | ],
120 | '--entity' => $entities
121 | ]);
122 |
123 | $output = Artisan::output();
124 |
125 | expect($output)
126 | ->toBeString()
127 | ->toContain($names[0])
128 | ->toContain($names[1])
129 | ->toContain($names[2]);
130 | });
131 |
--------------------------------------------------------------------------------
/tests/Feature/DeleteCacheTest.php:
--------------------------------------------------------------------------------
1 | freeze('2022-05-17 12:43:34');
13 |
14 | $this->model = createModel();
15 | });
16 |
17 | it('will throw exception if entity name is not defined during deleting cache', function() {
18 | $this->expectException(CacheEntityDoesNotExist::class);
19 |
20 | TestModel::cache()->delete('unknown-name');
21 | });
22 |
23 | it('will delete cache after deleting record', function() {
24 | $name = 'latest';
25 | $fullName = 'test-model.latest';
26 |
27 | $cache = TestModel::cache()->get($name);
28 | expect($cache->name)->toBe('test-name');
29 |
30 | $this->model->delete();
31 |
32 | $facadeCache = Cache::get($fullName);
33 | $cache = TestModel::cache()->get($name);
34 |
35 | expect($cache)->toBeNull()
36 | ->and($facadeCache->value)->toBeNull();
37 | });
38 |
39 | it('will not delete cache after deleting record if refresh-after-delete flag is false', function() {
40 | $name = 'latest.no-delete';
41 |
42 | $cache = TestModel::cache()->get($name);
43 | expect($cache->name)->toBe('test-name');
44 |
45 | $this->model->delete();
46 |
47 | $cache = TestModel::cache()->get($name);
48 | expect($cache->name)->toBe('test-name');
49 | });
50 |
51 | it('will delete cache manually', function() {
52 | $latestCache = TestModel::cache()->get('latest');
53 | $dayCache = TestModel::cache()->get('list.day', true);
54 |
55 | expect($latestCache->name)->toBe('test-name')
56 | ->and($dayCache->expiration)->toBe(1652831999);
57 |
58 | TestModel::cache()->delete('latest');
59 | TestModel::cache()->delete('list.day');
60 |
61 | $latestCache = TestModel::cache()->get('latest', true);
62 | $dayCache = TestModel::cache()->get('list.day', true);
63 |
64 | expect($latestCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
65 | ->and($latestCache->value)->toBeNull()
66 | ->and($latestCache->expiration)->toBeNull()
67 | ->and($dayCache->value)->toBeNull()
68 | ->and($dayCache->expiration)->toBe(1652831999);
69 | });
70 |
71 | it('will delete cache manually using facade', function() {
72 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest');
73 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day');
74 |
75 | expect($latestCache->name)->toBe('test-name')
76 | ->and($dayCache)->toHaveCount(1);
77 |
78 | LaraCache::delete(TestModel::class, 'latest');
79 | LaraCache::delete(TestModel::class, 'list.day');
80 |
81 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest', true);
82 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day', true);
83 |
84 | expect($latestCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
85 | ->and($latestCache->value)->toBeNull()
86 | ->and($latestCache->expiration)->toBeNull()
87 | ->and($dayCache->status->equals(CacheStatus::DELETED()))
88 | ->and($dayCache->value)->toBeNull()
89 | ->and($dayCache->expiration)->toBe(1652831999);
90 | });
91 |
92 | it('will delete cache manually forever', function() {
93 | $weekCache = TestModel::cache()->get('list.week', true);
94 | $dayCache = TestModel::cache()->get('list.day', true);
95 |
96 | expect($weekCache->expiration)->toBe(1653177599)
97 | ->and($dayCache->expiration)->toBe(1652831999);
98 |
99 | TestModel::cache()->delete('list.week');
100 | TestModel::cache()->delete('list.day', true);
101 |
102 | $weekCache = TestModel::cache()->get('list.week', true);
103 | $dayCache = TestModel::cache()->get('list.day', true);
104 |
105 | expect($weekCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
106 | ->and($weekCache->expiration)->toBe(1653177599)
107 | ->and($dayCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
108 | ->and($dayCache->expiration)->toBeNull();
109 | });
110 |
111 | it('will delete cache manually forever using facade', function() {
112 | $weekCache = LaraCache::retrieve(TestModel::class, 'list.week', true);
113 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day', true);
114 |
115 | expect($weekCache->expiration)->toBe(1653177599)
116 | ->and($dayCache->expiration)->toBe(1652831999);
117 |
118 | LaraCache::delete(TestModel::class, 'list.week');
119 | LaraCache::delete(TestModel::class, 'list.day', true);
120 |
121 | $weekCache = LaraCache::retrieve(TestModel::class, 'list.week', true);
122 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day', true);
123 |
124 | expect($weekCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
125 | ->and($weekCache->expiration)->toBe(1653177599)
126 | ->and($dayCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
127 | ->and($dayCache->expiration)->toBeNull();
128 | });
129 |
130 | it('will return default value after deleting cache item', function() {
131 | $cache = TestModel::cache()->get('static.number', true);
132 |
133 | expect($cache->status->equals(CacheStatus::CREATED()))->toBeTrue()
134 | ->and($cache->value)->toBe(1);
135 |
136 | TestModel::cache()->delete('static.number');
137 |
138 | $cache = TestModel::cache()->get('static.number', true);
139 |
140 | expect($cache->status->equals(CacheStatus::DELETED()))->toBeTrue()
141 | ->and($cache->value)->toBe('default-value');
142 | });
143 |
144 | it('will not delete other entities during deleting an entity manually', function() {
145 | $latestCache = TestModel::cache()->get('latest');
146 | $dayCache = TestModel::cache()->get('list.day');
147 |
148 | expect($latestCache->name)->toBe('test-name')
149 | ->and($dayCache)->toHaveCount(1);
150 |
151 | TestModel::cache()->delete('latest');
152 |
153 | $latestCache = TestModel::cache()->get('latest', true);
154 | $dayCache = TestModel::cache()->get('list.day', true);
155 |
156 | expect($latestCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
157 | ->and($latestCache->value)->toBeNull()
158 | ->and($dayCache->status->equals(CacheStatus::CREATED()))->toBeTrue()
159 | ->and($dayCache->value)->toHaveCount(1);
160 | });
161 |
162 | it('will delete all cache entities of a model', function() {
163 | $weekCache = TestModel::cache()->get('list.week', true);
164 | $dayCache = TestModel::cache()->get('list.day', true);
165 | $latestCache = TestModel::cache()->get('latest', true);
166 |
167 | expect($weekCache->expiration)->toBe(1653177599)
168 | ->and($dayCache->expiration)->toBe(1652831999)
169 | ->and($latestCache->expiration)->toBeNull();
170 |
171 | TestModel::cache()->deleteAll();
172 |
173 | $weekCache = TestModel::cache()->get('list.week', true);
174 | $dayCache = TestModel::cache()->get('list.day', true);
175 | $latestCache = TestModel::cache()->get('latest', true);
176 |
177 | expect($weekCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
178 | ->and($weekCache->expiration)->toBe(1653177599)
179 | ->and($weekCache->value)->toBeNull()
180 | ->and($dayCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
181 | ->and($dayCache->expiration)->toBe(1652831999)
182 | ->and($dayCache->value)->toBeNull()
183 | ->and($latestCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
184 | ->and($latestCache->expiration)->toBeNull()
185 | ->and($dayCache->value)->toBeNull();
186 | });
187 |
188 | it('will delete all cache entities of a model using facade', function() {
189 | $weekCache = LaraCache::retrieve(TestModel::class, 'list.week', true);
190 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day', true);
191 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest', true);
192 |
193 | expect($weekCache->expiration)->toBe(1653177599)
194 | ->and($dayCache->expiration)->toBe(1652831999)
195 | ->and($latestCache->expiration)->toBeNull();
196 |
197 | LaraCache::deleteAll(TestModel::class);
198 |
199 | $weekCache = LaraCache::retrieve(TestModel::class, 'list.week', true);
200 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day', true);
201 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest', true);
202 |
203 | expect($weekCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
204 | ->and($weekCache->expiration)->toBe(1653177599)
205 | ->and($weekCache->value)->toBeNull()
206 | ->and($dayCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
207 | ->and($dayCache->expiration)->toBe(1652831999)
208 | ->and($dayCache->value)->toBeNull()
209 | ->and($latestCache->status->equals(CacheStatus::DELETED()))->toBeTrue()
210 | ->and($latestCache->expiration)->toBeNull()
211 | ->and($dayCache->value)->toBeNull();
212 | });
213 |
214 | it('will delete all cache entities of a model forever', function() {
215 | $weekCache = TestModel::cache()->get('list.week', true);
216 | $dayCache = TestModel::cache()->get('list.day', true);
217 | $latestCache = TestModel::cache()->get('latest', true);
218 |
219 | expect($weekCache->expiration)->toBe(1653177599)
220 | ->and($dayCache->expiration)->toBe(1652831999)
221 | ->and($latestCache->expiration)->toBeNull();
222 |
223 | TestModel::cache()->deleteAll(true);
224 |
225 | $weekCache = TestModel::cache()->get('list.week', true);
226 | $dayCache = TestModel::cache()->get('list.day', true);
227 | $latestCache = TestModel::cache()->get('latest', true);
228 |
229 | expect($weekCache->expiration)->toBeNull()
230 | ->and($dayCache->expiration)->toBeNull()
231 | ->and($latestCache->expiration)->toBeNull();
232 | });
233 |
234 | it('will delete all cache entities of a model forever using facade', function() {
235 | $weekCache = LaraCache::retrieve(TestModel::class, 'list.week', true);
236 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day', true);
237 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest', true);
238 |
239 | expect($weekCache->expiration)->toBe(1653177599)
240 | ->and($dayCache->expiration)->toBe(1652831999)
241 | ->and($latestCache->expiration)->toBeNull();
242 |
243 | LaraCache::deleteAll(TestModel::class, true);
244 |
245 | $weekCache = LaraCache::retrieve(TestModel::class, 'list.week', true);
246 | $dayCache = LaraCache::retrieve(TestModel::class, 'list.day', true);
247 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest', true);
248 |
249 | expect($weekCache->expiration)->toBeNull()
250 | ->and($dayCache->expiration)->toBeNull()
251 | ->and($latestCache->expiration)->toBeNull();
252 | });
253 |
254 | it('will delete all cache entities that stored with laracache', function() {
255 | createModel2();
256 |
257 | $weekCache1 = LaraCache::retrieve(TestModel::class, 'list.week', true);
258 | $dayCache1 = LaraCache::retrieve(TestModel::class, 'list.day', true);
259 | $latestCache1 = LaraCache::retrieve(TestModel::class, 'latest', true);
260 | $weekCache2 = LaraCache::retrieve(TestModel2::class, 'list.week', true);
261 | $dayCache2 = LaraCache::retrieve(TestModel2::class, 'list.day', true);
262 | $latestCache2 = LaraCache::retrieve(TestModel2::class, 'latest', true);
263 |
264 | expect($weekCache1->expiration)->toBe(1653177599)
265 | ->and($dayCache1->expiration)->toBe(1652831999)
266 | ->and($latestCache1->expiration)->toBeNull()
267 | ->and($weekCache2->expiration)->toBe(1653177599)
268 | ->and($dayCache2->expiration)->toBe(1652831999)
269 | ->and($latestCache2->expiration)->toBeNull();
270 |
271 | LaraCache::deleteAll();
272 |
273 | $weekCache1 = LaraCache::retrieve(TestModel::class, 'list.week', true);
274 | $dayCache1 = LaraCache::retrieve(TestModel::class, 'list.day', true);
275 | $latestCache1 = LaraCache::retrieve(TestModel::class, 'latest', true);
276 | $weekCache2 = LaraCache::retrieve(TestModel2::class, 'list.week', true);
277 | $dayCache2 = LaraCache::retrieve(TestModel2::class, 'list.day', true);
278 | $latestCache2 = LaraCache::retrieve(TestModel2::class, 'latest', true);
279 |
280 | expect($weekCache1->status->equals(CacheStatus::DELETED()))->toBeTrue()
281 | ->and($weekCache1->expiration)->toBe(1653177599)
282 | ->and($weekCache1->value)->toBeNull()
283 | ->and($dayCache1->status->equals(CacheStatus::DELETED()))->toBeTrue()
284 | ->and($dayCache1->expiration)->toBe(1652831999)
285 | ->and($dayCache1->value)->toBeNull()
286 | ->and($latestCache1->status->equals(CacheStatus::DELETED()))->toBeTrue()
287 | ->and($latestCache1->expiration)->toBeNull()
288 | ->and($dayCache1->value)->toBeNull()
289 | ->and($weekCache2->status->equals(CacheStatus::DELETED()))->toBeTrue()
290 | ->and($weekCache2->expiration)->toBe(1653177599)
291 | ->and($weekCache2->value)->toBeNull()
292 | ->and($dayCache2->status->equals(CacheStatus::DELETED()))->toBeTrue()
293 | ->and($dayCache2->expiration)->toBe(1652831999)
294 | ->and($dayCache2->value)->toBeNull()
295 | ->and($latestCache2->status->equals(CacheStatus::DELETED()))->toBeTrue()
296 | ->and($latestCache2->expiration)->toBeNull()
297 | ->and($dayCache2->value)->toBeNull();
298 | });
299 |
300 | it('will delete all cache entities that stored with laracache forever', function() {
301 | createModel2();
302 |
303 | $weekCache1 = LaraCache::retrieve(TestModel::class, 'list.week', true);
304 | $dayCache1 = LaraCache::retrieve(TestModel::class, 'list.day', true);
305 | $latestCache1 = LaraCache::retrieve(TestModel::class, 'latest', true);
306 | $weekCache2 = LaraCache::retrieve(TestModel2::class, 'list.week', true);
307 | $dayCache2 = LaraCache::retrieve(TestModel2::class, 'list.day', true);
308 | $latestCache2 = LaraCache::retrieve(TestModel2::class, 'latest', true);
309 |
310 | expect($weekCache1->expiration)->toBe(1653177599)
311 | ->and($dayCache1->expiration)->toBe(1652831999)
312 | ->and($latestCache1->expiration)->toBeNull()
313 | ->and($weekCache2->expiration)->toBe(1653177599)
314 | ->and($dayCache2->expiration)->toBe(1652831999)
315 | ->and($latestCache2->expiration)->toBeNull();
316 |
317 | LaraCache::deleteAll(forever: true);
318 |
319 | $weekCache1 = LaraCache::retrieve(TestModel::class, 'list.week', true);
320 | $dayCache1 = LaraCache::retrieve(TestModel::class, 'list.day', true);
321 | $latestCache1 = LaraCache::retrieve(TestModel::class, 'latest', true);
322 | $weekCache2 = LaraCache::retrieve(TestModel2::class, 'list.week', true);
323 | $dayCache2 = LaraCache::retrieve(TestModel2::class, 'list.day', true);
324 | $latestCache2 = LaraCache::retrieve(TestModel2::class, 'latest', true);
325 |
326 | expect($weekCache1->expiration)->toBeNull()
327 | ->and($dayCache1->expiration)->toBeNull()
328 | ->and($latestCache1->expiration)->toBeNull()
329 | ->and($weekCache2->expiration)->toBeNull()
330 | ->and($dayCache2->expiration)->toBeNull()
331 | ->and($latestCache2->expiration)->toBeNull();
332 | });
333 |
--------------------------------------------------------------------------------
/tests/Feature/DeleteGroupCacheCommandTest.php:
--------------------------------------------------------------------------------
1 | 'test-model 1',
12 | 'content' => 'content 1'
13 | ],
14 | [
15 | 'name' => 'test-model 2',
16 | 'content' => 'content 2'
17 | ]
18 | ];
19 |
20 | foreach ($records as $record) {
21 | TestModel::query()->create($record);
22 | TestModel2::query()->create($record);
23 | }
24 |
25 | $this->created = CacheStatus::CREATED();
26 | $this->deleted = CacheStatus::DELETED();
27 | });
28 |
29 |
30 | it('will delete all models and entities of the group', function() {
31 | config()->set('laracache.groups.test-group', [
32 | [
33 | 'model' => TestModel::class,
34 | 'entities' => [
35 | 'list.forever', 'list.week'
36 | ],
37 | ],
38 | [
39 | 'model' => TestModel2::class,
40 | 'entities' => [],
41 | ]
42 | ]);
43 |
44 | $names = [
45 | "List Forever\nDeleted", "List Week\nDeleted", "List Day\nDeleted", "Latest\nDeleted"
46 | ];
47 |
48 |
49 | Artisan::call('laracache:delete-group', [
50 | 'group' => 'test-group'
51 | ]);
52 |
53 | $output = Artisan::output();
54 |
55 | expect($output)
56 | ->toBeString()
57 | ->toContain($names[0])
58 | ->toContain($names[1])
59 | ->toContain($names[2])
60 | ->toContain($names[3]);
61 | });
62 |
63 |
--------------------------------------------------------------------------------
/tests/Feature/HelpersTest.php:
--------------------------------------------------------------------------------
1 | freeze('2022-05-17 12:43:34');
8 | });
9 |
10 |
11 | it('will calculate time to end of the week in seconds', function() {
12 | $timeToEnd = week_ending_seconds();
13 | expect($timeToEnd)->toBe(386185);
14 |
15 | $timeToEnd = week_ending_seconds(-20);
16 | expect($timeToEnd)->toBe(386185);
17 |
18 | $timeToEnd = week_ending_seconds(2);
19 | expect($timeToEnd)->toBe(1595785);
20 | });
21 |
22 | it('will calculate time to end of the week when end of week is something custom', function() {
23 | config()->set('laracache.last-day-of-week', CarbonInterface::FRIDAY);
24 |
25 | $timeToEnd = week_ending_seconds();
26 | expect($timeToEnd)->toBe(299785);
27 | });
28 |
29 | it('will calculate time to end of the day in seconds', function() {
30 | $timeToEnd = day_ending_seconds();
31 | expect($timeToEnd)->toBe(40585);
32 |
33 | $timeToEnd = day_ending_seconds(-20);
34 | expect($timeToEnd)->toBe(40585);
35 |
36 | $timeToEnd = day_ending_seconds(4);
37 | expect($timeToEnd)->toBe(386185);
38 | });
39 |
--------------------------------------------------------------------------------
/tests/Feature/QueueCacheTest.php:
--------------------------------------------------------------------------------
1 | get('latest', true);
22 | $isCreating = $cache->status->equals(CacheStatus::CREATING());
23 |
24 | expect($isCreating)->toBeTrue();
25 | });
26 |
27 | it('will initiate cache object with entity default value', function() {
28 | createQueueModel();
29 |
30 | $cache = QueueTestModel::cache()->get('latest', true);
31 |
32 | expect($cache->value)->toBe(-1);
33 | });
34 |
35 | it('will initiate cache object with properly expiration ttl', function() {
36 | createQueueModel();
37 |
38 | $cache = QueueTestModel::cache()->get('latest', true);
39 |
40 | expect(is_null($cache->expiration))->toBeFalse();
41 | });
42 |
43 | it('will dispatch refresh-cache', function() {
44 | Queue::fake();
45 | createQueueModel();
46 |
47 | $onQueue = config('laracache.queue.name');
48 |
49 | Queue::assertPushedOn($onQueue, RefreshCache::class);
50 | });
51 |
52 | it('will create cache after processing queue', function() {
53 | createQueueModel();
54 | $before = now();
55 |
56 | $model = createQueueModel();
57 | Artisan::call('queue:work --once');
58 |
59 | $cache = QueueTestModel::cache()->get('latest', true);
60 | $isCreated = $cache->status->equals(CacheStatus::CREATED());
61 | $after = now();
62 |
63 | expect($before->diffInSeconds($after) >= 1)->toBeTrue()
64 | ->and($cache->value)->toBeInstanceOf(QueueTestModel::class)
65 | ->and($cache->value->name)->toBe($model->name)
66 | ->and($isCreated)->toBeTrue();
67 | });
68 |
69 | it('will return default value and dispatch cache creation job on retrieving entity', function() {
70 | Queue::fake();
71 | DB::table('test_models')
72 | ->insert([
73 | 'name' => 'queue-test-name',
74 | 'content' => 'content',
75 | 'created_at' => now()
76 | ]);
77 |
78 | $cache = QueueTestModel::cache()->get('latest', true);
79 | $isCreating = $cache->status->equals(CacheStatus::CREATING());
80 |
81 | expect($isCreating)->toBeTrue()
82 | ->and($cache->value)->toBe(-1);
83 |
84 | $onQueue = config('laracache.queue.name');
85 |
86 | Queue::assertPushedOn($onQueue, RefreshCache::class);
87 | });
88 |
89 | it('will create cache in background on retrieving entity', function() {
90 | $name = 'queue-test-name';
91 | $before = now();
92 |
93 | DB::table('test_models')
94 | ->insert([
95 | 'name' => $name,
96 | 'content' => 'content',
97 | 'created_at' => now()
98 | ]);
99 |
100 | $cache = QueueTestModel::cache()->get('latest', true);
101 | $isCreating = $cache->status->equals(CacheStatus::CREATING());
102 |
103 | expect($isCreating)->toBeTrue()
104 | ->and($cache->value)->toBe(-1);
105 |
106 | Artisan::call('queue:work --once');
107 |
108 | $cache = QueueTestModel::cache()->get('latest', true);
109 | $isCreated = $cache->status->equals(CacheStatus::CREATED());
110 | $after = now();
111 |
112 | expect($before->diffInSeconds($after) >= 1)->toBeTrue()
113 | ->and($cache->value)->toBeInstanceOf(QueueTestModel::class)
114 | ->and($cache->value->name)->toBe($name)
115 | ->and($isCreated)->toBeTrue();
116 | });
117 |
118 | it('will change cache status to creating on model update', function() {
119 | $model = createQueueModel();
120 |
121 | $cache = QueueTestModel::cache()->get('latest', true);
122 | $isCreating = $cache->status->equals(CacheStatus::CREATING());
123 |
124 | expect($isCreating)->toBeTrue();
125 |
126 | Artisan::call('queue:work --once');
127 |
128 | $cache = QueueTestModel::cache()->get('latest', true);
129 | $isCreated = $cache->status->equals(CacheStatus::CREATED());
130 |
131 | expect($isCreated)->toBeTrue();
132 |
133 | $model->name = 'new name';
134 | $model->save();
135 |
136 | $cache = QueueTestModel::cache()->get('latest', true);
137 | $isCreating = $cache->status->equals(CacheStatus::CREATING());
138 |
139 | expect($isCreating)->toBeTrue();
140 |
141 | Artisan::call('queue:work --once');
142 |
143 | $cache = QueueTestModel::cache()->get('latest', true);
144 | $isCreated = $cache->status->equals(CacheStatus::CREATED());
145 |
146 | expect($isCreated)->toBeTrue()
147 | ->and($cache->value->name)->toBe('new name');
148 | });
149 |
150 | it('will return old cache until queue process of updating model is done', function() {
151 | $model = createQueueModel('old-name');
152 |
153 | $cache = QueueTestModel::cache()->get('latest');
154 | expect($cache)->toBe(-1);
155 |
156 | Artisan::call('queue:work --once');
157 |
158 | $cache = QueueTestModel::cache()->get('latest');
159 | expect($cache->name)->toBe('old-name');
160 |
161 | $model->name = 'new-name';
162 | $model->save();
163 |
164 | $cache = QueueTestModel::cache()->get('latest');
165 | expect($cache->name)->toBe('old-name');
166 |
167 | Artisan::call('queue:work --once');
168 |
169 | $cache = QueueTestModel::cache()->get('latest');
170 | expect($cache->name)->toBe('new-name');
171 | });
172 |
--------------------------------------------------------------------------------
/tests/Feature/RestoreCacheTest.php:
--------------------------------------------------------------------------------
1 | get($name);
13 | expect($cache->name)->toBe('test-name');
14 |
15 | $model->delete();
16 |
17 | $facadeCache = Cache::get($fullName);
18 | $cache = TestModel::cache()->get($name);
19 |
20 | expect($facadeCache->value)->toBeNull()
21 | ->and($cache)->toBeNull();
22 |
23 | $model->restore();
24 |
25 | $facadeCache = Cache::get($fullName);
26 | $cache = TestModel::cache()->get($name);
27 |
28 | expect($facadeCache->value->name)->toBe('test-name')
29 | ->and($cache->name)->toBe('test-name');
30 | });
31 |
32 | it('will not restore cache after restoring record if refresh-after-restore flag is false', function() {
33 | $model = createModel();
34 | $name = 'latest.no-restore';
35 | $fullName = 'test-model.latest.no-restore';
36 |
37 | $cache = Cache::get($fullName);
38 | expect($cache->value->name)->toBe('test-name');
39 |
40 | $model->delete();
41 |
42 | $cache = Cache::get($fullName);
43 | expect($cache->value)->toBeNull();
44 |
45 | $model->restore();
46 |
47 | $facadeCache = Cache::get($fullName);
48 | $cache = TestModel::cache()->get($name);
49 |
50 | expect($facadeCache->value)->toBeNull()
51 | ->and($cache)->toBeNull();
52 | });
53 |
--------------------------------------------------------------------------------
/tests/Feature/RetrieveCacheTest.php:
--------------------------------------------------------------------------------
1 | expectException(CacheEntityDoesNotExist::class);
10 |
11 | TestModel::cache()->get('unknown-name');
12 | });
13 |
14 | it('will retrieve content of each entity correctly', function() {
15 | $numberCache = TestModel::cache()->get('static.number');
16 | $arrayCache = TestModel::cache()->get('static.array');
17 | $boolCache = TestModel::cache()->get('static.bool');
18 |
19 | expect($numberCache)->toBe(1)
20 | ->and($arrayCache)->toBe([1, 2])
21 | ->and($boolCache)->toBeTrue();
22 | });
23 |
24 | it('will retrieve content of each entity correctly using facade', function() {
25 | $cache = LaraCache::retrieve(TestModel::class, 'static.array');
26 |
27 | expect($cache)->toBe([1, 2]);
28 | });
29 |
30 | it('will retrieve cache using laraCache static method', function() {
31 | $numberCache = TestModel::laraCache()->get('static.number');
32 | $arrayCache = TestModel::laraCache()->get('static.array');
33 | $boolCache = TestModel::laraCache()->get('static.bool');
34 |
35 | expect($numberCache)->toBe(1)
36 | ->and($arrayCache)->toBe([1, 2])
37 | ->and($boolCache)->toBeTrue();
38 | });
39 |
40 | it('will return cache data if with cache data flag is true', function() {
41 | createModel();
42 |
43 | $cache = TestModel::cache()->get('latest', true);
44 |
45 | expect($cache)->toBeInstanceOf(CacheData::class);
46 | });
47 |
--------------------------------------------------------------------------------
/tests/Feature/UpdateCacheCommandTest.php:
--------------------------------------------------------------------------------
1 | getTable())
11 | ->insert([
12 | [
13 | 'name' => 'test-model-1-1',
14 | 'content' => 'content 1-1'
15 | ],
16 | [
17 | 'name' => 'test-model-1-2',
18 | 'content' => 'content 1-2'
19 | ]
20 | ]);
21 |
22 | DB::table((new TestModel2())->getTable())
23 | ->insert([
24 | [
25 | 'name' => 'test-model-2-1',
26 | 'content' => 'content 2-1'
27 | ],
28 | [
29 | 'name' => 'test-model-2-2',
30 | 'content' => 'content 2-2'
31 | ]
32 | ]);
33 | });
34 |
35 |
36 | it('will update all entities of all models if multiple models sent to the action', function() {
37 | $names = [
38 | 'list.day', 'list.week', 'list.forever', 'latest'
39 | ];
40 |
41 | foreach ($names as $name) {
42 | $hasCache = Cache::has("test-model.$name");
43 | expect($hasCache)->toBeFalse();
44 |
45 | $hasCache = Cache::has("test-model-2.$name");
46 | expect($hasCache)->toBeFalse();
47 | }
48 |
49 | Artisan::call('laracache:update', [
50 | '--model' => [
51 | TestModel::class, TestModel2::class
52 | ]
53 | ]);
54 |
55 | foreach ($names as $name) {
56 | $hasCache = Cache::has("test-model.$name");
57 | expect($hasCache)->toBeTrue();
58 |
59 | $hasCache = Cache::has("test-model2.$name");
60 | expect($hasCache)->toBeTrue();
61 | }
62 | });
63 |
64 | it('will update all entities of passed model if entities argument is empty', function() {
65 | $names = [
66 | 'list.day', 'list.week', 'list.forever', 'latest'
67 | ];
68 |
69 | foreach ($names as $name) {
70 | $hasCache = Cache::has("test-model.$name");
71 | expect($hasCache)->toBeFalse();
72 | }
73 |
74 | Artisan::call('laracache:update', [
75 | '-m' => [
76 | TestModel::class
77 | ]
78 | ]);
79 |
80 | foreach ($names as $name) {
81 | $hasCache = Cache::has("test-model.$name");
82 | expect($hasCache)->toBeTrue();
83 | }
84 | });
85 |
86 | it('will update only specified entities if one model is sent to the action', function() {
87 | $names = [
88 | 'list.week', 'list.forever', 'latest'
89 | ];
90 |
91 | $hasCache = Cache::has('test-model.list.day');
92 | expect($hasCache)->toBeFalse();
93 |
94 | Artisan::call('laracache:update', [
95 | '--model' => [
96 | TestModel::class
97 | ],
98 | '--entity' => [
99 | 'list.day'
100 | ]
101 | ]);
102 |
103 | foreach ($names as $name) {
104 | $hasCache = Cache::has("test-model.$name");
105 | expect($hasCache)->toBeFalse();
106 | }
107 |
108 | $hasCache = Cache::has('test-model.list.day');
109 | expect($hasCache)->toBeTrue();
110 | });
111 |
112 | it('will print the name of updated cache entities in the console', function() {
113 | $entities = [
114 | 'list.week', 'list.forever', 'latest'
115 | ];
116 |
117 | $names = [
118 | "List Week\nUpdated", "List Forever\nUpdated", "Latest\nUpdated"
119 | ];
120 |
121 |
122 | Artisan::call('laracache:update', [
123 | '--model' => [
124 | TestModel::class
125 | ],
126 | '--entity' => $entities
127 | ]);
128 |
129 | $output = Artisan::output();
130 |
131 | expect($output)
132 | ->toBeString()
133 | ->toContain($names[0])
134 | ->toContain($names[1])
135 | ->toContain($names[2]);
136 | });
137 |
138 |
--------------------------------------------------------------------------------
/tests/Feature/UpdateCacheTest.php:
--------------------------------------------------------------------------------
1 | model = createModel();
12 | });
13 |
14 | it('will throw exception if entity name is not defined during updating cache', function() {
15 | $this->expectException(CacheEntityDoesNotExist::class);
16 |
17 | TestModel::cache()->update('unknown-name');
18 | });
19 |
20 | it('will update cache after updating record', function() {
21 | $name = 'latest';
22 | $fullName = 'test-model.latest';
23 |
24 | $facadeCache = Cache::get($fullName);
25 | $cache = TestModel::cache()->get($name);
26 |
27 | expect($cache->name)->toBe('test-name')
28 | ->and($facadeCache->value->name)->toBe('test-name');
29 |
30 | $this->model->name = 'new-test-name';
31 | $this->model->save();
32 |
33 | $facadeCache = Cache::get($fullName);
34 | $cache = TestModel::cache()->get($name);
35 |
36 | expect($cache->name)->toBe('new-test-name')
37 | ->and($facadeCache->value->name)->toBe('new-test-name');
38 | });
39 |
40 | it('will not update cache after updating record if refresh-after-update flag is false', function() {
41 | $name = 'latest.no-update';
42 | $fullName = 'test-model.latest.no-update';
43 |
44 | $cache = TestModel::cache()->get($name);
45 | expect($cache->name)->toBe('test-name');
46 |
47 | $this->model->name = 'new-test-name';
48 | $this->model->save();
49 |
50 | $cacheFacade = Cache::get($fullName);
51 | $cache = TestModel::cache()->get($name);
52 |
53 | expect($cache->name)->toBe('test-name')
54 | ->and($cacheFacade->value->name)->toBe('test-name');
55 | });
56 |
57 | it('will update cache manually', function() {
58 | $name = 'latest';
59 |
60 | $cache = TestModel::cache()->get($name);
61 | expect($cache->name)->toBe('test-name');
62 |
63 | DB::table('test_models')
64 | ->where('id', $this->model->id)
65 | ->update([
66 | 'name' => 'new-test-name'
67 | ]);
68 |
69 | $cache = TestModel::cache()->get($name);
70 | expect($cache->name)->toBe('test-name');
71 |
72 | TestModel::cache()->update($name);
73 |
74 | $cache = TestModel::cache()->get($name);
75 | expect($cache->name)->toBe('new-test-name');
76 | });
77 |
78 | it('will update cache manually using facade', function() {
79 | $cache = LaraCache::retrieve(TestModel::class, 'latest');
80 | expect($cache->name)->toBe('test-name');
81 |
82 | DB::table('test_models')
83 | ->where('id', $cache->id)
84 | ->update([
85 | 'name' => 'new-test-name'
86 | ]);
87 |
88 | $cache = LaraCache::retrieve(TestModel::class, 'latest');
89 | expect($cache->name)->toBe('test-name');
90 |
91 | LaraCache::update(TestModel::class, 'latest');
92 |
93 | $cache = LaraCache::retrieve(TestModel::class, 'latest');
94 | expect($cache->name)->toBe('new-test-name');
95 | });
96 |
97 | it('will update all cache entities', function() {
98 | $latestCache = TestModel::cache()->get('latest');
99 | $foreverCache = TestModel::cache()->get('list.forever');
100 |
101 | expect($latestCache->name)->toBe('test-name')
102 | ->and($foreverCache)->toHaveCount(1);
103 |
104 | DB::table('test_models')->insert([
105 | 'name' => 'new-test-name',
106 | 'content' => 'content',
107 | 'created_at' => now()->addSecond()
108 | ]);
109 |
110 | $latestCache = TestModel::cache()->get('latest');
111 | $foreverCache = TestModel::cache()->get('list.forever');
112 |
113 | expect($latestCache->name)->toBe('test-name')
114 | ->and($foreverCache)->toHaveCount(1);
115 |
116 | TestModel::cache()->updateAll();
117 |
118 | $latestCache = TestModel::cache()->get('latest');
119 | $foreverCache = TestModel::cache()->get('list.forever');
120 |
121 | expect($latestCache->name)->toBe('new-test-name')
122 | ->and($foreverCache)->toHaveCount(2);
123 | });
124 |
125 | it('will update all cache entities manually using facade', function() {
126 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest');
127 | $foreverCache = LaraCache::retrieve(TestModel::class, 'list.forever');
128 |
129 | expect($latestCache->name)->toBe('test-name')
130 | ->and($foreverCache)->toHaveCount(1);
131 |
132 | DB::table('test_models')->insert([
133 | 'name' => 'new-test-name',
134 | 'content' => 'content',
135 | 'created_at' => now()->addSecond()
136 | ]);
137 |
138 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest');
139 | $foreverCache = LaraCache::retrieve(TestModel::class, 'list.forever');
140 |
141 | expect($latestCache->name)->toBe('test-name')
142 | ->and($foreverCache)->toHaveCount(1);
143 |
144 | LaraCache::updateAll(TestModel::class);
145 |
146 | $latestCache = LaraCache::retrieve(TestModel::class, 'latest');
147 | $foreverCache = LaraCache::retrieve(TestModel::class, 'list.forever');
148 |
149 | expect($latestCache->name)->toBe('new-test-name')
150 | ->and($foreverCache)->toHaveCount(2);
151 | });
152 |
153 | it('will update all cache entities that stored with laracache', function() {
154 | $model2 = createModel2();
155 |
156 | $latestCache1 = TestModel::cache()->get('latest');
157 | $dayCache1 = TestModel::cache()->get('list.day');
158 | $latestCache2 = TestModel2::cache()->get('latest');
159 | $dayCache2 = TestModel2::cache()->get('list.day');
160 |
161 | expect($latestCache1->name)->toBe('test-name')
162 | ->and($dayCache1)->toHaveCount(1)
163 | ->and($latestCache2->name)->toBe('test-name-2')
164 | ->and($dayCache2)->toHaveCount(1);
165 |
166 | DB::table('test_models')
167 | ->where('id', $this->model->id)
168 | ->update([
169 | 'name' => 'new-test-name'
170 | ]);
171 |
172 | DB::table('test_models_2')
173 | ->where('id', $model2->id)
174 | ->update([
175 | 'name' => 'new-test-name-2'
176 | ]);
177 |
178 | $latestCache1 = TestModel::cache()->get('latest');
179 | $dayCache1 = TestModel::cache()->get('list.day');
180 | $latestCache2 = TestModel2::cache()->get('latest');
181 | $dayCache2 = TestModel2::cache()->get('list.day');
182 |
183 | expect($latestCache1->name)->toBe('test-name')
184 | ->and($dayCache1)->toHaveCount(1)
185 | ->and($latestCache2->name)->toBe('test-name-2')
186 | ->and($dayCache2)->toHaveCount(1);
187 |
188 | LaraCache::updateAll();
189 |
190 | $latestCache1 = TestModel::cache()->get('latest');
191 | $dayCache1 = TestModel::cache()->get('list.day');
192 | $latestCache2 = TestModel2::cache()->get('latest');
193 | $dayCache2 = TestModel2::cache()->get('list.day');
194 |
195 | expect($latestCache1->name)->toBe('new-test-name')
196 | ->and($dayCache1)->toHaveCount(1)
197 | ->and($latestCache2->name)->toBe('new-test-name-2')
198 | ->and($dayCache2)->toHaveCount(1);
199 | });
200 |
--------------------------------------------------------------------------------
/tests/Feature/UpdateGroupCacheCommandTest.php:
--------------------------------------------------------------------------------
1 | getTable())
10 | ->insert([
11 | [
12 | 'name' => 'test-model-1-1',
13 | 'content' => 'content 1-1'
14 | ],
15 | [
16 | 'name' => 'test-model-1-2',
17 | 'content' => 'content 1-2'
18 | ]
19 | ]);
20 |
21 | DB::table((new TestModel2())->getTable())
22 | ->insert([
23 | [
24 | 'name' => 'test-model-2-1',
25 | 'content' => 'content 2-1'
26 | ],
27 | [
28 | 'name' => 'test-model-2-2',
29 | 'content' => 'content 2-2'
30 | ]
31 | ]);
32 | });
33 |
34 |
35 | it('will update all models and entities of the group', function() {
36 | config()->set('laracache.groups.test-group', [
37 | [
38 | 'model' => TestModel::class,
39 | 'entities' => [
40 | 'list.forever', 'list.week'
41 | ],
42 | ],
43 | [
44 | 'model' => TestModel2::class,
45 | 'entities' => [],
46 | ]
47 | ]);
48 |
49 | $names = [
50 | "List Forever\nUpdated", "List Week\nUpdated", "List Day\nUpdated", "Latest\nUpdated"
51 | ];
52 |
53 |
54 | Artisan::call('laracache:update-group', [
55 | 'group' => 'test-group'
56 | ]);
57 |
58 | $output = Artisan::output();
59 |
60 | expect($output)
61 | ->toBeString()
62 | ->toContain($names[0])
63 | ->toContain($names[1])
64 | ->toContain($names[2])
65 | ->toContain($names[3]);
66 | });
67 |
68 |
--------------------------------------------------------------------------------
/tests/Feature/UpdateLaraCacheModelsListTest.php:
--------------------------------------------------------------------------------
1 | set('queue.default', 'sync');
9 |
10 | createModel();
11 | createModel2();
12 | });
13 |
14 |
15 | it('will update the list of models which use laracache', function() {
16 | $models = Cache::get('laracache.models');
17 |
18 | expect($models)
19 | ->toBeArray()
20 | ->toHaveCount(2)
21 | ->toMatchArray([
22 | TestModel::class,
23 | TestModel2::class
24 | ]);
25 | });
26 |
27 | it('wont duplicate models', function() {
28 | createModel();
29 | $models = Cache::get('laracache.models');
30 |
31 | expect($models)->toBeArray()->toHaveCount(2);
32 | });
33 |
34 |
--------------------------------------------------------------------------------
/tests/Pest.php:
--------------------------------------------------------------------------------
1 | in(__DIR__);
9 |
10 | function createModel(?string $name = null): TestModel
11 | {
12 | $model = new TestModel;
13 | $model->name = $name ?? 'test-name';
14 | $model->content = 'content';
15 | $model->save();
16 |
17 | return $model;
18 | }
19 |
20 | function createModel2(?string $name = null): TestModel2
21 | {
22 | $model = new TestModel2();
23 | $model->name = $name ?? 'test-name-2';
24 | $model->content = 'content';
25 | $model->save();
26 |
27 | return $model;
28 | }
29 |
30 | function createQueueModel(?string $name = null): QueueTestModel
31 | {
32 | $model = new QueueTestModel();
33 | $model->name = $name ?? 'queue-test-name';
34 | $model->content = 'content';
35 | $model->save();
36 |
37 | return $model;
38 | }
39 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | setUpDatabase($this->app);
17 | }
18 |
19 | /**
20 | * @param Application $app
21 | *
22 | * @return array
23 | */
24 | protected function getPackageProviders($app): array
25 | {
26 | return [
27 | LaraCacheServiceProvider::class,
28 | ];
29 | }
30 |
31 | /**
32 | * @param Application $app
33 | */
34 | public function getEnvironmentSetUp($app)
35 | {
36 | config()->set('cache.default', 'array');
37 | config()->set('queue.default', 'database');
38 |
39 | config()->set('database.default', 'sqlite');
40 | config()->set('database.connections.sqlite', [
41 | 'driver' => 'sqlite',
42 | 'database' => ':memory:',
43 | 'prefix' => '',
44 | ]);
45 | }
46 |
47 | /**
48 | * @param Application $app
49 | */
50 | protected function setUpDatabase(Application $app)
51 | {
52 | $app['db']->connection()
53 | ->getSchemaBuilder()
54 | ->create('jobs', function(Blueprint $table) {
55 | $table->bigIncrements('id');
56 | $table->string('queue')->index();
57 | $table->longText('payload');
58 | $table->unsignedTinyInteger('attempts');
59 | $table->unsignedInteger('reserved_at')->nullable();
60 | $table->unsignedInteger('available_at');
61 | $table->unsignedInteger('created_at');
62 | });
63 |
64 | $app['db']->connection()
65 | ->getSchemaBuilder()
66 | ->create('failed_jobs', function(Blueprint $table) {
67 | $table->id();
68 | $table->string('uuid')->unique();
69 | $table->text('connection');
70 | $table->text('queue');
71 | $table->longText('payload');
72 | $table->longText('exception');
73 | $table->timestamp('failed_at')->useCurrent();
74 | });
75 |
76 | $app['db']->connection()
77 | ->getSchemaBuilder()
78 | ->create('test_models', function(Blueprint $table) {
79 | $table->increments('id');
80 | $table->string('name');
81 | $table->string('content', 500)->nullable();
82 | $table->timestamps();
83 | $table->softDeletes();
84 | });
85 |
86 | $app['db']->connection()
87 | ->getSchemaBuilder()
88 | ->create('test_models_2', function(Blueprint $table) {
89 | $table->increments('id');
90 | $table->string('name');
91 | $table->string('content', 500)->nullable();
92 | $table->timestamps();
93 | $table->softDeletes();
94 | });
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/tests/TestSupport/TestModels/QueueTestModel.php:
--------------------------------------------------------------------------------
1 | validForRestOfDay()
22 | ->isQueueable()
23 | ->setDefault(-1)
24 | ->cache(function() {
25 | sleep(1);
26 |
27 | return QueueTestModel::query()->latest()->first();
28 | })
29 | ];
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/tests/TestSupport/TestModels/TestModel.php:
--------------------------------------------------------------------------------
1 | forever()
21 | ->cache(function() {
22 | return TestModel::query()->latest()->get();
23 | }),
24 |
25 | CacheEntity::make('list.day')
26 | ->validForRestOfDay()
27 | ->cache(function() {
28 | return TestModel::query()->latest()->get();
29 | }),
30 |
31 | CacheEntity::make('list.week')
32 | ->validForRestOfWeek()
33 | ->cache(function() {
34 | return TestModel::query()->latest()->get();
35 | }),
36 |
37 | CacheEntity::make('list.ttl')
38 | ->ttl(120)
39 | ->cache(function() {
40 | return TestModel::query()->latest()->get();
41 | }),
42 |
43 | CacheEntity::make('latest')
44 | ->forever()
45 | ->cache(function() {
46 | return TestModel::query()->latest()->first();
47 | }),
48 |
49 | CacheEntity::make('latest.no-create')
50 | ->refreshAfterCreate(false)
51 | ->cache(function() {
52 | return TestModel::query()->latest()->first();
53 | }),
54 |
55 | CacheEntity::make('latest.no-update')
56 | ->refreshAfterUpdate(false)
57 | ->cache(function() {
58 | return TestModel::query()->latest()->first();
59 | }),
60 |
61 | CacheEntity::make('latest.no-delete')
62 | ->refreshAfterDelete(false)
63 | ->cache(function() {
64 | return TestModel::query()->latest()->first();
65 | }),
66 |
67 | CacheEntity::make('latest.no-restore')
68 | ->refreshAfterRestore(false)
69 | ->cache(function() {
70 | return TestModel::query()->latest()->first();
71 | }),
72 |
73 | CacheEntity::make('empty.number')
74 | ->setDefault('empty value')
75 | ->cache(fn() => 0),
76 |
77 | CacheEntity::make('empty.array')
78 | ->setDefault('empty value')
79 | ->cache(fn() => []),
80 |
81 | CacheEntity::make('empty.string')
82 | ->setDefault('empty value')
83 | ->cache(fn() => ''),
84 |
85 | CacheEntity::make('empty.bool')
86 | ->setDefault('empty value')
87 | ->cache(fn() => false),
88 |
89 | CacheEntity::make('empty.null')
90 | ->setDefault('empty value')
91 | ->cache(fn() => null),
92 |
93 | CacheEntity::make('static.number')
94 | ->setDefault('default-value')
95 | ->cache(fn() => 1),
96 |
97 | CacheEntity::make('static.array')
98 | ->cache(fn() => [1, 2]),
99 |
100 | CacheEntity::make('static.bool')
101 | ->cache(fn() => true)
102 | ];
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/tests/TestSupport/TestModels/TestModel2.php:
--------------------------------------------------------------------------------
1 | forever()
22 | ->cache(function() {
23 | return TestModel2::query()->latest()->get();
24 | }),
25 |
26 | CacheEntity::make('list.day')
27 | ->validForRestOfDay()
28 | ->cache(function() {
29 | return TestModel2::query()->latest()->get();
30 | }),
31 |
32 | CacheEntity::make('list.week')
33 | ->validForRestOfWeek()
34 | ->cache(function() {
35 | return TestModel2::query()->latest()->get();
36 | }),
37 |
38 | CacheEntity::make('list.ttl')
39 | ->ttl(120)
40 | ->cache(function() {
41 | return TestModel2::query()->latest()->get();
42 | }),
43 |
44 | CacheEntity::make('latest')
45 | ->forever()
46 | ->cache(function() {
47 | return TestModel2::query()->latest()->first();
48 | })
49 | ];
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/tests/TestSupport/TestModels/TestUser.php:
--------------------------------------------------------------------------------
1 | equals(CacheStatus::CREATED());
8 | expect($isEqual)->toBeTrue();
9 |
10 | $isEqual = CacheStatus::CREATED()->equals(CacheStatus::DELETED());
11 | expect($isEqual)->toBeFalse();
12 | });
13 |
14 | it('can get value of cache status', function(CacheStatus $status, string $value) {
15 | expect($status->getValue())->toBe($value);
16 | })->with([
17 | 'NOT_CREATED' => ['status' => CacheStatus::NOT_CREATED(), 'value' => 'NOT_CREATED'],
18 | 'CREATING' => ['status' => CacheStatus::CREATING(), 'value' => 'CREATING'],
19 | 'CREATED' => ['status' => CacheStatus::CREATED(), 'value' => 'CREATED'],
20 | 'DELETED' => ['status' => CacheStatus::DELETED(), 'value' => 'DELETED'],
21 | ]);
22 |
--------------------------------------------------------------------------------
/tests/Unit/CommandDataTest.php:
--------------------------------------------------------------------------------
1 | throws(EntityIsNotAllowed::class);
15 |
16 | it('will throw an exception if model does not exist', function() {
17 | CommandData::make(['Article']);
18 | })->throws(ModelDoestNotExist::class);
19 |
20 | it('will throw an exception if model does not use LaraCache trait', function() {
21 | CommandData::make([TestUser::class]);
22 | })->throws(ModelDoesntUseLaraCacheTrait::class);
23 |
24 | it('will assign existing models to models property', function() {
25 | $data = CommandData::make([TestModel::class, TestModel2::class]);
26 |
27 | expect($data->models)
28 | ->toBeArray()
29 | ->toHaveCount(2)
30 | ->toMatchArray([
31 | TestModel::class, TestModel2::class
32 | ]);
33 | });
34 |
35 | it('will assign entities to entities property', function() {
36 | $entities = ['latest', 'featured', 'popular'];
37 | $data = CommandData::make([TestModel::class], $entities);
38 |
39 | expect($data->entities)
40 | ->toBeArray()
41 | ->toHaveCount(3)
42 | ->toMatchArray($entities);
43 | });
44 |
--------------------------------------------------------------------------------
/tests/Unit/DeleteCacheActionTest.php:
--------------------------------------------------------------------------------
1 | 'test-model 1',
13 | 'content' => 'content 1'
14 | ],
15 | [
16 | 'name' => 'test-model 2',
17 | 'content' => 'content 2'
18 | ]
19 | ];
20 |
21 | foreach ($records as $record) {
22 | TestModel::query()->create($record);
23 | TestModel2::query()->create($record);
24 | }
25 |
26 | $this->created = CacheStatus::CREATED();
27 | $this->deleted = CacheStatus::DELETED();
28 | });
29 |
30 |
31 | it('will delete all entities of all models if multiple models sent to the action', function() {
32 | $names = [
33 | 'list.day', 'list.week', 'list.forever', 'latest'
34 | ];
35 |
36 | foreach ($names as $name) {
37 | $cache = TestModel::cache()->get($name, true);
38 | expect($cache->status->equals($this->created))->toBeTrue();
39 |
40 | $cache = TestModel2::cache()->get($name, true);
41 | expect($cache->status->equals($this->created))->toBeTrue();
42 | }
43 |
44 | DeleteCacheAction::make()->run(
45 | CommandData::make([TestModel::class, TestModel2::class])
46 | );
47 |
48 | foreach ($names as $name) {
49 | $cache = TestModel::cache()->get($name, true);
50 | expect($cache->status->equals($this->deleted))->toBeTrue();
51 |
52 | $cache = TestModel2::cache()->get($name, true);
53 | expect($cache->status->equals($this->deleted))->toBeTrue();
54 | }
55 | });
56 |
57 | it('will delete all entities of passed model if entities argument is empty', function() {
58 | $names = [
59 | 'list.day', 'list.week', 'list.forever', 'latest'
60 | ];
61 |
62 | foreach ($names as $name) {
63 | $cache = TestModel::cache()->get($name, true);
64 | expect($cache->status->equals($this->created))->toBeTrue();
65 | }
66 |
67 | DeleteCacheAction::make()->run(
68 | CommandData::make([TestModel::class])
69 | );
70 |
71 | foreach ($names as $name) {
72 | $cache = TestModel::cache()->get($name, true);
73 | expect($cache->status->equals($this->deleted))->toBeTrue();
74 | }
75 | });
76 |
77 | it('will delete only specified entities if one model is sent to the action', function() {
78 | $names = [
79 | 'list.week', 'list.forever', 'latest'
80 | ];
81 |
82 | $cache = TestModel::cache()->get('list.day', true);
83 | expect($cache->status->equals($this->created))->toBeTrue();
84 |
85 | DeleteCacheAction::make()->run(
86 | CommandData::make([TestModel::class], ['list.day'])
87 | );
88 |
89 | foreach ($names as $name) {
90 | $cache = TestModel::cache()->get($name, true);
91 | expect($cache->status->equals($this->created))->toBeTrue();
92 | }
93 |
94 | $cache = TestModel::cache()->get('list.day', true);
95 | expect($cache->status->equals($this->deleted))->toBeTrue();
96 | });
97 |
--------------------------------------------------------------------------------
/tests/Unit/DeleteGroupCacheActionTest.php:
--------------------------------------------------------------------------------
1 | 'test-model 1',
14 | 'content' => 'content 1'
15 | ],
16 | [
17 | 'name' => 'test-model 2',
18 | 'content' => 'content 2'
19 | ]
20 | ];
21 |
22 | foreach ($records as $record) {
23 | TestModel::query()->create($record);
24 | TestModel2::query()->create($record);
25 | }
26 |
27 | $this->created = CacheStatus::CREATED();
28 | $this->deleted = CacheStatus::DELETED();
29 | });
30 |
31 |
32 | it('will throw an exception if group doesnt exist in config file', function() {
33 | DeleteGroupCacheAction::make()->run('test-group');
34 | })->throws(CacheGroupNotExist::class);
35 |
36 | it('will throw an exception if group property is not an array', function() {
37 | config()->set('laracache.groups.test-group', 'test');
38 |
39 | DeleteGroupCacheAction::make()->run('test-group');
40 | })->throws(CacheGroupValueIsNotValid::class);
41 |
42 | it('will throw an exception if model key in group item is not set', function() {
43 | config()->set('laracache.groups.test-group', [
44 | [
45 | 'entities' => [
46 | 'list.forever', 'list.week'
47 | ],
48 | ]
49 | ]);
50 |
51 | DeleteGroupCacheAction::make()->run('test-group');
52 | })->throws(CacheGroupValueIsNotValid::class);
53 |
54 | it('will throw an exception if model key in group item is not a string', function() {
55 | config()->set('laracache.groups.test-group', [
56 | [
57 | 'model' => [TestModel::class],
58 | 'entities' => [
59 | 'list.forever', 'list.week'
60 | ],
61 | ]
62 | ]);
63 |
64 | DeleteGroupCacheAction::make()->run('test-group');
65 | })->throws(CacheGroupValueIsNotValid::class);
66 |
67 | it('will throw an exception if entities key in group item is not set', function() {
68 | config()->set('laracache.groups.test-group', [
69 | [
70 | 'model' => [TestModel::class],
71 | ]
72 | ]);
73 |
74 | DeleteGroupCacheAction::make()->run('test-group');
75 | })->throws(CacheGroupValueIsNotValid::class);
76 |
77 | it('will throw an exception if entities key in group item is not an array', function() {
78 | config()->set('laracache.groups.test-group', [
79 | [
80 | 'model' => [TestModel::class],
81 | 'entities' => 'list.forever',
82 | ]
83 | ]);
84 |
85 | DeleteGroupCacheAction::make()->run('test-group');
86 | })->throws(CacheGroupValueIsNotValid::class);
87 |
88 | it('will update all models and entities of the group', function() {
89 | config()->set('laracache.groups.test-group', [
90 | [
91 | 'model' => TestModel::class,
92 | 'entities' => [
93 | 'list.forever', 'list.week'
94 | ],
95 | ],
96 | [
97 | 'model' => TestModel2::class,
98 | 'entities' => [],
99 | ]
100 | ]);
101 |
102 | $entities1 = ['list.forever', 'list.week'];
103 | $entities2 = ['list.day', 'list.week', 'list.forever', 'latest'];
104 |
105 | foreach ($entities1 as $entity) {
106 | $cache = TestModel::cache()->get($entity, true);
107 | expect($cache->status->equals($this->created))->toBeTrue();
108 | }
109 |
110 | foreach ($entities2 as $entity) {
111 | $cache = TestModel2::cache()->get($entity, true);
112 | expect($cache->status->equals($this->created))->toBeTrue();
113 | }
114 |
115 | DeleteGroupCacheAction::make()->run('test-group');
116 |
117 |
118 | foreach ($entities1 as $entity) {
119 | $cache = TestModel::cache()->get($entity, true);
120 | expect($cache->status->equals($this->deleted))->toBeTrue();
121 | }
122 |
123 | foreach ($entities2 as $entity) {
124 | $cache = TestModel2::cache()->get($entity, true);
125 | expect($cache->status->equals($this->deleted))->toBeTrue();
126 | }
127 | });
128 |
--------------------------------------------------------------------------------
/tests/Unit/UpdateCacheActionTest.php:
--------------------------------------------------------------------------------
1 | 'test-model-1',
14 | 'content' => 'content 1'
15 | ],
16 | [
17 | 'name' => 'test-model-2',
18 | 'content' => 'content 2'
19 | ]
20 | ];
21 |
22 | DB::table((new TestModel())->getTable())->insert($records);
23 | DB::table((new TestModel2())->getTable())->insert($records);
24 | });
25 |
26 |
27 | it('will update all entities of all models if multiple models sent to the action', function() {
28 | $names = [
29 | 'list.day', 'list.week', 'list.forever', 'latest'
30 | ];
31 |
32 | foreach ($names as $name) {
33 | $hasCache = Cache::has("test-model.$name");
34 | expect($hasCache)->toBeFalse();
35 |
36 | $hasCache = Cache::has("test-model2.$name");
37 | expect($hasCache)->toBeFalse();
38 | }
39 |
40 | UpdateCacheAction::make()->run(
41 | CommandData::make([TestModel::class, TestModel2::class])
42 | );
43 |
44 | foreach ($names as $name) {
45 | $hasCache = Cache::has("test-model.$name");
46 | expect($hasCache)->toBeTrue();
47 |
48 | $hasCache = Cache::has("test-model2.$name");
49 | expect($hasCache)->toBeTrue();
50 | }
51 | });
52 |
53 | it('will update all entities of passed model if entities argument is empty', function() {
54 | $names = [
55 | 'list.day', 'list.week', 'list.forever', 'latest'
56 | ];
57 |
58 | foreach ($names as $name) {
59 | $hasCache = Cache::has("test-model.$name");
60 | expect($hasCache)->toBeFalse();
61 | }
62 |
63 | UpdateCacheAction::make()->run(
64 | CommandData::make([TestModel::class])
65 | );
66 |
67 | foreach ($names as $name) {
68 | $hasCache = Cache::has("test-model.$name");
69 | expect($hasCache)->toBeTrue();
70 | }
71 | });
72 |
73 | it('will update only specified entities if one model is sent to the action', function() {
74 | $names = [
75 | 'list.week', 'list.forever', 'latest'
76 | ];
77 |
78 | $hasCache = Cache::has('test-model.list.day');
79 | expect($hasCache)->toBeFalse();
80 |
81 | UpdateCacheAction::make()->run(
82 | CommandData::make([TestModel::class], ['list.day'])
83 | );
84 |
85 | foreach ($names as $name) {
86 | $hasCache = Cache::has("test-model.$name");
87 | expect($hasCache)->toBeFalse();
88 | }
89 |
90 | $hasCache = Cache::has('test-model.list.day');
91 | expect($hasCache)->toBeTrue();
92 | });
93 |
--------------------------------------------------------------------------------
/tests/Unit/UpdateGroupCacheActionTest.php:
--------------------------------------------------------------------------------
1 | 'test-model-1',
15 | 'content' => 'content 1'
16 | ],
17 | [
18 | 'name' => 'test-model-2',
19 | 'content' => 'content 2'
20 | ]
21 | ];
22 |
23 | DB::table((new TestModel())->getTable())->insert($records);
24 | DB::table((new TestModel2())->getTable())->insert($records);
25 | });
26 |
27 |
28 | it('will throw an exception if group doesnt exist in config file', function() {
29 | UpdateGroupCacheAction::make()->run('test-group');
30 | })->throws(CacheGroupNotExist::class);
31 |
32 | it('will throw an exception if group property is not an array', function() {
33 | config()->set('laracache.groups.test-group', 'test');
34 |
35 | UpdateGroupCacheAction::make()->run('test-group');
36 | })->throws(CacheGroupValueIsNotValid::class);
37 |
38 | it('will throw an exception if model key in group item is not set', function() {
39 | config()->set('laracache.groups.test-group', [
40 | [
41 | 'entities' => [
42 | 'list.forever', 'list.week'
43 | ],
44 | ]
45 | ]);
46 |
47 | UpdateGroupCacheAction::make()->run('test-group');
48 | })->throws(CacheGroupValueIsNotValid::class);
49 |
50 | it('will throw an exception if model key in group item is not a string', function() {
51 | config()->set('laracache.groups.test-group', [
52 | [
53 | 'model' => [TestModel::class],
54 | 'entities' => [
55 | 'list.forever', 'list.week'
56 | ],
57 | ]
58 | ]);
59 |
60 | UpdateGroupCacheAction::make()->run('test-group');
61 | })->throws(CacheGroupValueIsNotValid::class);
62 |
63 | it('will throw an exception if entities key in group item is not set', function() {
64 | config()->set('laracache.groups.test-group', [
65 | [
66 | 'model' => [TestModel::class],
67 | ]
68 | ]);
69 |
70 | UpdateGroupCacheAction::make()->run('test-group');
71 | })->throws(CacheGroupValueIsNotValid::class);
72 |
73 | it('will throw an exception if entities key in group item is not an array', function() {
74 | config()->set('laracache.groups.test-group', [
75 | [
76 | 'model' => [TestModel::class],
77 | 'entities' => 'list.forever',
78 | ]
79 | ]);
80 |
81 | UpdateGroupCacheAction::make()->run('test-group');
82 | })->throws(CacheGroupValueIsNotValid::class);
83 |
84 | it('will update all models and entities of the group', function() {
85 | config()->set('laracache.groups.test-group', [
86 | [
87 | 'model' => TestModel::class,
88 | 'entities' => [
89 | 'list.forever', 'list.week'
90 | ],
91 | ],
92 | [
93 | 'model' => TestModel2::class,
94 | 'entities' => [],
95 | ]
96 | ]);
97 |
98 | $entities1 = ['list.forever', 'list.week'];
99 | $entities2 = ['list.day', 'list.week', 'list.forever', 'latest'];
100 |
101 | foreach ($entities1 as $entity) {
102 | $hasCache = Cache::has("test-model.$entity");
103 | expect($hasCache)->toBeFalse();
104 | }
105 |
106 | foreach ($entities2 as $entity) {
107 | $hasCache = Cache::has("test-model2.$entity");
108 | expect($hasCache)->toBeFalse();
109 | }
110 |
111 | UpdateGroupCacheAction::make()->run('test-group');
112 |
113 | foreach ($entities1 as $entity) {
114 | $hasCache = Cache::has("test-model.$entity");
115 | expect($hasCache)->toBeTrue();
116 | }
117 |
118 | foreach ($entities2 as $entity) {
119 | $hasCache = Cache::has("test-model2.$entity");
120 | expect($hasCache)->toBeTrue();
121 | }
122 | });
123 |
--------------------------------------------------------------------------------