Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Attachments Laravel Package

sehrgut/laravel-attachments

A Laravel package for attaching files to Eloquent models. It offers a simple, reusable way to manage uploads and storage and to associate one or many files with your records through clean, expressive APIs, making it easy to add file and media support to any model.

View on GitHub
Deep Wiki
Context7

Getting Started

Read the package status first. This package is archived and has effectively no community (2 stars, 0 dependents). Treat it as a reference implementation or a starting point to fork, not a dependency you install and forget. Before writing any code, open the repository and read src/, config/, and database/migrations/ — there is no meaningful third-party documentation or Stack Overflow coverage, so the source is the documentation.

  1. Install (or better, vendor it into your project so you control it):

    composer require sehrgutesoftware/laravel-attachments
    
  2. Publish assets and run migrations:

    php artisan vendor:publish --provider="SehrgutSoftware\Attachments\AttachmentsServiceProvider"
    php artisan migrate
    
  3. Add the package trait to any Eloquent model that should own files:

    use SehrgutSoftware\Attachments\Traits\HasAttachments;
    
    class Post extends Model
    {
        use HasAttachments;
    }
    
  4. First use case — attach an uploaded file on create. The canonical flow is: accept an UploadedFile in a controller, save the model, then hand the file to the model's attachment API:

    public function store(StorePostRequest $request)
    {
        $post = Post::create($request->validated());
        $post->attach($request->file('cover'));
    
        return redirect()->route('posts.show', $post);
    }
    
  5. Confirm the file landed where you expect. Check the published config/attachments.php for the default disk and base path, then verify on disk (storage/app/...) and via the model relation ($post->attachments). Getting storage wiring right on the first attempt is the main onboarding hurdle.

Implementation Patterns

Attach after persist, not before. Attachments are tied to a model via a polymorphic relation, so the parent must have a primary key. In practice: create/update the model inside a transaction, then attach files. If you need atomicity across DB + disk, wrap in DB::transaction() and clean up files in a catch.

Request-to-model mapping pattern. For multi-file uploads, loop explicitly rather than guessing package behavior:

foreach ($request->file('attachments', []) as $file) {
    $post->attach($file);
}

Replacement workflow. "Replace the cover image" is more common than "add another." Implement it as detach-then-attach, and delete the old file from disk in the same step so you don't accumulate orphans:

$old = $post->attachments()->where('collection', 'cover')->first();
$post->attach($request->file('cover'), ['collection' => 'cover']);
$old?->delete(); // or ->deleteFile() depending on the package's API

If the package doesn't support collections out of the box, add a collection column in your own migration and scope the relation accordingly — that's the pragmatic extension point.

Polymorphic reuse. The trait is designed to be dropped on multiple models. Keep a single Attachment model and one storage convention (attachments/{model}/{id}/{uuid} or similar) so cleanup jobs and backup tooling work uniformly.

Serving files. Never expose the storage path directly. Serve through a controller action that authorizes the request, then return a streamed download:

public function download(Post $post, Attachment $attachment)
{
    $this->authorize('view', $post);
    abort_unless($attachment->attachable->is($post), 404);

    return Storage::disk($attachment->disk)->download($attachment->path);
}

Testing pattern. Use Storage::fake('attachments') (or whatever disk you configure) in feature tests, then assert attachment rows exist and files were written. Because the package is archived and untested against newer Laravel versions, your test suite is your regression safety net — write tests for attach, delete, and download before upgrading Laravel.

Integration tip. If you're building something long-lived, wrap the trait behind your own FileService / Attachments interface so swapping to spatie/laravel-medialibrary or a homegrown model later is a one-file change, not a grep-and-replace across the app.

Gotchas and Tips

  • Archived means frozen. No security patches, no Laravel 11/12 compatibility fixes, no PHP 8.4 support guarantees. Pin it or fork it, and review the source for anything touching Storage, File, or UploadedFile before relying on it.
  • Verify the trait and API names against the source. Low-traffic packages drift; methods may be attach, addAttachment, or files. Don't assume — grep -r "public function" src/ before you write controllers.
  • Migration publishing is mandatory. Many minimal packages ship migrations that aren't auto-loaded. If attachments table doesn't exist after composer require, you skipped vendor:publish.
  • Disk/config mismatch. The most common runtime failure is the configured disk not existing in config/filesystems.php, or storage:link not being run when the package returns public URLs. Check both.
  • Orphaned files. Eloquent's deleting event handlers for files are unreliable across package versions. Add an explicit deleting observer on each owner model that deletes attached files, plus a scheduled attachments:prune command you write yourself for files with no DB row.
  • Security defaults are yours, not the package's. Minimal packages rarely validate MIME types or sizes. Always validate in a FormRequest (mimes, max, dimensions for images) and always authorize downloads — never trust a raw attachment URL.
  • No over-engineering cuts both ways. The package likely does one thing well (store file + row). It probably does not handle image conversions, thumbnails, chunked uploads, or S3 presigned URLs. Plan to add those yourself or pick a heavier package.
  • Debugging checklist when an upload silently fails: (1) is the model trait applied? (2) does the disk key exist? (3) are directory permissions correct? (4) does UploadedFile::isValid() return true (check php.ini upload limits)? (5) did the DB insert actually commit before the file write?
  • Extension points worth using: publish and override the Attachment model (custom casts, accessors for URLs), and add your own collection or metadata JSON column rather than forking the package's schema.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin