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

Upload Bundle Laravel Package

ruwork/upload-bundle

Ruwork Upload Bundle is a Symfony bundle that provides reusable file-upload handling for PHP applications. It helps reduce boilerplate around receiving, storing, and managing uploaded files, making upload logic easier to organize and integrate into your project.

View on GitHub
Deep Wiki
Context7

Getting Started

Treat this package as a reference implementation rather than a dependency you can lean on. The repository is archived, the last release is from July 2018, and it targets the Symfony 3.x/4.0 era — that means PHP 7.1-ish assumptions, symfony/form and symfony/http-foundation APIs from before the 4.4/5.x refactors, and Doctrine ORM pre-2.7 conventions. If you are starting a new project on Symfony 5+, 6+ or 7+, nothing here will install cleanly without conflict resolution hacks.

First steps if you genuinely need to use it (or mine it):

  1. Read README.md first — that is the only real documentation. Then read composer.json to see the exact Symfony and Doctrine version constraints; that tells you what era you are dealing with faster than the code does.
  2. Look at src/ for the bundle class, the DI extension (DependencyInjection/RuworkUploadExtension.php), and service definitions in Resources/config/services.xml (or .yaml). The service wiring is where these small bundles reveal their actual contract.
  3. Find the entity-mapping or upload-listener classes — that is the core of any "upload bundle": mapping an uploaded file to a persisted record, moving the file from the temp directory to a configured storage directory, and cleaning up on delete/update.
  4. Try the smallest possible use case in a throwaway Symfony 4 sandbox: one Doctrine entity with an uploadable field, one form with FileType, one upload. If that boots, the rest is polish. If it does not, stop — you have already learned more than the README will tell you.

Because dependents are zero and stars are zero, there is no community signal proving it works in the wild. Budget a half-day to validate it against your target Symfony version before committing any design to it.

Implementation Patterns

The pattern for a bundle like this is almost always the same, and you can adopt it even if the package itself is too stale to install:

  • Upload-as-entity pattern. A Doctrine entity (call it File or Upload) holds the filename, original name, MIME type, size, and a path. The bundle hooks into Doctrine's prePersist/preUpdate/postLoad lifecycle — either via an @EntityListeners annotation or a container-registered event subscriber — to move files from a temp upload path to a permanent storage path and to inject an absolute path back onto a non-persisted property.
  • Form binding. The entity exposes a non-mapped UploadedFile $file property populated by FileType. The lifecycle listener does the actual file move. Your controller is then just $form->handleRequest($request); $em->persist($entity); $em->flush();.
  • Storage abstraction. Even in these old bundles, storage is usually a configured directory plus a public path prefix (ruwork_upload.dir, ruwork_upload.path_prefix or similar). Wire it to your %kernel.project_dir%/public/uploads and a matching Twig helper or entity getWebPath() method.
  • Replacing files. The preUpdate listener is expected to delete the previous file before writing the new one. Verify this actually happens — it is the single most common bug in this category of bundle, and with an unmaintained repo you may be the first person to notice.

Integration tips if you adapt the code into your own project (recommended over installing the archived package):

  • Copy the listener/entity pair into your App\Upload namespace, keep the Doctrine lifecycle hooks, and drop the bundle plumbing entirely. A bundle is overhead for something this small.
  • Keep the upload directory outside the docroot and stream files through a controller if uploads may contain user-sensitive content; the 2018-era default of writing straight into web/uploads is a liability.
  • If you must run the original bundle, pin it to a Symfony 4.0–4.3 app, freeze that app's dependencies, and do not plan to upgrade it.

Gotchas and Tips

  • It is archived. No security fixes, no Symfony 5+ support, no PHP 8 compatibility. Any production use means you own maintenance of a dead codebase — usually a bad trade for ~200 lines of upload logic you could write yourself.
  • Composer will fight you. Transitive constraints on old Symfony components will deadlock with a modern symfony/framework-bundle. Use composer why-not ruwork/upload-bundle if you need the argument written down for a code review.
  • Lifecycle listener ordering. If you also have your own prePersist listener on the same entity, order matters — the file must exist before anything tries to hash, resize, or index it. Register your own listener with a higher priority or move the file explicitly in the service before flush().
  • postLoad and absolute paths. Listeners that set an absolute path on a non-persisted property break if the entity is serialized, cached, or detached. Prefer computing paths lazily (getPath() calling a storage service) over mutating entity state on load.
  • Orphaned files. If the DB transaction rolls back after the file was moved, you leak a file. Add a scheduled cleanup that cross-references the storage directory against the entity table — this is cheap and catches both rollback leaks and the "replace on update" bug.
  • Config quirks. The 2018 naming conventions (dir, path, prefix) may not match what the README shows if the README predates the last code change — always trust Configuration.php (the TreeBuilder definition) over the docs for the real key names and defaults.
  • Extension point. The one genuinely reusable idea in these bundles is the storage-agnostic "move on persist, delete on remove" listener. If you fork, keep the listener interface clean (accept a storage service, not a hardcoded path) so you can later swap local disk for S3 or Flysystem without touching entity code.
  • Debugging. If uploads silently no-op, check that the entity is actually managed by Doctrine and that the listener is attached — a @EntityListeners annotation with the wrong FQCN fails silently on flush(). Dump $em->getEventManager()->getListeners('prePersist') to confirm registration.
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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core