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.
Architecture fit. The core design is sound and idiomatic for Eloquent: a single attachments polymorphic table (attachable_id / attachable_type) plus a trait gives any model one-or-many files without per-model schema changes. That is the same shape used by modern packages (Spatie Media Library, Laravel's own morphMany patterns), so the data model will not fight the framework. The fluent surface ($post->attachment()->create([...]), $post->attachments) is a thin wrapper over relationship methods, which means the abstraction leaks very little — a plus for a TPM evaluating lock-in.
Integration feasibility. Installation is conceptually one command plus a published migration and config file. In practice, feasibility is gated by release age: last release 2015-03-31, 46 stars, repository archived. That places it in the Laravel 4.2/5.0–5.2 era. Expect:
illuminate/* and PHP versions, blocking install on Laravel 8+ (and certainly 10/11) without a fork.$defer, manual alias registration, non-discovery registration).Illuminate\Filesystem\Filesystem and raw paths rather than the Storage facade and disk abstraction, which matters for S3/cloud disks.Technical risk. High, and concentrated in three places:
Mitigating factors: MIT license, small codebase, and a simple pattern — so forking or reimplementing is cheap. The real risk is organizational (who owns the fork) rather than technical.
Key questions.
Stack fit. Only a clean fit for a legacy Laravel 4.2/5.x application already carrying this dependency or an equivalent. On Laravel 8+, treat the package as a design reference, not a dependency. For greenfield or modern stacks, the correct move is the pattern, not the package: a polymorphic attachments table, a HasAttachments trait, and a small service class wrapping Storage::disk(...)->putFileAs() with validation.
Migration path. Two tracks, chosen by the stack audit:
| Track | Condition | Action |
|---|---|---|
| A — Vendor/fork | Legacy app that must keep the package | Fork under internal namespace, relax Composer constraints, replace raw filesystem calls with Storage, port thumbnails to Intervention v3 or drop them, add return types and PHP 8 syntax, add tests |
| B — Reimplement | Laravel 9+ or any app with upgrade headroom | Rebuild the same schema + trait in ~1–2 days; adopt Spatie Media Library if conversions, responsive images, and multi-disk support are needed |
| C — Replace | Modern app with rich media needs | Spatie laravel-medialibrary; accept the larger dependency for conversions, queues, and maintained security posture |
Compatibility. Before any code work, resolve: Composer constraint conflicts against the current lockfile; service provider registration style (auto-discovery vs config/app.php); Storage vs Filesystem semantics for disk roots and visibility; Intervention Image major version; and migration column types/morphs() index behavior, including whether the published migration uses morphs() (indexed) or raw string + integer (unindexed). Also verify whether the trait defines attachment() as hasMany — the singular naming can cause confusion and ->first() misuse.
Sequencing.
Storage facade, config-driven disks/directories/naming, return types, PHP 8 syntax.Maintenance. The dominant cost is ownership, not code. Abandoned-package scanners (Dependabot, Snyk, composer audit) will flag it indefinitely; expect recurring exceptions or a private fork to suppress the noise. Budget a named owner, quarterly review, and a documented fork point. Volume of code is small, so the ongoing maintenance is low-hours but non-zero, and it competes with roadmap work. Also note the archived repo means no upstream bug reports — every issue is yours.
Support. No vendor support, no active community (46 stars), documentation limited to a README. Onboarding relies on reading source. Internal runbook should cover: where files live on each disk, how names are generated, how to backfill/repair orphans, and how to rotate storage credentials.
Scaling. The polymorphic table scales acceptably if indexed on (attachable_type, attachable_id). Watch:
attachments.Failure modes.
public vs private), surfacing as 403s or unintended exposure.attachable_type lookups; enforce Relation::morphMap().Ramp-up. Developer learning curve is near zero — the API is three methods and one trait. The hidden ramp-up is for the team: understanding the fork's divergence, the storage layout, and the remediation procedures. Plan a short internal doc and one walkthrough; the risk is not "how do I attach a file" but "who fixes this in eighteen months."
Recommendation. Treat as moderate opportunity, high lifecycle risk. Use only in a legacy context via a small internal fork with hardening and tests; otherwise extract the pattern and reimplement on Storage, or adopt a maintained media library if conversions and multi-disk support are real requirements. The 2015 archive date is the deciding factor, not the code quality.
How can I help you explore Laravel packages today?