Skip to content

Commit d5ede8e

Browse files
committed
Added many-to-many flush
1 parent 1731455 commit d5ede8e

File tree

9 files changed

+238
-7
lines changed

9 files changed

+238
-7
lines changed

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@
3030
"test": "vendor/bin/phpunit"
3131
},
3232
"require-dev": {
33+
"chelout/laravel-relationship-events": "^1.4",
3334
"laravel/legacy-factories": "^1.1",
3435
"mockery/mockery": "^1.4",
35-
"orchestra/testbench": "^5.0|^6.0",
36-
"orchestra/database": "^5.0|^6.0"
36+
"orchestra/database": "^5.0|^6.0",
37+
"orchestra/testbench": "^5.0|^6.0"
3738
},
3839
"config": {
3940
"sort-packages": true

src/FlushQueryCacheObserver.php

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,103 @@ public function restored(Model $model)
6262
$this->invalidateCache($model);
6363
}
6464

65+
/**
66+
* Invalidate attach for belongsToMany.
67+
*
68+
* @param string $relation
69+
* @param \Illuminate\Database\Eloquent\Model $model
70+
* @param array $ids
71+
* @return void
72+
*/
73+
public function belongsToManyAttached($relation, Model $model, $ids)
74+
{
75+
$this->invalidateCache($model, $relation, $model->{$relation}()->findMany($ids));
76+
}
77+
78+
/**
79+
* Invalidate detach for belongsToMany.
80+
*
81+
* @param string $relation
82+
* @param \Illuminate\Database\Eloquent\Model $model
83+
* @param array $ids
84+
* @return void
85+
*/
86+
public function belongsToManyDetached($relation, Model $model, $ids)
87+
{
88+
$this->invalidateCache($model, $relation, $model->{$relation}()->findMany($ids));
89+
}
90+
91+
/**
92+
* Invalidate update pivot for belongsToMany.
93+
*
94+
* @param string $relation
95+
* @param \Illuminate\Database\Eloquent\Model $model
96+
* @param array $ids
97+
* @return void
98+
*/
99+
public function belongsToManyUpdatedExistingPivot($relation, Model $model, $ids)
100+
{
101+
$this->invalidateCache($model, $relation, $model->{$relation}()->findMany($ids));
102+
}
103+
104+
/**
105+
* Invalidate attach for morphToMany.
106+
*
107+
* @param string $relation
108+
* @param \Illuminate\Database\Eloquent\Model $model
109+
* @param array $ids
110+
* @return void
111+
*/
112+
public function morphToManyAttached($relation, Model $model, $ids)
113+
{
114+
$this->invalidateCache($model, $relation, $model->{$relation}()->findMany($ids));
115+
}
116+
117+
/**
118+
* Invalidate detach for morphToMany.
119+
*
120+
* @param string $relation
121+
* @param \Illuminate\Database\Eloquent\Model $model
122+
* @param array $ids
123+
* @return void
124+
*/
125+
public function morphToManyDetached($relation, Model $model, $ids)
126+
{
127+
$this->invalidateCache($model, $relation, $model->{$relation}()->findMany($ids));
128+
}
129+
130+
/**
131+
* Invalidate update pivot for morphToMany.
132+
*
133+
* @param string $relation
134+
* @param \Illuminate\Database\Eloquent\Model $model
135+
* @param array $ids
136+
* @return void
137+
*/
138+
public function morphToManyUpdatedExistingPivot($relation, Model $model, $ids)
139+
{
140+
$this->invalidateCache($model, $relation, $model->{$relation}()->findMany($ids));
141+
}
142+
65143
/**
66144
* Invalidate the cache for a model.
67145
*
68146
* @param \Illuminate\Database\Eloquent\Model $model
147+
* @param string|null $relation
148+
* @param \Illuminate\Database\Eloquent\Collection|null $pivotedModels
69149
* @return void
70150
* @throws Exception
71151
*/
72-
protected function invalidateCache(Model $model): void
152+
protected function invalidateCache(Model $model, $relation = null, $pivotedModels = null): void
73153
{
74154
$class = get_class($model);
75155

76-
if (! $model->getCacheTagsToInvalidateOnUpdate()) {
156+
if (! $model->getCacheTagsToInvalidateOnUpdate($relation, $pivotedModels)) {
77157
throw new Exception('Automatic invalidation for '.$class.' works only if at least one tag to be invalidated is specified.');
78158
}
79159

80160
$class::flushQueryCache(
81-
$model->getCacheTagsToInvalidateOnUpdate()
161+
$model->getCacheTagsToInvalidateOnUpdate($relation, $pivotedModels)
82162
);
83163
}
84164
}

src/Traits/QueryCacheable.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ protected static function getFlushQueryCacheObserver()
5050
* When invalidating automatically on update, you can specify
5151
* which tags to invalidate.
5252
*
53+
* @param string|null $relation
54+
* @param \Illuminate\Database\Eloquent\Collection|null $pivotedModels
5355
* @return array
5456
*/
55-
public function getCacheTagsToInvalidateOnUpdate(): array
57+
public function getCacheTagsToInvalidateOnUpdate($relation = null, $pivotedModels = null): array
5658
{
5759
return $this->getCacheBaseTags();
5860
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Rennokki\QueryCache\Test;
4+
5+
use Rennokki\QueryCache\Test\Models\User;
6+
use Rennokki\QueryCache\Test\Models\Role;
7+
8+
class FlushCacheOnUpdatePivotTest extends TestCase
9+
{
10+
public function test_belongs_to_many()
11+
{
12+
$key = 'leqc:sqlitegetselect "roles".*, "role_user"."user_id" as "pivot_user_id", "role_user"."role_id" as "pivot_role_id" from "roles" inner join "role_user" on "roles"."id" = "role_user"."role_id" where "role_user"."user_id" = ? limit 1a:1:{i:0;i:1;}';
13+
14+
$user = factory(User::class)->create();
15+
$role = factory(Role::class)->create();
16+
$storedRoles = $user->roles()->cacheFor(now()->addHours(1))->cacheTags(["user:{$user->id}:roles"])->get();
17+
$cache = $this->getCacheWithTags($key, ["user:{$user->id}:roles"]);
18+
19+
$this->assertNull($cache);
20+
$this->assertEquals(0, $storedRoles->count());
21+
22+
$user->roles()->attach($role->id);
23+
24+
$storedRoles = $user->roles()->cacheFor(now()->addHours(1))->cacheTags(["user:{$user->id}:roles"])->get();
25+
26+
$this->assertEquals(
27+
$role->id,
28+
$storedRoles->first()->id
29+
);
30+
31+
$user->roles()->detach($role->id);
32+
33+
$storedRoles = $user->roles()->cacheFor(now()->addHours(1))->cacheTags(["user:{$user->id}:roles"])->get();
34+
35+
$this->assertEquals(0, $storedRoles->count());
36+
}
37+
}

tests/Models/Kid.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class Kid extends Model
99
{
1010
use QueryCacheable;
1111

12+
protected $cacheUsePlainKey = true;
13+
1214
protected $fillable = [
1315
'name',
1416
];

tests/Models/Role.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Rennokki\QueryCache\Test\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use Rennokki\QueryCache\Traits\QueryCacheable;
7+
8+
class Role extends Model
9+
{
10+
use QueryCacheable;
11+
12+
protected $cacheUsePlainKey = true;
13+
14+
protected $fillable = [
15+
'name',
16+
];
17+
18+
protected function getCacheBaseTags(): array
19+
{
20+
return [
21+
//
22+
];
23+
}
24+
}

tests/Models/User.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@
22

33
namespace Rennokki\QueryCache\Test\Models;
44

5+
use Chelout\RelationshipEvents\Concerns\HasBelongsToManyEvents;
6+
use Chelout\RelationshipEvents\Traits\HasRelationshipObservables;
57
use Illuminate\Foundation\Auth\User as Authenticatable;
68
use Rennokki\QueryCache\Traits\QueryCacheable;
79

810
class User extends Authenticatable
911
{
12+
use HasBelongsToManyEvents;
13+
use HasRelationshipObservables;
1014
use QueryCacheable;
1115

16+
protected static $flushCacheOnUpdate = true;
17+
18+
protected $cacheUsePlainKey = true;
19+
1220
protected $fillable = [
1321
'name', 'email', 'password',
1422
];
@@ -20,12 +28,32 @@ class User extends Authenticatable
2028
protected function getCacheBaseTags(): array
2129
{
2230
return [
23-
//
31+
'test',
2432
];
2533
}
2634

35+
public function getCacheTagsToInvalidateOnUpdate($relation = null, $pivotedModels = null): array
36+
{
37+
if ($relation === 'roles') {
38+
$tags = array_reduce($pivotedModels->all(), function ($tags, Role $role) {
39+
return array_merge($tags, ["user:{$this->id}:roles:{$role->id}"]);
40+
}, []);
41+
42+
return array_merge($tags, [
43+
"user:{$this->id}:roles",
44+
]);
45+
}
46+
47+
return $this->getCacheBaseTags();
48+
}
49+
2750
public function posts()
2851
{
2952
return $this->hasMany(Post::class);
3053
}
54+
55+
public function roles()
56+
{
57+
return $this->belongsToMany(Role::class);
58+
}
3159
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/*
3+
|--------------------------------------------------------------------------
4+
| Model Factories
5+
|--------------------------------------------------------------------------
6+
|
7+
| This directory should contain each of the model factory definitions for
8+
| your application. Factories provide a convenient way to generate new
9+
| model instances for testing / seeding your application's database.
10+
|
11+
*/
12+
13+
use Illuminate\Support\Str;
14+
15+
$factory->define(\Rennokki\QueryCache\Test\Models\Role::class, function () {
16+
return [
17+
'name' => 'Role'.Str::random(5),
18+
];
19+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class Roles extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('roles', function (Blueprint $table) {
17+
$table->increments('id');
18+
$table->string('name');
19+
$table->timestamps();
20+
});
21+
22+
Schema::create('role_user', function (Blueprint $table) {
23+
$table->string('user_id');
24+
$table->string('role_id');
25+
});
26+
}
27+
28+
/**
29+
* Reverse the migrations.
30+
*
31+
* @return void
32+
*/
33+
public function down()
34+
{
35+
Schema::dropIfExists('roles');
36+
Schema::dropIfExists('role_user');
37+
}
38+
}

0 commit comments

Comments
 (0)