diff --git a/README.md b/README.md index 3296d3c..fd1135c 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ php artisan vendor:publish --provider="BeyondCode\Comments\CommentsServiceProvid To let your models be able to receive comments, add the `HasComments` trait to the model classes. -``` php +```php namespace App\Models; use Illuminate\Database\Eloquent\Model; @@ -146,10 +146,36 @@ $comment = BeyondCode\Comments\Comment::first(); $comment->commentAsUser($user, "Hey there!"); ``` +#### Deleting Replies + +When you delete a comment, you may optionally want to delete all it's nested comments (replies). To do optionally enable this feature, set the `delete_replies_along_comments` config property in the `configs/comments.php` file to `true`. + +### Events + +When a new comment is added the `BeyondCode\Comments\Events\CommentAdded` event will be dispatched. +When a comment is deleted the `BeyondCode\Comments\Events\CommentDeleted` event will be dispatched. +you can listen to these event and do other things as your requirements call for. + +_App\Providers\EventServiceProvider_ + +```php +use BeyondCode\Comments\Events\CommentAdded; +use BeyondCode\Comments\Events\CommentDeleted; +use App\Listeners\InformAdmin; + +protected $listen = [ + CommentAdded::class => [ + InformAdmin::class, + ], + CommentDeleted::class => [ + InformAdmin::class, + ], +]; +``` ### Testing -``` bash +```bash composer test ``` @@ -167,8 +193,8 @@ If you discover any security related issues, please email marcel@beyondco.de ins ## Credits -- [Marcel Pociot](https://github.com/mpociot) -- [All Contributors](../../contributors) +- [Marcel Pociot](https://github.com/mpociot) +- [All Contributors](../../contributors) ## License diff --git a/composer.json b/composer.json index 24bb795..5888f7c 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ } }, "scripts": { - "test": "vendor/bin/phpunit", + "test": "XDEBUG_MODE=coverage vendor/bin/phpunit", "test-coverage": "vendor/bin/phpunit --coverage-html coverage" }, "config": { diff --git a/config/config.php b/config/config.php index 9c3c85b..57cf44a 100644 --- a/config/config.php +++ b/config/config.php @@ -15,4 +15,8 @@ return [ */ 'user_model' => null, -]; \ No newline at end of file + /** + * Determines if replies will be deleted when comments are deleted + */ + 'delete_replies_along_comments' => false, +]; diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7bab00e..f303f02 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,28 +1,33 @@ - + + + + src/ + + + + + + + tests - - - src/ - - - - - - + diff --git a/phpunit.xml.dist.bak b/phpunit.xml.dist.bak new file mode 100644 index 0000000..ff916d0 --- /dev/null +++ b/phpunit.xml.dist.bak @@ -0,0 +1,29 @@ + + + + + tests + + + + + src/ + + + + + + + + + diff --git a/src/Comment.php b/src/Comment.php index ebacf3b..46c47fb 100644 --- a/src/Comment.php +++ b/src/Comment.php @@ -2,9 +2,11 @@ namespace BeyondCode\Comments; +use BeyondCode\Comments\Events\CommentAdded; +use BeyondCode\Comments\Events\CommentDeleted; +use BeyondCode\Comments\Traits\HasComments; use Exception; use Illuminate\Database\Eloquent\Model; -use BeyondCode\Comments\Traits\HasComments; class Comment extends Model { @@ -13,13 +15,32 @@ class Comment extends Model protected $fillable = [ 'comment', 'user_id', - 'is_approved' + 'is_approved', ]; protected $casts = [ - 'is_approved' => 'boolean' + 'is_approved' => 'boolean', ]; + public static function boot(): void + { + parent::boot(); + + static::deleting(function (self $model) { + if (config('comments.delete_replies_along_comments')) { + $model->comments()->delete(); + } + }); + + static::deleted(function (self $model) { + CommentDeleted::dispatch($model); + }); + + static::created(function (self $model) { + CommentAdded::dispatch($model); + }); + } + public function scopeApproved($query) { return $query->where('is_approved', true); @@ -43,7 +64,7 @@ class Comment extends Model return $this; } - + public function disapprove() { $this->update([ @@ -59,11 +80,10 @@ class Comment extends Model return config('comments.user_model'); } - if (!is_null(config('auth.providers.users.model'))) { + if (! is_null(config('auth.providers.users.model'))) { return config('auth.providers.users.model'); } throw new Exception('Could not determine the commentator model name.'); } - } diff --git a/src/CommentsServiceProvider.php b/src/CommentsServiceProvider.php index 2fd75e3..b91344d 100644 --- a/src/CommentsServiceProvider.php +++ b/src/CommentsServiceProvider.php @@ -16,7 +16,6 @@ class CommentsServiceProvider extends ServiceProvider __DIR__.'/../config/config.php' => config_path('comments.php'), ], 'config'); - if (! class_exists('CreateCommentsTable')) { $this->publishes([ __DIR__.'/../database/migrations/create_comments_table.php.stub' => database_path('migrations/'.date('Y_m_d_His', time()).'_create_comments_table.php'), diff --git a/src/Contracts/Commentator.php b/src/Contracts/Commentator.php index 40e963a..6007c89 100644 --- a/src/Contracts/Commentator.php +++ b/src/Contracts/Commentator.php @@ -2,14 +2,12 @@ namespace BeyondCode\Comments\Contracts; - interface Commentator { /** * Check if a comment for a specific model needs to be approved. - * @param mixed $model - * @return bool + * + * @param mixed $model */ public function needsCommentApproval($model): bool; - -} \ No newline at end of file +} diff --git a/src/Events/CommentAdded.php b/src/Events/CommentAdded.php new file mode 100644 index 0000000..a03c59a --- /dev/null +++ b/src/Events/CommentAdded.php @@ -0,0 +1,22 @@ +comments()->save($comment); } - -} \ No newline at end of file +} diff --git a/tests/CommentsTest.php b/tests/CommentsTest.php index e20a05c..5883e6d 100644 --- a/tests/CommentsTest.php +++ b/tests/CommentsTest.php @@ -2,9 +2,12 @@ namespace BeyondCode\Comments\Tests; +use BeyondCode\Comments\Events\CommentAdded; +use BeyondCode\Comments\Events\CommentDeleted; use BeyondCode\Comments\Tests\Models\ApprovedUser; use BeyondCode\Comments\Tests\Models\Post; use Illuminate\Foundation\Auth\User; +use Illuminate\Support\Facades\Event; class CommentsTest extends TestCase { @@ -12,7 +15,7 @@ class CommentsTest extends TestCase public function users_without_commentator_interface_do_not_get_approved() { $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $post->comment('this is a comment'); @@ -26,7 +29,7 @@ class CommentsTest extends TestCase public function models_can_store_comments() { $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $post->comment('this is a comment'); @@ -42,7 +45,7 @@ class CommentsTest extends TestCase public function comments_without_users_have_no_relation() { $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $comment = $post->comment('this is a comment'); @@ -59,7 +62,7 @@ class CommentsTest extends TestCase auth()->login($user); $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $comment = $post->comment('this is a comment'); @@ -73,7 +76,7 @@ class CommentsTest extends TestCase $user = User::first(); $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $comment = $post->commentAsUser($user, 'this is a comment'); @@ -87,7 +90,7 @@ class CommentsTest extends TestCase $user = User::first(); $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $comment = $post->comment('this is a comment'); @@ -105,7 +108,7 @@ class CommentsTest extends TestCase $user = User::first(); $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $comment = $post->comment('this is a comment'); @@ -120,7 +123,7 @@ class CommentsTest extends TestCase $user = ApprovedUser::first(); $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $comment = $post->commentAsUser($user, 'this is a comment'); @@ -134,7 +137,7 @@ class CommentsTest extends TestCase $user = ApprovedUser::first(); $post = Post::create([ - 'title' => 'Some post' + 'title' => 'Some post', ]); $post->comment('this comment is not approved'); @@ -145,4 +148,69 @@ class CommentsTest extends TestCase $this->assertSame('this comment is approved', $post->comments()->approved()->first()->comment); } + + /** @test */ + public function comments_are_deleted_when_posts_are_deleted() + { + $post = Post::create([ + 'title' => 'Some post', + ]); + + $comment = $post->comment('this comment will be deleted'); + + $post->delete(); + + $this->assertFalse($comment->exists()); + } + + /** @test */ + public function replies_are_deleted_when_post_comments_are_deleted() + { + config(['comments.delete_replies_along_comments' => true]); + + $post = Post::create([ + 'title' => 'Some post', + ]); + + $comment = $post->comment('this comment will be deleted'); + $reply = $comment->comment('this comment will be deleted too'); + + $comment->delete(); + + $this->assertFalse($reply->exists()); + } + + /** @test */ + public function comment_added_event_is_dispatched_when_comment_is_created() + { + Event::fake([CommentAdded::class]); + + $post = Post::create([ + 'title' => 'Some post', + ]); + + $comment = $post->comment('this comment is added'); + + Event::assertDispatched(CommentAdded::class, function ($event) use ($comment) { + return $event->comment->is($comment); + }); + } + + /** @test */ + public function comment_deleted_event_is_dispatched_when_comment_is_deleted() + { + Event::fake([CommentDeleted::class]); + + $post = Post::create([ + 'title' => 'Some post', + ]); + + $comment = $post->comment('this comment is added'); + + $comment->delete(); + + Event::assertDispatched(CommentDeleted::class, function ($event) use ($comment) { + return $event->comment->is($comment); + }); + } } diff --git a/tests/Models/ApprovedUser.php b/tests/Models/ApprovedUser.php index 53734e0..b057cbe 100644 --- a/tests/Models/ApprovedUser.php +++ b/tests/Models/ApprovedUser.php @@ -2,22 +2,20 @@ namespace BeyondCode\Comments\Tests\Models; -use Illuminate\Foundation\Auth\User; use BeyondCode\Comments\Contracts\Commentator; +use Illuminate\Foundation\Auth\User; class ApprovedUser extends User implements Commentator { - protected $table = 'users'; /** * Check if a comment for a specific model needs to be approved. - * @param mixed $model - * @return bool + * + * @param mixed $model */ public function needsCommentApproval($model): bool { return false; } - -} \ No newline at end of file +} diff --git a/tests/Models/Post.php b/tests/Models/Post.php index 8260dc6..3c318bc 100644 --- a/tests/Models/Post.php +++ b/tests/Models/Post.php @@ -10,4 +10,13 @@ class Post extends Model use HasComments; protected $guarded = []; -} \ No newline at end of file + + public static function boot(): void + { + parent::boot(); + + static::deleting(function (self $model) { + $model->comments()->delete(); + }); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 9b56a6c..3679880 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,13 +2,12 @@ namespace BeyondCode\Comments\Tests; -use Illuminate\Foundation\Auth\User; -use Illuminate\Database\Schema\Blueprint; use BeyondCode\Comments\CommentsServiceProvider; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Foundation\Auth\User; abstract class TestCase extends \Orchestra\Testbench\TestCase { - public function setUp(): void { parent::setUp(); @@ -38,7 +37,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase protected function setUpDatabase() { - include_once __DIR__ . '/../database/migrations/create_comments_table.php.stub'; + include_once __DIR__.'/../database/migrations/create_comments_table.php.stub'; (new \CreateCommentsTable())->up(); @@ -54,8 +53,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase User::forceCreate([ 'name' => 'User', 'email' => 'user@email.com', - 'password' => 'test' + 'password' => 'test', ]); } - -} \ No newline at end of file +}