NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Comments for Laravel

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. 4

What 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 crypto

By 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.