›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-comments
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Commentable models
  • Threads and replies
  • Moderation
  • Initial status
  • Pinning
  • Reactions
  • Edits and revisions
  • Attachments
  • Deleting comments

Operations

  • Comment counts
  • Events and listeners
  • Reply notifications
  • Authorization
  • Rendering and safety

Reference

  • Configuration
  • Console commands
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Commentable models
  • Threads and replies
  • Moderation
  • Initial status
  • Pinning
  • Reactions
  • Edits and revisions
  • Attachments
  • Deleting comments

Operations

  • Comment counts
  • Events and listeners
  • Reply notifications
  • Authorization
  • Rendering and safety

Reference

  • Configuration
  • Console commands
  • Testing
  • Troubleshooting

byrcsc/laravel-comments · 1.x

Attachments.

Record attachment metadata while your application manages the stored files.

An attachment is a row of metadata about a file your application stored: a disk name, a path on it, and what the application said the file is called, is, and weighs.

The package never opens the file, never checks that it is there, and never deletes it. Serving it, authorizing the download, and cleaning it up stay on your side of the line.

Record a file

$path = $request->file('receipt')->store('receipts', 'uploads');

$attachment = $comment->attach(
    path: $path,
    disk: 'uploads',
    name: $request->file('receipt')->getClientOriginalName(),
    mimeType: $request->file('receipt')->getMimeType(),
    size: $request->file('receipt')->getSize(),
);

Only path is required:

ArgumentFalls back to
diskcomments.attachments.disk, then the application's default disk
nameThe path's basename
mimeTypeStays null
sizeStays null

Size and MIME type stay null when you did not measure them. A guess recorded as fact is worse than an honest absence.

The metadata is recorded as given and never verified against the disk. Attaching a path that holds nothing succeeds, because the package has no business reading the file to find out.

Read them

$comment->attachments;   // oldest first

foreach ($comment->attachments as $attachment) {
    $attachment->disk;
    $attachment->path;
    $attachment->name;
    $attachment->mime_type;
    $attachment->size;
}

Rendering them is ordinary Eloquent, and so is eager-loading a whole thread's with with('attachments').

Remove one

$comment->detach($attachment);  // returns whether there was one to remove

The file on disk is untouched, here as everywhere. Passing an attachment that belongs to a different comment throws an InvalidAttachmentException rather than removing it.

Delete the file

Deleting bytes belongs in a listener on AttachmentRemoved, where the row is still in hand and its disk and path are still readable:

use ByRcsc\LaravelComments\Events\AttachmentRemoved;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Storage;

Event::listen(AttachmentRemoved::class, function (AttachmentRemoved $event): void {
    Storage::disk($event->attachment->disk)->delete($event->attachment->path);
});

That listener covers both removal paths. detach() fires it once. A force delete fires it once per attachment across the complete reply subtree, including tombstones. The listener can therefore remove every stored file.

A soft delete fires nothing, because nothing was removed.

Attach an image

attachImage() processes an uploaded image, stores it, and records it in one call:

use Illuminate\Support\Facades\Image;

$comment->attachImage(Image::fromUpload($request->file('screenshot')));

Everything about the processing is the framework's, hand it whatever Image::fromUpload() and friends give you, configured however you like:

$comment->attachImage(
    Image::fromUpload($request->file('screenshot'))->resize(1600, 900),
    name: 'Screenshot.png',
    disk: 'uploads',
    directory: 'comments/screenshots',
);

The disk and directory fall back to comments.attachments.disk and comments.attachments.directory. The name falls back to the uploaded file's own name carrying the extension of what was actually stored, a screenshot.png optimized to WebP is recorded as screenshot.webp, because a row whose name disagrees with its own bytes is metadata that lies.

This is the one path where the package writes bytes to a disk, and it writes only the ones it was handed. Nothing is read back afterwards.

The optimize flag

$optimize defaults to true and applies the framework's own optimize step. It writes WebP at the framework's default quality.

Pass optimize: false when the pipeline you handed over already says what the output should be:

$comment->attachImage(
    Image::fromUpload($file)->toPng(),
    optimize: false,
);

Image keeps its pipeline private, so the package cannot ask whether you configured one and would otherwise overwrite your format. The flag is that question, asked of the caller.

Requirements

attachImage() needs the framework's Image facade, which arrived in Laravel 13, and intervention/image, which the package suggests rather than requires:

composer require intervention/image

Without it the call throws an ImageSupportMissingException naming the missing dependency, rather than a driver error three frames away. Nothing else in the package needs it, attach() works without an image library at all.

Validation

The package checks presence and types, and nothing further:

  • A blank path or a blank name throws an InvalidAttachmentException.
  • A negative size throws the same. Zero is accepted, an empty file is a real file.
  • Attaching to an unsaved comment throws a LogicException.

Whether the bytes are really on that disk is your application's to know: it is what put them there.

Deleted comments

A tombstone keeps the attachments it already had and takes no new ones, for the same reason its reactions are frozen: a moderator reading what happened needs the record to have stopped changing. Attaching to or detaching from a soft-deleted comment throws a CommentTrashedException. Restoring it makes both work again.

Force deleting removes the rows through the cascade, for the comment and its whole subtree, and fires AttachmentRemoved for each one first.

Reading is never gated.

Events

EventFires when
AttachmentAddedattach() or attachImage() records a row
AttachmentRemoveddetach() removes one, or a force delete takes one

Both extend CommentAttachmentChanged and carry the comment and the attachment model. On the force-delete sweep, the comment the event carries is the one that held the attachment, not necessarily the one the caller deleted.

Authorization

attach is an ability on the shipped CommentPolicy and allows any authenticated actor by default, 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. See authorization.

What to read next

  • Rendering and safety to control attachment URLs and stored file access.
  • Events and listeners to remove stored files after attachment rows are deleted.
  • Authorization to restrict who can add or remove evidence.
PreviousEdits and revisionsNextDeleting comments
View source

On this page

  1. Record a file
  2. Read them
  3. Remove one
  4. Delete the file
  5. Attach an image
  6. The optimize flag
  7. Requirements
  8. Validation
  9. Deleted comments
  10. Events
  11. Authorization
  12. What to read next