Skip to content

Commit 8ece615

Browse files
authored
Features: Migrations, Policies config and Models, Reactions, Comments (#7)
- Added Comment and Reaction Model - Set user model as AUTH_MODEL env by default - Set comment and reactin models by default - Added a guest-comments setting to mark whether to allow guest comments - Finished migrations for comments and reactions - Added HasReactions and HasComments concerns - Ability to toggle Reactions - Ability to set allowed reactions - Ability to add comments - Ability to fetch comments tree (base comments with their nested replies) - Ability to delete a comment if it belongs to you (untested) - Ability to set whether to allow multiple reactions or not - Ability to set whether to allow guest comments and reactions or not
2 parents b1236c5 + f0f7eb9 commit 8ece615

File tree

11 files changed

+411
-8
lines changed

11 files changed

+411
-8
lines changed

.github/workflows/fix-php-code-style-issues.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,11 @@ jobs:
3737
branch: php-style-fixes
3838
title: Fix PHP Code Styling
3939
labels: code-style
40-
auto-merge: true
4140
delete-branch: true
41+
42+
- name: Auto-merge Pull Request
43+
uses: pascalgn/automerge-action@v0.16.4
44+
with:
45+
merge-method: squash
46+
env:
47+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"require": {
2323
"php": "^8.2",
2424
"filament/filament": "^3",
25+
"kalnoy/nestedset": "^6.0",
2526
"spatie/laravel-package-tools": "^1.15.0"
2627
},
2728
"require-dev": {
@@ -71,4 +72,4 @@
7172
},
7273
"minimum-stability": "dev",
7374
"prefer-stable": true
74-
}
75+
}

config/nested-comments.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
<?php
22

3-
// config for Coolsam/NestedComments
43
return [
4+
'tables' => [
5+
'comments' => 'comments',
6+
'reactions' => 'reactions',
7+
'users' => 'users', // The table that will be used to get the authenticated user
8+
],
59

10+
'models' => [
11+
'comment' => \Coolsam\NestedComments\Models\Comment::class,
12+
'reaction' => \Coolsam\NestedComments\Models\Reaction::class,
13+
'user' => env( 'AUTH_MODEL', 'App\Models\User'), // The model that will be used to get the authenticated user
14+
],
15+
16+
'policies' => [
17+
'comment' => null,
18+
'reaction' => null,
19+
],
20+
'allowed-reactions' => [
21+
'👍', // thumbs up
22+
'👎', // thumbs down
23+
'❤️', // heart
24+
'😂', // laughing
25+
'😮', // surprised
26+
'😢', // crying
27+
'😡', // angry
28+
'🔥', // fire
29+
'🎉', // party popper
30+
'🚀', // rocket
31+
],
32+
'allow-multiple-reactions' => env('ALLOW_MULTIPLE_REACTIONS', false), // Allow multiple reactions from the same user
33+
'allow-guest-reactions' => env('ALLOW_GUEST_REACTIONS', false), // Allow guest users to react
34+
'allow-guest-comments' => env('ALLOW_GUEST_COMMENTS', false), // Allow guest users to comment
635
];

database/migrations/create_nested_comments_table.php.stub

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,37 @@
22

33
use Illuminate\Database\Migrations\Migration;
44
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Config;
56
use Illuminate\Support\Facades\Schema;
67

78
return new class extends Migration
89
{
910
public function up()
1011
{
11-
Schema::create('nested_comments_table', function (Blueprint $table) {
12+
$users = Config::get('nested-comments.tables.users', 'users');
13+
Schema::create(Config::get('nested-comments.tables.comments'), function (Blueprint $table) use ($users) {
1214
$table->id();
15+
$table->nestedSet();
16+
$table->foreignId('user_id')->nullable()->constrained($users)->cascadeOnDelete();
17+
$table->text('body');
18+
$table->morphs('commentable');
19+
$table->ipAddress()->nullable();
20+
$table->timestamps();
21+
});
1322

14-
// add fields
15-
23+
Schema::create(Config::get('nested-comments.tables.reactions'), function (Blueprint $table) use ($users) {
24+
$table->id();
25+
$table->foreignId('user_id')->nullable()->constrained($users)->cascadeOnDelete();
26+
$table->morphs('reactable');
27+
$table->string('emoji');
28+
$table->ipAddress()->nullable();
1629
$table->timestamps();
1730
});
1831
}
32+
33+
public function down()
34+
{
35+
Schema::dropIfExists(Config::get('nested-comments.tables.reactions'));
36+
Schema::dropIfExists(Config::get('nested-comments.tables.comments'));
37+
}
1938
};

package-lock.json

Lines changed: 135 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@tailwindcss/typography": "^0.5.9",
1717
"autoprefixer": "^10.4.14",
1818
"esbuild": "^0.25.2",
19+
"flowbite": "^3.1.2",
1920
"npm-run-all": "^4.1.5",
2021
"postcss": "^8.4.26",
2122
"postcss-import": "^15.1.0",

src/Concerns/HasComments.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
namespace Coolsam\NestedComments\Concerns;
4+
5+
use Coolsam\NestedComments\Models\Comment;
6+
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\MorphMany;
8+
9+
/**
10+
* @mixin Model
11+
*/
12+
trait HasComments
13+
{
14+
public function comments(): MorphMany
15+
{
16+
return $this->morphMany(config('nested-comments.models.comment'), 'commentable');
17+
}
18+
19+
public function getCommentsCountAttribute(): int
20+
{
21+
return $this->comments()->count();
22+
}
23+
24+
public function getCommentsTree($offset = null, $limit = null, $columns = ['*'])
25+
{
26+
$query = $this->comments()
27+
->getQuery()
28+
->where('parent_id', '=', null);
29+
if (filled($offset)) {
30+
$query->offset($offset);
31+
}
32+
if (filled($limit)) {
33+
$query->limit($limit);
34+
}
35+
36+
$columns = ['id', 'parent_id', '_lft', '_rgt', ...$columns];
37+
38+
return collect($query->get($columns)->map(function (Comment $comment) use ($columns) {
39+
$descendants = $comment->getDescendants($columns);
40+
return collect($comment->toArray())->put('descendants', $descendants->toArray());
41+
})->toArray());
42+
}
43+
44+
/**
45+
* @throws \Exception
46+
*/
47+
public function addComment(string $comment, mixed $parentId = null)
48+
{
49+
$allowGuest = config('nested-comments.allow-guest-comments', false);
50+
if (! $allowGuest && ! auth()->check()) {
51+
throw new \Exception('You must be logged in to comment.');
52+
}
53+
54+
if ($allowGuest && ! auth()->check()) {
55+
$userId = null;
56+
} else {
57+
$userId = auth()->id();
58+
}
59+
60+
return $this->comments()->create([
61+
'user_id' => $userId,
62+
'body' => $comment,
63+
'commentable_id' => $this->getKey(),
64+
'commentable_type' => $this->getMorphClass(),
65+
'parent_id' => $parentId,
66+
'ip_address' => request()->ip(),
67+
]);
68+
}
69+
70+
/**
71+
* @throws \Exception
72+
*/
73+
public function deleteComment(Comment $comment): ?bool
74+
{
75+
if (! auth()->check()) {
76+
throw new \Exception('You must be logged in to delete your comment.');
77+
}
78+
79+
if ($comment->getAttribute('user_id') !== auth()->id()) {
80+
throw new \Exception('You are not authorized to delete this comment.');
81+
}
82+
83+
return $comment->delete();
84+
}
85+
}

0 commit comments

Comments
 (0)