2lenet/entity-file-bundle
EntityFileBundle lets Symfony entities attach and manage files through configurable FlySystem storage adapters, with simple save, retrieve, access, delete, rename, and move operations via a per-configuration manager.
role (including PUBLIC_ACCESS) and disposition (inline vs attachment) are product-visible dials: gated customer documents vs. public images, view-in-browser vs. forced download. These map directly to policy questions stakeholders will ask.EntityFileInterface plus the shipped trait), so metadata is queryable — "which entities have attachments," "who uploaded what" become SQL, not log archaeology.EntityFileBrick gives a dropzone UI (view, add, remove, download) for back-office panels — this can decide whether ops tooling ships this quarter or next.Adopt if:
File / UploadedFile / resource, retrieve, read or stream contents, move/rename, delete (entity + physical file together).Look elsewhere if:
config/filesystems.php, and Laravel's Storage facade are not what it talks to. Bridging is real work, not configuration.For executives: "This is a small, MIT-licensed Symfony component that attaches files to records in our database — a seller's logo, a product's images, a generated report. Instead of engineering building upload, storage, path, and download-serving logic, we configure one mapping per entity. It also gives us a ready-made upload panel for internal admin screens. Two things to be clear about: it's plumbing, not a media platform — thumbnails, scanning, and public-scale delivery are separate line items — and it's maintained by a single small vendor, so we'd wrap it thinly and stay able to replace it. Expected payoff is a few engineer-weeks avoided per attachment feature, with storage choice left open so we're not locked into local disk."
For engineering: "Doctrine-oriented Symfony bundle. You define a configuration per entity+filesystem in lle_entity_file.yaml (class, storage_adapter, optional entity_file_class, role, disposition), then get a manager: $entityFileLoader->get('seller_logos'). save($entity, $data, $path) accepts a string, File/UploadedFile, or stream resource and returns an EntityFile you must persist and flush yourself — that's the main footgun. move() likewise requires a flush. Read with read()/readStream(), remove with delete() (removes row and blob). Paths are caller-supplied, so dynamic layouts like Y-m/{id}.xml are trivial. Storage is FlySystem: define any adapter in flysystem.yaml and reference it; the default drops files under data/{configName}. Delivery is two routes — by id or by path — gated by the config role; register them manually if you're not on Flex. Extend metadata by implementing EntityFileInterface and using the provided trait.
Known gaps to plan around: no file validation, no image processing, no queueing, no signed URLs, no Laravel/Eloquent path, and the docs show no test suite or CI. Mitigation I'd recommend: put a one-method internal interface in front of the manager so a future swap to raw FlySystem is a contained change, pin the version, and add our own validation and authorization layer rather than relying on the bundle's role check alone. Budget a spike to confirm Symfony/Doctrine version fit and route-security behavior before we commit to a date."
How can I help you explore Laravel packages today?