diff --git a/README.md b/README.md index 4e1a56a..8435ef3 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ $value = $cache->get('mykey'); $cache->set('tagging', [ 'tags' => ['tag1', 'tag2'], - 'value' => 'myvalue', + 'other_value' => 'myothervalue', ]); ``` @@ -245,18 +245,31 @@ filtering my tags or invalidating many cache entries at once. // NOTE: we are using the cacheCollection() method here $collection = mongo()->cacheCollection(); -// find all that have the tag 'tag1' +// find all that have the tag 'tag1' and are NOT expired $documents = $collection->find([ - 'tags' => ['$in' => ['tag1']], + 'value.tags' => ['$in' => ['tag1']], + 'expires_at' => ['$gt' => time()], ]); +foreach ($documents as $document) { + // $document->value->tags + // $document->value->other_value +} // delete any cache entry older than 5 minutes $deleteResult = $collection->deleteMany([ 'expires_at' => ['$lt' => time() - 5*60] ]); $deletedCount = $deleteResult->getDeletedCount(); + +// you can also manually clean expired cache entries +mongo()->clean(); ``` +> [!NOTE] +> +> Querying the cache directly is not recommended for regular use-cases. It will not check for the expiration of the +> cache entries and delete them automatically. + ## Using the Cache Driver in Kirby You can also use the MongoDB-based cache as a **cache driver** for Kirby. This will allow you to use it for caching of @@ -287,6 +300,9 @@ return [ | username | `null` | | | password | `null` | | | database | `kirby` | you can give it any name you want and MongoDB will create it for you | +| uriOptions | `[]` | | +| driverOptions | `[]` | | +| auto-clean-cache | `true` | will clean the cache once before the first get() | | khulan.read | `false` | read from cache is disabled by default as loading from file might be faster | | khulan.write | `true` | write to cache for all models that use the ModelWithKhulan trait | | khulan.patch-files-class | `true` | monkey-patch the \Kirby\CMS\Files class to use Khulan for caching its content | diff --git a/classes/Mongodb.php b/classes/Mongodb.php index b280d02..f5267eb 100644 --- a/classes/Mongodb.php +++ b/classes/Mongodb.php @@ -18,6 +18,8 @@ final class Mongodb extends Cache { protected ?Client $_client = null; + protected bool $hasCleanedOnce = false; + /** * Sets all parameters which are needed to connect to MongoDB. */ @@ -34,6 +36,7 @@ public function __construct(array $options = []) 'driverOptions' => option('bnomei.mongodb.driverOptions'), 'collection-cache' => option('bnomei.mongodb.collections.cache'), 'collection-content' => option('bnomei.mongodb.collections.content'), + 'auto-clean-cache' => option('bnomei.mongodb.auto-clean-cache'), ], $options); foreach ($this->options as $key => $call) { @@ -95,6 +98,11 @@ public function set(string $key, $value, int $minutes = 0): bool */ public function retrieve(string $key): ?Value { + if ($this->options['auto-clean-cache'] && $this->hasCleanedOnce === false) { + $this->clean(time()); + $this->hasCleanedOnce = true; + } + $value = $value ?? $this->cacheCollection()->findOne([ '_id' => $this->key($key), ]); @@ -183,6 +191,15 @@ public function root(): string return kirby()->cache('bnomei.mongodb')->root(); } + public function clean(?int $time = null): ?int + { + $result = $this->cacheCollection()->deleteMany([ + 'expires_at' => ['$lt' => $time ?? time()], + ]); + + return $result->isAcknowledged() ? $result->getDeletedCount() : null; + } + public function cache(): self { return $this; diff --git a/composer.json b/composer.json index 075c22e..526973f 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "bnomei/kirby-mongodb", "type": "kirby-plugin", - "version": "1.4.2", + "version": "1.4.3", "description": "Khulan is a cache driver and content cache with NoSQL interface for Kirby using MongoDB", "license": "MIT", "authors": [ diff --git a/composer.lock b/composer.lock index 4171f2a..79ce35c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "369cbfd2810cbfddd5613bf3a21c79f5", + "content-hash": "2acb6bf396ddb610a0869853263d09a4", "packages": [ { "name": "getkirby/composer-installer", diff --git a/index.php b/index.php index a356498..d345389 100644 --- a/index.php +++ b/index.php @@ -72,6 +72,7 @@ function khulan(string|array|null $search = null, ?array $options = null): mixed 'password' => null, 'uriOptions' => [], 'driverOptions' => [], + 'auto-clean-cache' => true, // collections 'collections' => [ diff --git a/tests/MongodbTest.php b/tests/MongodbTest.php index b6f94b4..d82797e 100644 --- a/tests/MongodbTest.php +++ b/tests/MongodbTest.php @@ -70,6 +70,36 @@ expect($value)->toBe('value'); }); +it('can use the cache for array based values', function () { + $mongodb = mongo(); + $mongodb->set('tagging', [ + 'tags' => ['tag1', 'tag2'], + 'not_value' => 'notmyvalue', + ]); + + $collection = mongo()->cacheCollection(); + $documents = $collection->find([ + 'value.tags' => ['$in' => ['tag1']], + ]); + + foreach ($documents as $document) { + expect($document->value->tags[0])->toEqual('tag1') + ->and($document->value->tags[1])->toEqual('tag2') + ->and($document->value->not_value)->toEqual('notmyvalue'); + } +}); + +it('can clean expired entries', function () { + $mongodb = mongo(); + $mongodb->set('test', 'value', 5); + + $mongodb->clean(time() + 5 * 60 + 1); + + $value = $mongodb->get('test'); + + expect($value)->toBeNull(); +}); + it('will not use the cache in debug mode', function () { Mongodb::$singleton = null; diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 23d0184..8138637 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -1,8 +1,8 @@ array( 'name' => 'bnomei/kirby-mongodb', - 'pretty_version' => '1.4.2', - 'version' => '1.4.2.0', + 'pretty_version' => '1.4.3', + 'version' => '1.4.3.0', 'reference' => null, 'type' => 'kirby-plugin', 'install_path' => __DIR__ . '/../../', @@ -11,8 +11,8 @@ ), 'versions' => array( 'bnomei/kirby-mongodb' => array( - 'pretty_version' => '1.4.2', - 'version' => '1.4.2.0', + 'pretty_version' => '1.4.3', + 'version' => '1.4.3.0', 'reference' => null, 'type' => 'kirby-plugin', 'install_path' => __DIR__ . '/../../',