Transferring comments
Comments::transfer($from, $to) moves every comment of one subject onto another and returns how many moved — for merging two records, such as duplicate tickets or two posts about the same thing. It re-points the commentable morph of all of $from’s comments in one transaction: top-level comments and replies, invisible, pending and hidden ones, and soft-deleted ones too, so a later restore lands on $to:
use RoundlyConsulting\Comments\Facades\Comments;
$moved = Comments::transfer($duplicate, $original); // int — e.g. 4What travels with the comments
- Replies keep their parent_id, and every parent moves with them, so threads stay whole.
- Mentions, likes, reports and attachments belong to the comment, not the subject, so they follow it.
- A thread lock (locked_at) is on the comment and travels with it.
- A subject lock stays where it is: a locked $from stays locked — moving its comments out is allowed — and $to does not become locked.
- Comments $from wrote as an author are not touched; only comments on it move.
- updated_at is left alone — a move is not an edit.
Refusals
When a check fails, nothing moves, nothing is recorded and no event fires:
- $from and $to are the same subject — the same morph type and key, even as two instances — so InvalidCommentTransferException is thrown.
- $to is subject-locked, so CommentsLockedException is thrown.
- With comments.authorization on, the policy’s existing create ability is checked on $to — create(?Model $user, ?Model $commentable) with $to as the commentable — and a denial throws UnauthorizedCommentActionException. A policy that doesn’t extend CommentPolicy needs no new method.
use RoundlyConsulting\Comments\Exceptions\CommentsLockedException;
use RoundlyConsulting\Comments\Exceptions\InvalidCommentTransferException;
try {
Comments::transfer($duplicate, $original);
} catch (InvalidCommentTransferException $e) {
// $duplicate and $original are the same subject
} catch (CommentsLockedException $e) {
// $original is locked
}After the move
CommentsTransferred fires with $from, $to and $count — also when nothing moved and $count is 0 — and Comments::fake() records the call for assertTransferred() (see Testing):
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\Comments\Events\CommentsTransferred;
Event::listen(function (CommentsTransferred $event): void {
$event->from; // the subject the comments left
$event->to; // the subject they now belong to
$event->count; // how many moved — 0 is possible
});Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.