novaway/filemanagementbundle
NovawayFileManagementBundle is a Symfony bundle for handling file uploads and attachments. It lets you associate files with Doctrine entities, manage uploads and deletions, and organize stored files through a simple configurable API, streamlining media and document handling in Symfony applications.
Viability check first. Last tagged release is July 2016 and the code targets Symfony 2.x (ContainerAware, getEntityManager(), form type aliases, @inheritdoc style docblocks). With 7 stars and no dependents, treat this as legacy-only: if you are starting a new Symfony app, go straight to vich/uploader-bundle + liip/imagine-bundle — this bundle is essentially a thin convenience layer over both, and you can reproduce it in an afternoon. Use it only if you are inheriting a Symfony 2.8 project that already depends on it, or if you are forking it for a modernization pass.
Install (legacy stack).
composer require novaway/filemanagementbundle — expect resolver conflicts on PHP 8/Symfony 4+; on a legacy box pin php: ~5.6|~7.0 and symfony/symfony: ~2.8.NovawayFileManagementBundle in AppKernel, plus VichUploaderBundle and LiipImagineBundle (both are effectively required for the upload/thumbnail paths).DependencyInjection/Configuration.php — do not trust blog snippets, the keys changed between the 2013 and 2016 releases.Where to look first. Three files tell you the entire public API:
Entity/BaseFile.php and Entity/BaseImage.php — the columns you inherit (name, originalName, mimeType, size, path accessors; images add dimensions).Manager/*Manager.php — the create / save / remove / path helpers you will actually call.Resources/config/services.* — the service ids to inject or override.First use case. A Product with a single main image and two thumbnails:
AppBundle\Entity\File extends BaseFile (and Image extends BaseImage) with @ORM\Entity, a table name, and @Vich\Uploadable on the class plus a @Vich\UploadableField on the uploaded-file property.upload_destination, uri_prefix, namer) and one Liip filter set per thumbnail.VichFileType (or your own FileType), point it at the upload property.UploadedFile, persist the owner, then call the image manager's save() so the file lands on disk and the metadata columns are filled.One attachment entity vs. many. The base entities encourage a single File/Image table with a ManyToOne back to each owner, or a join table per owner. The single-table approach is fine for a handful of use cases and keeps the manager reusable; add cascade={"persist","remove"} and an inverse side only if you need DB-level cleanup.
Upload flow. Keep the manager call out of the entity. The typical request cycle is: form binds UploadedFile → controller sets it on the entity → owner persists → manager save() moves the file into upload_destination and populates name/originalName/size/mimeType. If you ever write a file outside a form (CLI import, fixture, API), set those metadata columns yourself; the base entity will not infer them from a path.
Store originals, derive variants. Do not persist thumbnail paths. Persist the original relative path and render {{ imagine_filter('product_thumb', file.path) }} in Twig. This keeps Liip's cache resolver as the single source of truth and makes filter changes retroactive.
Cleanup via Doctrine events. Wire a subscriber on preRemove (or postRemove) that calls the manager's remove() before the row disappears — otherwise DB rows vanish and files linger in upload_destination forever. Do the same for replacement uploads: when a user swaps an image, delete the previous file explicitly.
Admin/CRUD integration. Because the manager services are ordinary public services, they drop into Sonata Admin or a hand-rolled CRUD controller without ceremony: inject the image/form manager, call save() after $em->flush(). Avoid doing the save in a postPersist listener — the file path is written back to the entity, which then needs a second flush.
Testing. Use a functional test with a small fixture image and a per-test upload_destination under var/tmp. Assert both the DB row and is_file($absolutePath). Point Liip's data_root at the same tmp dir so the filter cache does not pollute web/.
vich_uploader.upload_destination, vich_uploader.uri_prefix, and Liip's web_root/data_root must agree. Nine out of ten "file uploads but images 404" reports come from uri_prefix not matching the web-relative path.'required' => false on the upload field for edit forms; otherwise a no-op submit re-uploads or, worse, blanks the property. Guard with if ($uploadedFile !== null).remove listeners only fire if you use its mapping strictly. Through this bundle's manager you must call remove() yourself. Verify by deleting a record and checking the directory.photo.jpg). Use a uniqid or property namer, and make the stored name unique at the DB level as a backstop.ContainerAwareInterface removals, getEntityManager() → getManager(), deprecated form type service aliases (@Vich\UploaderBundle\Form\Type\VichFileType must be referenced by FQCN), and @inheritdoc on methods with return types. It is a small but non-zero fork.count() on non-countables, implicit nullable params, and dynamic properties. Run under E_ALL with declare(strict_types=1) before trusting it.BaseFile/BaseImage, extend the manager, and override the service definition. The bundle ships almost no templates or form types, so you are writing the UI layer regardless.bin/console debug:container | grep -i novaway lists the manager/storage ids; Vich namer errors surface in dev.log at vich_uploader.namer level. For stale thumbnails, bin/console liip:imagine:cache:remove is your first move — not a browser hard refresh.How can I help you explore Laravel packages today?