Skip to content

Commit 723ef1c

Browse files
author
riccardodallavia
committed
UPDATE delete mark relations upon entity deletion
1 parent 5152934 commit 723ef1c

File tree

4 files changed

+127
-20
lines changed

4 files changed

+127
-20
lines changed

README.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ Default prefix is set to `markable_`.
148148
Here's an example migration for bookmarks:
149149

150150
``` php
151-
class CreateBookmarksTable extends Migration
151+
return new class extends Migration
152152
{
153153
public function up()
154154
{
@@ -164,9 +164,12 @@ class CreateBookmarksTable extends Migration
164164
}
165165
```
166166

167-
Once done, you can create a new class which extends the abstract `Mark` class and implement the `markableRelationName` method, which defines the name of the relation.
167+
Once done, you can create a new class which extends the abstract `Mark` class and implement the `markableRelationName` method, which is used to retrieve the users who marked a given model entity with the mark entity as pivot.
168168

169-
Here's an example model for bookmarks:
169+
You can also override the `markRelationName` method, which is used to retrieve the list of marks of a given model entity.
170+
By default, the relation name is the plural name of the mark class name.
171+
172+
Here's an example model for the bookmarks mark:
170173

171174
``` php
172175
<?php
@@ -181,6 +184,15 @@ class Bookmark extends Mark
181184
{
182185
return 'bookmarkers';
183186
}
187+
188+
/**
189+
* The override is useless in this case, as I am returning the default
190+
* relation name which is the plural name of the mark class name (bookmarks, indeed)
191+
*/
192+
public static function markRelationName(): string
193+
{
194+
return 'bookmarks';
195+
}
184196
}
185197
```
186198

@@ -227,15 +239,24 @@ Reaction::has($post, $user, 'heart'); // returns whether the user has reacted wi
227239
Reaction::count($post, 'person_raising_hand'); // returns the amount of 'person_raising_hand' reactions for the given post
228240
```
229241

230-
### Retrieve mark relation with eloquent
242+
### Retrieve the list of marks of an entity with eloquent
231243

232244
``` php
233245
use App\Models\Course;
234246
use App\Models\Post;
235247

236-
Course::firstOrFail()->likers; // returns the collection of likes to the given course with their user
248+
Course::firstOrFail()->likes; // returns the collection of like marks related to the course
249+
Post::firstOrFail()->reactions; // returns the collection of reaction marks related to the post
250+
```
251+
252+
### Retrieve the list of users who marked an entity with eloquent
253+
254+
``` php
255+
use App\Models\Course;
256+
use App\Models\Post;
237257

238-
Post::firstOrFail()->reacters; // returns the collection of reactions to the given post with their user and value
258+
Course::firstOrFail()->likers; // returns the collection of users who liked the course along with the mark value as pivot
259+
Post::firstOrFail()->reacters; // returns the collection of users who reacted to the post along with the mark value as pivot
239260
```
240261

241262
### Filter marked models with eloquent

src/Mark.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,17 @@
1313

1414
abstract class Mark extends MorphPivot
1515
{
16+
public $incrementing = true;
17+
1618
abstract public static function markableRelationName(): string;
1719

20+
public static function markRelationName(): string
21+
{
22+
return Str::of(
23+
class_basename(static::class)
24+
)->plural()->lower()->__toString();
25+
}
26+
1827
public static function allowedValues(): ?array
1928
{
2029
$className = Str::lower(static::getMarkClassName());

src/Markable.php

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ trait Markable
1212
public static function bootMarkable(): void
1313
{
1414
static::registerMarks();
15+
1516
static::addGlobalScope(new MarkableScope);
17+
18+
static::deleted(
19+
fn ($markable) => self::deleteMarks($markable)
20+
);
1621
}
1722

1823
public static function marks(): array
@@ -31,33 +36,52 @@ public function scopeWhereHasMark(Builder $builder, Mark $mark, Model $user, ?st
3136
);
3237
}
3338

34-
protected static function registerMarks(): void
39+
protected static function deleteMarks(self $markable): void
3540
{
36-
foreach (static::marks() as $mark) {
37-
static::registerMark($mark);
41+
foreach (static::marks() as $markClass) {
42+
$markModel = self::getMarkModelInstance($markClass);
43+
44+
$markRelationName = $markModel->markRelationName();
45+
46+
$markable->$markRelationName()->delete();
3847
}
3948
}
4049

41-
protected static function registerMark(string $mark)
50+
protected static function registerMarks(): void
4251
{
43-
$instance = new $mark;
44-
45-
if (! $instance instanceof Mark) {
46-
throw InvalidMarkInstanceException::create();
52+
foreach (static::marks() as $markClass) {
53+
static::addMarkableRelation($markClass);
4754
}
48-
49-
static::addMarkableRelation($instance);
5055
}
5156

52-
protected static function addMarkableRelation(Mark $mark)
57+
protected static function addMarkableRelation(string $markClass): void
5358
{
59+
$markModel = self::getMarkModelInstance($markClass);
60+
5461
static::resolveRelationUsing(
55-
$mark->markableRelationName(),
62+
$markModel->markableRelationName(),
5663
fn ($markable) => $markable
57-
->morphToMany(config('markable.user_model'), 'markable', $mark->getTable())
58-
->using($mark->getMorphClass())
64+
->morphToMany(config('markable.user_model'), 'markable', $markModel->getTable())
65+
->using($markModel->getMorphClass())
5966
->withPivot('value')
6067
->withTimestamps()
6168
);
69+
70+
static::resolveRelationUsing(
71+
$markModel->markRelationName(),
72+
fn ($markable) => $markable
73+
->morphMany($markClass, 'markable')
74+
);
75+
}
76+
77+
protected static function getMarkModelInstance(string $markClass): Mark
78+
{
79+
$instance = new $markClass;
80+
81+
if (! $instance instanceof Mark) {
82+
throw InvalidMarkInstanceException::create();
83+
}
84+
85+
return $instance;
6286
}
6387
}

tests/MarkableTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,57 @@ public function can_filter_marked_models()
5656
$this->assertCount(2, Article::whereHasMark(app(Like::class), $users[0])->get());
5757
$this->assertCount(1, Article::whereHasMark(app(Like::class), $users[1])->get());
5858
}
59+
60+
/** @test */
61+
public function it_should_delete_marks_related_to_deleted_markables()
62+
{
63+
$article = Article::factory()->create();
64+
$user = User::factory()->create();
65+
66+
$mark = Like::add($article, $user);
67+
68+
$this->assertDatabaseHas($mark->getTable(), [
69+
'user_id' => $user->getKey(),
70+
'markable_id' => $article->getKey(),
71+
'markable_type' => $article->getMorphClass(),
72+
]);
73+
74+
$article->delete();
75+
76+
$this->assertDatabaseMissing($mark->getTable(), [
77+
'user_id' => $user->getKey(),
78+
'markable_id' => $article->getKey(),
79+
'markable_type' => $article->getMorphClass(),
80+
]);
81+
}
82+
83+
/** @test */
84+
public function it_should_retrieve_the_list_of_users_who_marked_an_entity()
85+
{
86+
$article = Article::factory()->create();
87+
$users = User::factory(2)->create();
88+
89+
Like::add($article, $users[0]);
90+
Like::add($article, $users[1]);
91+
92+
$this->assertEquals([
93+
$users[0]->getKey(),
94+
$users[1]->getKey(),
95+
], $article->likers->modelKeys());
96+
}
97+
98+
/** @test */
99+
public function it_should_retrieve_the_list_of_marks_of_an_entity()
100+
{
101+
$article = Article::factory()->create();
102+
$users = User::factory(2)->create();
103+
104+
$like1 = Like::add($article, $users[0]);
105+
$like2 = Like::add($article, $users[1]);
106+
107+
$this->assertEquals([
108+
$like1->getKey(),
109+
$like2->getKey(),
110+
], $article->likes->modelKeys());
111+
}
59112
}

0 commit comments

Comments
 (0)