From 4a4de057f5d057913b23cf22f28319fb51bf6bbd Mon Sep 17 00:00:00 2001 From: Kirk Bushell Date: Sun, 27 Aug 2023 14:51:35 +1000 Subject: [PATCH] Fixing a few bugs, cleaning up tests by adding factories, making it much easier to expand on additional features and testing. --- src/Behaviours/Cacheable.php | 2 - src/Behaviours/CountCache/CountCache.php | 3 +- src/Behaviours/SumCache/SumCache.php | 4 +- src/Behaviours/SumCache/Summable.php | 6 +- tests/Acceptance/AcceptanceTestCase.php | 12 +++- tests/Acceptance/ChainedAggregatesTest.php | 18 ++++++ tests/Acceptance/CountCacheTest.php | 65 ++++++--------------- tests/Acceptance/Models/Category.php | 19 ++++++ tests/Acceptance/Models/CategoryFactory.php | 15 +++++ tests/Acceptance/Models/Comment.php | 13 +++++ tests/Acceptance/Models/CommentFactory.php | 18 ++++++ tests/Acceptance/Models/Item.php | 8 +++ tests/Acceptance/Models/ItemFactory.php | 15 +++++ tests/Acceptance/Models/Order.php | 8 +++ tests/Acceptance/Models/OrderFactory.php | 15 +++++ tests/Acceptance/Models/Post.php | 30 +++++++++- tests/Acceptance/Models/PostFactory.php | 18 ++++++ tests/Acceptance/Models/User.php | 8 +++ tests/Acceptance/Models/UserFactory.php | 18 ++++++ tests/Acceptance/SluggedTest.php | 14 +---- tests/Acceptance/SumCacheTest.php | 2 +- 21 files changed, 242 insertions(+), 69 deletions(-) create mode 100644 tests/Acceptance/ChainedAggregatesTest.php create mode 100644 tests/Acceptance/Models/Category.php create mode 100644 tests/Acceptance/Models/CategoryFactory.php create mode 100644 tests/Acceptance/Models/CommentFactory.php create mode 100644 tests/Acceptance/Models/ItemFactory.php create mode 100644 tests/Acceptance/Models/OrderFactory.php create mode 100644 tests/Acceptance/Models/PostFactory.php create mode 100644 tests/Acceptance/Models/UserFactory.php diff --git a/src/Behaviours/Cacheable.php b/src/Behaviours/Cacheable.php index 5d908f8..cfbc0f5 100644 --- a/src/Behaviours/Cacheable.php +++ b/src/Behaviours/Cacheable.php @@ -3,8 +3,6 @@ use Closure; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\DB; -use Illuminate\Support\Str; /** * The cacheable trait is concerned with the related models. diff --git a/src/Behaviours/CountCache/CountCache.php b/src/Behaviours/CountCache/CountCache.php index 8e324ee..5da735b 100644 --- a/src/Behaviours/CountCache/CountCache.php +++ b/src/Behaviours/CountCache/CountCache.php @@ -28,7 +28,8 @@ public function update(): void $this->apply(function(CacheConfig $config) { $foreignKey = $config->foreignKeyName($this->model); - if (!$this->model->getOriginal($foreignKey) || $this->model->$foreignKey === $this->model->getOriginal($foreignKey)) return; + // We only need to do anything if the foreign key was changed. + if (!$this->model->wasChanged($foreignKey)) return; // for the minus operation, we first have to get the model that is no longer associated with this one. $originalRelatedModel = $config->emptyRelatedModel($this->model)->find($this->model->getOriginal($foreignKey)); diff --git a/src/Behaviours/SumCache/SumCache.php b/src/Behaviours/SumCache/SumCache.php index 6fb9e99..d708669 100644 --- a/src/Behaviours/SumCache/SumCache.php +++ b/src/Behaviours/SumCache/SumCache.php @@ -31,14 +31,14 @@ public function rebuild(): void public function increase(): void { $this->apply(function(CacheConfig $config) { - $this->updateCacheValue($config->relatedModel($this->model), $config, $this->model->{$config->sourceField}); + $this->updateCacheValue($config->relatedModel($this->model), $config, (int) $this->model->{$config->sourceField}); }); } public function decrease(): void { $this->apply(function(CacheConfig $config) { - $this->updateCacheValue($config->relatedModel($this->model), $config, -$this->model->{$config->sourceField}); + $this->updateCacheValue($config->relatedModel($this->model), $config, -(int) $this->model->{$config->sourceField}); }); } diff --git a/src/Behaviours/SumCache/Summable.php b/src/Behaviours/SumCache/Summable.php index 007f503..607f9f9 100644 --- a/src/Behaviours/SumCache/Summable.php +++ b/src/Behaviours/SumCache/Summable.php @@ -13,7 +13,11 @@ interface Summable * * Of course, if you want to customise the field saving the total as well, you can do that too: * - * ['order' => ['amount' => 'total_amount']]. + * ['relationshp' => ['aggregate_field' => 'source_field']] + * + * In real-world terms: + * + * ['order' => ['total_amount' => 'amount']] * * By default, the sum cache will take the source field, and add "_total" to it on the related model. * diff --git a/tests/Acceptance/AcceptanceTestCase.php b/tests/Acceptance/AcceptanceTestCase.php index 6c6dca1..939f5d4 100644 --- a/tests/Acceptance/AcceptanceTestCase.php +++ b/tests/Acceptance/AcceptanceTestCase.php @@ -33,8 +33,8 @@ private function migrate() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); - $table->string('first_name'); - $table->string('last_name'); + $table->string('first_name')->nullable(); + $table->string('last_name')->nullable(); $table->string('slug')->nullable(); $table->integer('comment_count')->default(0); $table->integer('post_count')->default(0); @@ -43,6 +43,7 @@ private function migrate() Schema::create('posts', function (Blueprint $table) { $table->increments('id'); + $table->integer('category_id')->nullable(); $table->integer('user_id')->nullable(); $table->string('slug')->nullable(); $table->integer('comment_count')->default(0); @@ -69,5 +70,12 @@ private function migrate() $table->integer('amount'); $table->timestamps(); }); + + Schema::create('categories', function (Blueprint $table) { + $table->increments('id'); + $table->integer('post_count')->default(0); + $table->integer('total_comments')->default(0); + $table->timestamps(); + }); } } diff --git a/tests/Acceptance/ChainedAggregatesTest.php b/tests/Acceptance/ChainedAggregatesTest.php new file mode 100644 index 0000000..6a6d65a --- /dev/null +++ b/tests/Acceptance/ChainedAggregatesTest.php @@ -0,0 +1,18 @@ +create(); + + $this->assertSame(1, Category::first()->postCount); + $this->assertSame(1, Category::first()->totalComments); + } +} \ No newline at end of file diff --git a/tests/Acceptance/CountCacheTest.php b/tests/Acceptance/CountCacheTest.php index a296aab..e246c48 100644 --- a/tests/Acceptance/CountCacheTest.php +++ b/tests/Acceptance/CountCacheTest.php @@ -1,76 +1,49 @@ data = $this->setupUserAndPost(); - } - function test_userHasASinglePostCount() { - $user = User::first(); + $user = User::factory()->create(); - $this->assertEquals(1, $user->postCount); + Post::factory()->for($user)->create(); + + $this->assertEquals(1, $user->fresh()->postCount); } function test_whenRelatedModelsAreSwitchedBothCountCachesAreUpdated() { - $post = new Post; - $post->userId = $this->data['user']->id; - $post->save(); - - $comment = new Comment; - $comment->userId = $this->data['user']->id; - $comment->postId = $this->data['post']->id; - $comment->save(); + $user1 = User::factory()->create(); + $user2 = User::factory()->create(); + $posts = Post::factory()->count(2)->for($user1)->create(); + $comment = Comment::factory()->for($user1)->for($posts->first())->create(); - $this->assertEquals(2, User::first()->postCount); - $this->assertEquals(1, User::first()->commentCount); - $this->assertEquals(1, Post::first()->commentCount); + $this->assertEquals(2, $user1->fresh()->postCount); + $this->assertEquals(1, $user1->fresh()->commentCount); + $this->assertEquals(1, $posts->first()->fresh()->commentCount); $comment = $comment->fresh(); - $comment->postId = $post->id; + $comment->userId = $user2->id; $comment->save(); - $this->assertEquals(0, $this->data['post']->fresh()->commentCount); - $this->assertEquals(1, $post->fresh()->commentCount); + $this->assertEquals(0, $user1->fresh()->commentCount); + $this->assertEquals(1, $user2->fresh()->commentCount); } - public function testItCanHandleNegativeCounts() + public function testItCanHandleModelRestoration() { - $post = new Post; - $post->userId = $this->data['user']->id; - $post->save(); + $post = Post::factory()->create(); - $comment = new Comment; - $comment->userId = $this->data['user']->id; - $comment->postId = $this->data['post']->id; - $comment->save(); + $comment = Comment::factory()->for($post)->create(); $comment->delete(); $comment->restore(); - $this->assertEquals(1, Post::first()->commentCount); - } - - private function setupUserAndPost() - { - $user = new User; - $user->firstName = 'Kirk'; - $user->lastName = 'Bushell'; - $user->save(); - - $post = new Post; - $post->userId = $user->id; - $post->save(); - - return compact('user', 'post'); + $this->assertEquals(1, $post->fresh()->commentCount); } } diff --git a/tests/Acceptance/Models/Category.php b/tests/Acceptance/Models/Category.php new file mode 100644 index 0000000..cf0c985 --- /dev/null +++ b/tests/Acceptance/Models/Category.php @@ -0,0 +1,19 @@ +belongsTo(Post::class); @@ -28,4 +36,9 @@ public function countedBy(): array { return ['post', 'user']; } + + protected static function newFactory(): Factory + { + return CommentFactory::new(); + } } diff --git a/tests/Acceptance/Models/CommentFactory.php b/tests/Acceptance/Models/CommentFactory.php new file mode 100644 index 0000000..8337cf2 --- /dev/null +++ b/tests/Acceptance/Models/CommentFactory.php @@ -0,0 +1,18 @@ + Post::factory(), + 'user_id' => User::factory(), + ]; + } +} \ No newline at end of file diff --git a/tests/Acceptance/Models/Item.php b/tests/Acceptance/Models/Item.php index 41f9f02..4658e98 100644 --- a/tests/Acceptance/Models/Item.php +++ b/tests/Acceptance/Models/Item.php @@ -4,12 +4,15 @@ use Eloquence\Behaviours\SumCache\HasSums; use Eloquence\Behaviours\CamelCased; use Eloquence\Behaviours\SumCache\Summable; +use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Item extends Model implements Summable { use CamelCased; use HasSums; + use HasFactory; public function summedBy(): array { @@ -20,4 +23,9 @@ public function order() { return $this->belongsTo(Order::class); } + + protected static function newFactory(): Factory + { + return ItemFactory::new(); + } } diff --git a/tests/Acceptance/Models/ItemFactory.php b/tests/Acceptance/Models/ItemFactory.php new file mode 100644 index 0000000..4bf070e --- /dev/null +++ b/tests/Acceptance/Models/ItemFactory.php @@ -0,0 +1,15 @@ +hasMany(Item::class); } + + protected static function newFactory(): Factory + { + return OrderFactory::new(); + } } diff --git a/tests/Acceptance/Models/OrderFactory.php b/tests/Acceptance/Models/OrderFactory.php new file mode 100644 index 0000000..4e4a04d --- /dev/null +++ b/tests/Acceptance/Models/OrderFactory.php @@ -0,0 +1,15 @@ +belongsTo(Category::class); + } + + public function summedBy(): array + { + return ['category' => ['total_comments' => 'comment_count']]; + } + + protected static function newFactory(): Factory + { + return PostFactory::new(); + } } diff --git a/tests/Acceptance/Models/PostFactory.php b/tests/Acceptance/Models/PostFactory.php new file mode 100644 index 0000000..b46c77b --- /dev/null +++ b/tests/Acceptance/Models/PostFactory.php @@ -0,0 +1,18 @@ + Category::factory(), + 'user_id' => User::factory(), + ]; + } +} \ No newline at end of file diff --git a/tests/Acceptance/Models/User.php b/tests/Acceptance/Models/User.php index e53295d..0a91b6b 100644 --- a/tests/Acceptance/Models/User.php +++ b/tests/Acceptance/Models/User.php @@ -3,15 +3,23 @@ use Eloquence\Behaviours\CamelCased; use Eloquence\Behaviours\Sluggable; +use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class User extends Model { use CamelCased; + use HasFactory; use Sluggable; public function slugStrategy() { return ['firstName', 'lastName']; } + + protected static function newFactory(): Factory + { + return UserFactory::new(); + } } diff --git a/tests/Acceptance/Models/UserFactory.php b/tests/Acceptance/Models/UserFactory.php new file mode 100644 index 0000000..357e7f1 --- /dev/null +++ b/tests/Acceptance/Models/UserFactory.php @@ -0,0 +1,18 @@ + fake()->firstName(), + 'lastName' => fake()->lastName(), + ]; + } +} \ No newline at end of file diff --git a/tests/Acceptance/SluggedTest.php b/tests/Acceptance/SluggedTest.php index 7a4be28..d01a4e8 100644 --- a/tests/Acceptance/SluggedTest.php +++ b/tests/Acceptance/SluggedTest.php @@ -8,24 +8,14 @@ class SluggedTest extends AcceptanceTestCase { function test_slugsCanBeGeneratedWithCustomStrategy() { - $user = new User; - $user->firstName = 'Kirk'; - $user->lastName = 'Bushell'; - $user->save(); + $user = User::factory(['firstName' => 'Kirk', 'lastName' => 'Bushell'])->create(); $this->assertEquals('kirk-bushell', (string) $user->slug); } function test_slugsCanBeGeneratedUsingRandomValues() { - $user = new User; - $user->firstName = 'Kirk'; - $user->lastName = 'Bushell'; - $user->save(); - - $post = new Post; - $post->userId = $user->id; - $post->save(); + $post = Post::factory()->create(); $this->assertMatchesRegularExpression('/^[a-z0-9]{8}$/i', (string) $post->slug); } diff --git a/tests/Acceptance/SumCacheTest.php b/tests/Acceptance/SumCacheTest.php index 9e80f42..70a1ecf 100644 --- a/tests/Acceptance/SumCacheTest.php +++ b/tests/Acceptance/SumCacheTest.php @@ -6,7 +6,7 @@ class SumCacheTest extends AcceptanceTestCase { - private $data = []; + private array $data = []; public function init() {