Looking to hire Laravel developers? Try LaraJobs

laravel-messaging-attachments maintained by phunky

Description
Message attachments extension for phunky/laravel-messaging
Author
Last update
2026/04/16 17:47 (dev-master)
License
Downloads
0

Comments
comments powered by Disqus

Laravel Messaging Attachments

Attach files and media to messages in phunky/laravel-messaging conversations. This extension stores attachment metadata (path, disk, MIME type, size, and arbitrary JSON) alongside each message, while leaving actual file storage entirely to your application.

Requirements

  • PHP ^8.4
  • [phunky/laravel-messaging](https://packagist.org/packages/phunky/laravel-messaging) ^0.0.1

Installation

composer require phunky/laravel-messaging-attachments

Register the extension in config/messaging.php:

'extensions' => [
    \Phunky\LaravelMessagingAttachments\AttachmentExtension::class,
],

Run migrations:

php artisan migrate

Usage

Inject AttachmentService — or resolve it from the container — wherever you handle uploads.

use Phunky\LaravelMessagingAttachments\AttachmentService;

class MessageController extends Controller
{
    public function __construct(private AttachmentService $attachments) {}

    public function store(Request $request, Message $message)
    {
        $path = $request->file('file')->store('attachments', 'public');

        $attachment = $this->attachments->attach($message, $request->user(), [
            'type'      => 'image',
            'path'      => $path,
            'filename'  => $request->file('file')->getClientOriginalName(),
            'disk'      => 'public',
            'mime_type' => $request->file('file')->getMimeType(),
            'size'      => $request->file('file')->getSize(),
        ]);
    }
}

Attaching files

// Single attachment — returns Attachment model
$attachment = $attachmentService->attach($message, $sender, [
    'type'      => 'image',          // required — e.g. 'image', 'video', 'document', 'audio'
    'path'      => 'uploads/a.jpg',  // required — path on the disk
    'filename'  => 'photo.jpg',      // required — original file name
    'disk'      => 'public',         // optional — Laravel filesystem disk
    'url'       => 'https://...',    // optional — direct or CDN URL
    'mime_type' => 'image/jpeg',     // optional
    'size'      => 204800,           // optional — size in bytes
    'order'     => 0,                // optional — position; auto-increments when omitted
    'meta'      => ['width' => 800], // optional — arbitrary JSON data
]);

// Multiple attachments in one transaction — returns Collection<Attachment>
$attachments = $attachmentService->attachMany($message, $sender, [
    ['type' => 'image', 'path' => 'a.jpg', 'filename' => 'a.jpg'],
    ['type' => 'image', 'path' => 'b.jpg', 'filename' => 'b.jpg'],
]);

Only the original message sender can attach or detach files. Attempts by anyone else throw Phunky\LaravelMessaging\Exceptions\CannotMessageException.

Removing an attachment

// Deletes the record and dispatches AttachmentDetached
$attachmentService->detach($message, $sender, $attachment);

Fetching attachments

// All attachments for a message, ordered by position then id
$attachments = $attachmentService->getAttachments($message);

// All attachments across a whole conversation,
// ordered by message sent_at (newest first), then attachment order and id
$attachments = $attachmentService->getAttachmentsForConversation($conversation);

Relationship macro

Message::attachments() is registered as a hasMany macro — call it as a method, not a property:

$message->refresh();
$message->attachments()->get();   // returns all Attachment models
$message->attachments()->count();

Events

Both events use Dispatchable and SerializesModels and are safe to queue.

Event Properties
AttachmentAttached Attachment $attachment, Message $message, Messageable $messageable
AttachmentDetached Message $message, Messageable $messageable, `int
use Phunky\LaravelMessagingAttachments\Events\AttachmentAttached;

Event::listen(AttachmentAttached::class, function (AttachmentAttached $event) {
    // Generate a thumbnail, push a notification, etc.
    GenerateThumbnail::dispatch($event->attachment->path, $event->attachment->disk);
});

AttachmentDetached carries the $attachmentId rather than a model because the record has already been deleted by the time the event fires.

Storage

This extension is storage-agnostic — it records where a file lives, not the file itself. Upload the file through Laravel's filesystem first, then pass the resulting path and disk to attach(). This works with any driver: local, public, s3, or any custom disk.

// Local disk
$path = $request->file('avatar')->store('avatars', 'local');

// S3
$path = $request->file('document')->store('documents', 's3');

// Then record the attachment
$attachmentService->attach($message, $user, [
    'type'     => 'document',
    'path'     => $path,
    'filename' => $request->file('document')->getClientOriginalName(),
    'disk'     => 's3',
]);

Deleting the underlying file from storage when an attachment is detached is your application's responsibility — listen to AttachmentDetached and remove the file using Storage::disk($disk)->delete($path).

License

MIT - see LICENSE.md.