diff --git a/src/Behaviours/Cacheable.php b/src/Behaviours/Cacheable.php index 7debde8..a2855df 100644 --- a/src/Behaviours/Cacheable.php +++ b/src/Behaviours/Cacheable.php @@ -22,6 +22,14 @@ trait Cacheable */ abstract private function configuration(): array; + /** + * Template method for setting up the CacheConfig object. + */ + protected function config($relationName, $aggregateField): CacheConfig + { + return new CacheConfig($relationName, $aggregateField); + } + /** * Helper method for easier use of the implementing classes. */ @@ -101,9 +109,9 @@ public function rebuildCacheRecord(CacheConfig $config, Model $model, $command): /** * Update the cache value for the model. */ - protected function updateCacheValue(Model $model, CacheConfig $config, int $amount): void + protected function updateCacheValue(Model $model, CacheConfig $config, $value): void { - $model->{$config->aggregateField} = $model->{$config->aggregateField} + $amount; + $model->{$config->aggregateField} = $model->{$config->aggregateField} + $value; $model->save(); } } diff --git a/src/Behaviours/CountCache/CountCache.php b/src/Behaviours/CountCache/CountCache.php index db2f617..672fd56 100644 --- a/src/Behaviours/CountCache/CountCache.php +++ b/src/Behaviours/CountCache/CountCache.php @@ -71,12 +71,4 @@ public function decrement(): void $this->updateCacheValue($config->relatedModel($this->model), $config, -1); }); } - - /** - * Takes a registered counter cache, and setups up defaults. - */ - protected function config($key, string $value): CacheConfig - { - return new CacheConfig($key, $value); - } } diff --git a/src/Behaviours/CountCache/HasCounts.php b/src/Behaviours/CountCache/HasCounts.php index 148cc25..61a4854 100644 --- a/src/Behaviours/CountCache/HasCounts.php +++ b/src/Behaviours/CountCache/HasCounts.php @@ -4,7 +4,7 @@ trait HasCounts { - public static function bootHasCounts() + public static function bootHasCounts(): void { static::observe(Observer::class); } diff --git a/src/Behaviours/SumCache/HasSums.php b/src/Behaviours/SumCache/HasSums.php index 4745410..965cea7 100644 --- a/src/Behaviours/SumCache/HasSums.php +++ b/src/Behaviours/SumCache/HasSums.php @@ -4,7 +4,7 @@ trait HasSums { - public static function bootHasSums() + public static function bootHasSums(): void { static::observe(Observer::class); } diff --git a/src/Behaviours/SumCache/SumCache.php b/src/Behaviours/SumCache/SumCache.php index 0b896ab..0d0e198 100644 --- a/src/Behaviours/SumCache/SumCache.php +++ b/src/Behaviours/SumCache/SumCache.php @@ -68,13 +68,13 @@ public function update(): void /** * Takes a registered sum cache, and setups up defaults. */ - protected function config($relation, string|array $sourceField): CacheConfig + protected function config($relationName, $sourceField): CacheConfig { $keys = array_keys($sourceField); $aggregateField = $keys[0]; $sourceField = $sourceField[$aggregateField]; - return new CacheConfig($relation, $aggregateField, $sourceField); + return new CacheConfig($relationName, $aggregateField, $sourceField); } } diff --git a/src/Behaviours/ValueCache/HasValues.php b/src/Behaviours/ValueCache/HasValues.php new file mode 100644 index 0000000..7ca5daa --- /dev/null +++ b/src/Behaviours/ValueCache/HasValues.php @@ -0,0 +1,16 @@ +rebuild(); + } +} \ No newline at end of file diff --git a/src/Behaviours/ValueCache/Observer.php b/src/Behaviours/ValueCache/Observer.php new file mode 100644 index 0000000..477c17b --- /dev/null +++ b/src/Behaviours/ValueCache/Observer.php @@ -0,0 +1,16 @@ +updateRelated(true); + } + + public function updated($model): void + { + ValueCache::for($model)->updateRelated(false); + } +} \ No newline at end of file diff --git a/src/Behaviours/ValueCache/ValueCache.php b/src/Behaviours/ValueCache/ValueCache.php new file mode 100644 index 0000000..ecf11f0 --- /dev/null +++ b/src/Behaviours/ValueCache/ValueCache.php @@ -0,0 +1,55 @@ +apply(function(CacheConfig $config) use ($new) { + $foreignKey = $config->foreignKeyName($this->model); + + // We only do work if the model previously existed and the source field has changed, or the model was newly created in the database. + if (!($new || $this->model->wasChanged($config->sourceField))) { + return; + } + + $relatedModel = $config->emptyRelatedModel($this->model)->find($this->model->$foreignKey); + + $relatedModel->{$config->aggregateField} = $this->model->{$config->sourceField}; + $relatedModel->save(); + }); + } + + private function configuration(): array + { + return $this->reflect(ValuedBy::class, function (array $config) { + return [$config['name'] => [$config['attribute']->as => $config['attribute']->from]]; + }); + } +} diff --git a/src/Behaviours/ValueCache/ValuedBy.php b/src/Behaviours/ValueCache/ValuedBy.php new file mode 100644 index 0000000..8e2ce07 --- /dev/null +++ b/src/Behaviours/ValueCache/ValuedBy.php @@ -0,0 +1,13 @@ +integer('user_id')->nullable(); $table->string('slug')->nullable(); $table->integer('comment_count')->default(0); + $table->dateTime('publish_at')->nullable(); $table->timestamps(); }); @@ -85,6 +86,7 @@ private function migrate() $table->increments('id'); $table->integer('post_count')->default(0); $table->integer('total_comments')->default(0); + $table->dateTime('last_activity_at')->nullable(); $table->timestamps(); }); } diff --git a/tests/Acceptance/ModelTest.php b/tests/Acceptance/ModelTest.php new file mode 100644 index 0000000..589a757 --- /dev/null +++ b/tests/Acceptance/ModelTest.php @@ -0,0 +1,8 @@ +belongsTo(Category::class); diff --git a/tests/Acceptance/ValueCacheTest.php b/tests/Acceptance/ValueCacheTest.php new file mode 100644 index 0000000..6e9a775 --- /dev/null +++ b/tests/Acceptance/ValueCacheTest.php @@ -0,0 +1,20 @@ +create(); + + $this->assertNull($category->last_activity_at); + + $post = Post::factory()->create(['category_id' => $category->id, 'publish_at' => now()->subDays(mt_rand(1, 10))]); + + $this->assertEquals($category->fresh()->last_activity_at, $post->publish_at); + } +}