›
byrcsc/laravel-comments · 1.x
Authorize comment actions through the included policy or application checks.
The package registers no policy, defines no gate, and never checks whether the current user may perform the requested action.
That is deliberate. approve(), react(), pin(), and the rest work in a
queued job, a seeder, and a console command, where there is no authenticated
actor to ask about. Enforcement belongs where your application calls the engine.
CommentPolicy is the boilerplate every installing application would otherwise
write. It is never registered for you:
use ByRcsc\LaravelComments\Models\Comment;
use ByRcsc\LaravelComments\Policies\CommentPolicy;
use Illuminate\Support\Facades\Gate;
// A service provider
Gate::policy(Comment::class, CommentPolicy::class);Then gate the call site:
// A controller
$this->authorize('approve', $comment);
$comment->approve(by: $request->user());| Ability | Default |
|---|---|
create | Any authenticated actor |
update | The comment's author |
delete | The comment's author |
react | Any authenticated actor |
attach | Any authenticated actor |
restore | Nobody |
forceDelete | Nobody |
approve | Nobody |
reject | Nobody |
markAsSpam | Nobody |
pin | Nobody |
unpin | Nobody |
In short: authors may edit and delete what they wrote, anyone signed in may react and attach, and nobody moderates until you say who does.
A few of those defaults are choices worth naming:
attach allows any authenticated actor, including on somebody else's
comment. A moderator adding evidence to a reported comment is as ordinary as an
author adding a screenshot to their own. Narrow it to authors by overriding.
restore denies everybody. Restoring is a moderator's undo, not an
author's, a comment removed for a reason should not come back because the
person who wrote it wants it to.
forceDelete denies everybody. It destroys a comment, its replies, its
reactions, its revisions, and its attachment rows.
update and delete both ask the comment whether the actor wrote it:
$comment->isBy($actor);Both halves of the morph have to match, so a User and an Admin sharing a
primary key are not the same author. A guest-authored comment matches nobody,
which means ownership always denies for one: a later visitor claiming to be Jane
has nothing to prove it with.
Extend the class and register yours instead. Everything you do not override keeps its default:
use ByRcsc\LaravelComments\Models\Comment;
use ByRcsc\LaravelComments\Policies\CommentPolicy;
use Illuminate\Database\Eloquent\Model;
final class AppCommentPolicy extends CommentPolicy
{
public function approve(?Model $actor, Comment $comment): bool
{
return $actor?->getAttribute('is_moderator') === true;
}
public function reject(?Model $actor, Comment $comment): bool
{
return $this->approve($actor, $comment);
}
public function markAsSpam(?Model $actor, Comment $comment): bool
{
return $this->approve($actor, $comment);
}
}Gate::policy(Comment::class, AppCommentPolicy::class);The actor is nullable throughout, so an unauthenticated visitor reaches these
methods rather than being refused before them. That is what lets create be the
one place deciding whether guests may write at all:
public function create(?Model $actor): bool
{
return true; // guests may comment
}An application that does that owns its own rate limiting, which is the check that actually matters for anonymous writes and one this package deliberately does not ship.
There is no view or viewAny here. Visibility is a query, not an ability: the
approved() scope is what decides what a visitor reads. See
moderation.
The policy knows nothing about permission packages, roles, teams, or tenants, and it never will. Those are your application's, and the way to bring them in is the subclass above.