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

Filesystem Laravel Package

zenstruck/filesystem

Zenstruck Filesystem is a Symfony bundle for attaching files and images to Doctrine entities. It handles storage via Flysystem adapters, image transformations, metadata, and automatic orphan cleanup, keeping file management clean and testable.

Deep Wiki
Context7

Technical Evaluation

Architecture fit. Zenstruck Filesystem implements a clean value-object pattern: File and Image wrap upload metadata and storage references, while Doctrine lifecycle listeners handle persist/update/remove semantics. For a Symfony + Doctrine codebase this is a strong fit — it removes file-handling boilerplate from entities and keeps domain models testable. For a Laravel codebase the fit is poor: the package is a Symfony bundle, registered through the Symfony kernel and DI container, and its persistence model assumes Doctrine ORM mappings and Doctrine event subscribers. Laravel's default ORM is Eloquent, which has no lifecycle integration with this bundle. The underlying abstractions (Flysystem-backed storage, orphan cleanup) are portable as patterns, not as a package.

Integration feasibility.

  • Direct use in Laravel: low. Would require Doctrine ORM as a parallel persistence layer, Symfony bundle bootstrapping (or significant manual wiring), and LiipImagineBundle for image filters — none of which are idiomatic or low-effort in a Laravel app.
  • Direct use in a Symfony service inside a mixed portfolio: high. If the organization runs Symfony services alongside Laravel, adoption is straightforward.
  • Pattern reuse in Laravel: moderate. Laravel's Storage facade is already Flysystem-backed, so the storage abstraction maps cleanly; the value-object and orphan-cleanup semantics would need a small in-house reimplementation using Eloquent casts, observers, and a scheduled cleanup command.

Technical risk.

  • Small ecosystem. 43 stars and a recent but single-track release history imply a bus factor of roughly one. MIT licensing removes legal lock-in but not maintenance risk.
  • Version coupling. Symfony major bumps, Doctrine ORM 2→3 transitions, and Flysystem 3 migration each represent a potential breaking window. The package must be pinned and tracked.
  • Orphan removal reliability. Cleanup depends on Doctrine lifecycle events firing; bulk DQL deletes, raw SQL, or queue workers bypassing the ORM will silently leak files.
  • LiipImagine coupling. Image filtering is delegated to a third bundle, so image pipeline risk is transitive.
  • Opportunity score (7.28) suggests real demand for this problem space, but the Laravel segment is not served by this artifact.

Key questions.

  1. Is any part of the target stack actually Symfony/Doctrine, or is this being evaluated for a pure Laravel estate?
  2. If Laravel-only, is the goal adoption or pattern inspiration (value objects + scheduled orphan reaper)?
  3. What is the acceptable bus-factor for a production dependency — is a single-maintainer package acceptable for file persistence, which is business-critical?
  4. Which storage backends are required (local, S3, GCS) and does the Flysystem adapter list cover them?
  5. What is the deletion/retention policy, and who owns reconciliation when orphan cleanup fails?

Integration Approach

Stack fit. Treat this as a Symfony-only component. In a Laravel-first estate, do not attempt direct integration; the cost of standing up Doctrine + bundle bootstrapping exceeds the benefit. Instead, adopt the design: a StoredFile value object, an Eloquent cast for persistence, a Storage disk per file class, and a scheduled files:prune-orphans command. Laravel's native Flysystem integration makes the storage half nearly free.

Migration path.

  1. Spike (1 sprint): Stand up the bundle in a throwaway Symfony app; validate the File/Image lifecycle, orphan removal, and LiipImagine filter path against a real S3 bucket.
  2. Decide (gate): If the target is Symfony, adopt directly and pin. If Laravel, freeze the spike as a reference implementation and port the value-object + cleanup contract.
  3. Port (Laravel path): Implement File/Image value objects, an Eloquent cast, a FileStorage service over Storage::disk(), and a queued orphan-prune job. Target parity on: persist, replace, delete, and orphan sweep.
  4. Backfill: For existing uploads, run a one-time migration that moves legacy paths into the value-object schema and writes metadata rows.
  5. Cutover: Feature-flag new uploads onto the new path; keep legacy read path until backfill verification completes.

Compatibility. Verify PHP version floor, Symfony 6.x/7.x support, Doctrine ORM 2.x/3.x, and Flysystem 3.x before committing. For the Laravel port, confirm the Storage disk config matches required backends (S3, GCS, local) and that image filtering is covered by Intervention Image or Glide rather than LiipImagine.

Sequencing. Storage abstraction first (lowest risk, highest reuse), then persistence, then deletion/orphan cleanup (highest risk — put it behind audit logging and a dry-run mode), then image filtering last.

Operational Impact

Maintenance. Single-maintainer, 43-star package used for a business-critical concern (file persistence). Plan for the possibility of forking. Budget a quarterly dependency review to track Symfony/Doctrine/Flysystem compatibility. The MIT license is permissive but does not transfer maintenance obligation — treat the fork as a contingency, not a plan.

Support. No commercial support; GitHub issues only. Internal ownership must be assigned explicitly: one engineer accountable for the file subsystem, with the runbook documented regardless of whether the Symfony bundle or a Laravel port is used.

Scaling. The storage layer scales with the underlying Flysystem adapter (S3/GCS are effectively unbounded). The real scaling pressure is metadata volume in the DB (one row per file, plus join columns on entities) and image filter cache growth, which needs a TTL and a purge job. Orphan sweeps should be incremental and indexed on created_at to avoid full-table scans.

Failure modes.

  • Orphan leak: bulk deletes or raw SQL bypass ORM events → unreferenced objects accumulate. Mitigate with a scheduled reconciliation job comparing storage listing vs. DB rows.
  • Delete-before-commit: file removed from storage but DB transaction rolls back → broken references. Ensure deletion is post-commit or queued.
  • Duplicate uploads: replace flows that write new objects without deleting old ones.
  • Image filter miss: LiipImagine cache cold-start latency on first request per variant; pre-warm for high-traffic assets.
  • Remote storage eventual consistency: reads immediately after write may 404 on some backends; add retry/backoff.

Ramp-up. For Symfony developers: low — a day to first productive use. For Laravel developers forced through the Doctrine compatibility path: high — Doctrine entity mapping, event lifecycle, and bundle config are all unfamiliar territory, and debugging is materially harder. This asymmetry is the strongest argument for the port-and-reuse strategy in a Laravel estate, and the strongest argument for direct adoption in a Symfony estate.

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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox