byrcsc/laravel-comments · 1.x
Initial status.
Which status a new comment starts in — the configured defaults, why guests are separate, and the DecidesCommentStatus hook that beats both.
Every comment lands in some status the moment it is written. Which one is resolved in a fixed, short order:
- A status the caller set explicitly.
- The commentable's
initialCommentStatus()hook, when it implementsDecidesCommentStatus. comments.default_statusfor a model-authored comment, orcomments.guest_statusfor a guest one.
The configured defaults
'default_status' => 'approved',
'guest_status' => 'pending',Guests are read from their own key on purpose. Raising default_status never
drags anonymous content along with it — approving content nobody can be held to
is a decision the package will not make for you. Set guest_status yourself
when you mean it.
Both accept pending, approved, rejected, or spam. Anything else throws
an InvalidConfigurationException when the package boots.
Hold everything for review by lowering the default:
'default_status' => 'pending',The commentable hook
For a rule the config cannot express — hold the first comment from anyone new, auto-approve on a closed internal board, hold everything on a locked thread — implement the contract on the commentable:
use ByRcsc\LaravelComments\Contracts\DecidesCommentStatus;
use ByRcsc\LaravelComments\Enums\CommentStatus;
use ByRcsc\LaravelComments\Models\Comment;
class Post extends Model implements DecidesCommentStatus
{
use HasComments;
public function initialCommentStatus(Comment $comment): ?CommentStatus
{
if ($this->comments_locked) {
return CommentStatus::Pending;
}
return null;
}
}The comment handed to the hook is unsaved and fully populated: its commentator, guest identity, parent, and body are all readable, and nothing it says has been trusted yet.
Returning null hands the decision back to the configured defaults, so a hook
only has to answer the cases it cares about. The hook is asked about replies as
well as thread starters.
Two things the hook is deliberately not:
It is not an authorization check. Returning pending holds a comment; it
does not refuse one. Refusing a write belongs in the
policy or your controller.
It is not consulted when a status was named. A factory, a seeder, or an import restoring an export already knows what it meant:
$post->comments()->create(['body' => 'Imported', 'status' => CommentStatus::Approved]);Resolution is only for the writes that said nothing.
Cost
The commentable is loaded for the hook only when its class implements the
contract, so a model that does not pays nothing. On the ordinary write path the
commentable is already in hand — $post->comment(...) hands the model over
rather than re-reading the row — so implementing the hook costs no extra query
either. Writing through the Comment model directly, without the commentable
loaded, costs one read.
Factories resolve the same way
Comment::factory() sets no status, so factory-built comments resolve theirs
exactly as written ones do — a guest lands pending, which is what a test of a
moderation queue should be seeing. Name one with status() or its shortcuts
when the test is about a particular status:
Comment::factory()->forCommentable($post)->pending()->create();See testing.