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

Attacher Laravel Package

artesaos/attacher

Attacher is a Laravel package for attaching files to Eloquent models. It provides polymorphic attachments, simple upload handling, storage management, and a clean API for managing model-related files and images.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm compatibility before anything else. This package's last release was 2015 and the repo is archived. It targets Laravel 5.x and PHP 5.x-era APIs. Before adding it to a modern app, read the composer.json constraints on the tagged release:

composer require artesaos/attacher

If Composer refuses due to laravel/framework or php constraints, that is your signal to either pin an older app or budget for a fork. Do not force-install with --ignore-platform-reqs in production.

2. Publish and run the migration. The package ships a publishable polymorphic attachments migration and config:

php artisan vendor:publish --provider="Artesaos\Attacher\AttacherServiceProvider"
php artisan migrate

Check config/attacher.php immediately — that is where the storage disk, target directory, and filename strategy live. Look at both the config file and the published migration first; they define the entire surface area you'll work against.

3. Add the trait to any model that can own files.

use Artesaos\Attacher\Traits\AttacherTrait;

class Post extends Model
{
    use AttacherTrait;
}

4. First use case — attach an upload from a controller. This is the 90% path:

public function store(Request $request, Post $post)
{
    $request->validate([
        'file' => 'required|file|max:10240',
    ]);

    $post->attachment()->create([
        'file' => $request->file('file'),
        'alt'  => $request->input('alt'),
    ]);

    return back();
}

Then read it back through the relationship:

@foreach ($post->attachments as $attachment)
    <img src="{{ $attachment->url }}" alt="{{ $attachment->alt }}">
@endforeach

Get one file working end-to-end (upload → row in attachments → file on the disk → URL renders) before touching thumbnails or multi-file flows.

Implementation Patterns

One file vs. many. The API separates the "attach a file" write path ($model->attachment()->create([...])) from the "read all files" relationship ($model->attachments). Use attachment()->create() in controllers/services and attachments in views. Treat attachments as read-only — it's a morphMany, so it's your display/iteration collection.

Keep controllers thin but don't hide the upload. The temptation is to wrap attachment()->create() in a service attach($file, $post). That's fine, but the win here is that storage logic is already out of your model and controller. Pass the UploadedFile object straight through — the package handles naming and disk placement via config:

$post->attachment()->create(['file' => $request->file('file')]);
$post->attachment()->create(['file' => $request->file('banner')]);

Eager load aggressively. attachments is a polymorphic relation; a loop over 50 posts without eager loading is 51 queries:

$posts = Post::with('attachments')->paginate(20);

Drive storage from config, not code. Set the disk and directory once in config/attacher.php and let every model inherit it. If you need per-context separation (e.g., avatars vs. documents), check whether the trait's create call accepts overrides — if not, keep separate disks/directories via config and avoid hardcoding paths in controllers:

// config/attacher.php (illustrative keys — verify against the published file)
'disk'        => env('ATTACHER_DISK', 'public'),
'directory'   => 'attachments',
'name'        => 'unique', // or a strategy that yields unique filenames

Ensure the disk exists in config/filesystems.php and that public is linked:

php artisan storage:link

Thumbnails and resizing. The package supports optional image resizing/thumbnails. Use it for user-uploaded images where you control dimensions; skip it for PDFs/archives by validating the upload type first. If thumbnails are enabled, confirm GD or Imagick is installed in the runtime image — this is the most common silent failure.

Clean up files on model deletion. The polymorphic table gives you cascade for the rows (if you set it up), but the files on disk will orphan. Hook the model's delete event:

static::deleting(function (Post $post) {
    foreach ($post->attachments as $attachment) {
        Storage::disk(config('attacher.disk'))->delete($attachment->path); // verify column name
        $attachment->delete();
    }
});

Or use an observer. Either way, treat file cleanup as your responsibility — don't assume the package does it.

Form UX pattern. Combine a hidden existing_attachment_id field with a new file input so users can keep or replace an upload. On save, only call attachment()->create() when a new file is present; otherwise leave the existing row untouched.

Gotchas and Tips

Archived means frozen. No security patches, no framework compatibility fixes. Audit the trait and config before adopting. If you're on Laravel 9+, plan to fork and update the service provider and any Arr/Str helper usage. Check whether the attachments model uses $fillable or $guarded and adjust mass-assignment accordingly.

Polymorphic type column. The attachments table stores attachable_type + attachable_id. If you rename models or use a morph map (Relation::morphMap([...])), historical rows keep the old type string. Introduce a morph map before the first attachment is written, or write a migration to update existing attachable_type values.

Filename collisions. With concurrent uploads, a naive naming strategy can overwrite files. Prefer unique/hashed names in config, and verify the strategy by uploading two files with the same original name in a test. Silent overwrites are hard to spot until a user reports a "missing" file.

Disk mismatch between write and read. A file saved to local (storage/app) but referenced via a public URL will 404. Keep config/attacher.php disk, config/filesystems.php visibility, and storage:link consistent. Debug by checking the actual path on disk first, then the generated URL.

Config caching bites in production. After editing config/attacher.php, run php artisan config:clear / config:cache. A stale cached config is a frequent cause of "it works locally but not in prod."

Validate uploads before they hit the package. The package moves and stores; it doesn't do MIME/extension validation for you. Keep file|mimes:jpg,png,pdf|max:... in Form Requests. Never trust the client filename for anything beyond display.

Watch storage permissions. The web user must be able to write to the target directory. Permission errors surface as exceptions during create(), not at upload time — check storage/logs/laravel.log and the directory owner.

Extension points to know: the published config (disk/directory/naming/thumbnail settings), the trait (override or extend methods if you need custom behavior), and the attachments model (swap or extend if the published one lacks fields you need — but remember you're editing a forked, archived baseline).

When to reconsider the dependency. For a greenfield app, Laravel's own Storage facade plus a hand-rolled morphMany attachment model is ~50 lines and fully supported. Adopt this package only if you're maintaining a legacy 5.x codebase where it's already in use, or if you're forking it deliberately. The score reflects convenience, not long-term support.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource