opifer/media-bundle
Opifer MediaBundle is a Symfony bundle for managing and displaying media assets such as images, videos, and files. It provides media entities, upload handling, and Twig helpers for embedding media in templates.
Latest tag is 0.1.3 — it adds editing of existing media items and fixes to run cleanly on Symfony 2.8. That confirms the supported target: PHP 5.5–7.0 and Symfony ~2.7/2.8. Treat the release as the ceiling, not a sign of life: the bundle is archived and there are no PHP 8 / Symfony 4+ fixes coming. If you're coming from Laravel, note up front that this is a Symfony bundle — no service provider, no config/media.php, AppKernel-style container wiring. The install path below is Symfony; the portable ideas (provider pool, storage abstraction) are what you'd re-implement in Laravel with spatie/laravel-medialibrary + Intervention Image + Flysystem.
Minimal path:
composer require opifer/media-bundle (if Packagist still resolves it — otherwise vendor it from the GitHub tag).AppKernel: new Opifer\MediaBundle\OpiferMediaBundle().app/config/routing.yml.php app/console config:dump-reference opifer_media.Media entity extending the bundle's mapped superclass and implementing its interface. The bundle does not ship a concrete entity — this is the first real task, and it is the step people miss. Map it (@ORM\Entity), then doctrine:schema:update or generate a migration.Look first at DependencyInjection/Configuration.php for the real config surface, and the Model/ + Provider/ directories for the extension contracts. Docs are thin; the code is the spec.
First use case: a Product with a ManyToOne to your Media entity, a file picker in the admin form, and an image thumbnail rendered in Twig. That exercises every layer — storage, provider, manager, templating helper — and tells you fast whether the bundle is worth keeping.
Mapped-superclass inheritance. You own the entity, the table, and the migrations; the bundle owns the behaviour. Keep your entity thin — a subclass with the table name and any extra relations — and let the bundle's manager do persistence and file handling. This is the cleanest way to add your own columns (e.g. alt, caption, sortOrder) without patching vendor code.
Manager/repository injection. Resolve the manager from the container (opifer_media.manager or the class-based service ID — check debug:container opifer_media) rather than constructing entities by hand. Uploads should go through the manager so storage naming, provider detection, and metadata stay consistent.
Provider pool. The bundle routes uploaded media through per-type providers (image, generic file, and remote types like YouTube/Vimeo). When rendering, use the provider/type to decide the template — images get Imagine filters applied, remote types render as embeds, generic files become download links. If you need a new type (e.g. SVG or a DAM-sourced asset), implementing the provider interface and tagging the service is the sanctioned extension point.
Storage abstraction. Swapping local filesystem for Gaufrette/Flysystem is a config change, not a code change, as long as you always go through the manager. Do this early — it's much cheaper than retrofitting after paths are baked into the database.
Editing media (new in 0.1.3). The picker/manager now exposes an edit flow for existing media, so metadata edits (name, alt/caption, provider selection) no longer need a hand-built admin form. Route edits through the manager too, so a changed file or provider re-runs the same storage/naming path as upload; if you map extra columns, add them to your own form type and merge them in. Treat the edit flow as the bundle's UI, not your model's write path.
Form integration. Embed the bundle's media picker form type into your own admin form types (Sonata Admin or plain Symfony forms), and link the edit action into your list/detail views. For rich text, wire the picker to CKEditor/Redactor through the bundle's controller endpoint — the modal returns an ID you store alongside the body HTML, and you resolve it at render time.
Rendering. Thumbnails come from Imagine filters; always render a filter variant rather than the original for list views, and cache-bust on the stored filename rather than the media ID.
Lifecycle. Add a Doctrine listener on your entity's preRemove/postRemove to delete the underlying file. The bundle predates widespread orphanRemoval usage; without a listener you will accumulate dead files indefinitely. Re-saving through the 0.1.3 edit flow doesn't clean up superseded files either.
ContainerBuilder autowiring, and the bundle-registration style won't survive a Symfony 4+ upgrade. The 2.8 compatibility fixes make 2.8 the sweet spot, not a launchpad. Treat any adoption as a fork-and-maintain decision.Media row leaves the file on disk and any Imagine thumbnail cache untouched. Write the listener, and put thumbnail cache in a path you can prune with a cron.web/ (pre-Symfony 4) is the docroot; the storage adapter writes elsewhere. Check the generated URL against what actually exists on disk when images 404 — it's almost always a path/naming mismatch, not a permissions issue.app/console debug:container opifer_media to find the real service IDs, debug:router for the picker endpoints, and the dev log for provider-pool resolution failures.app/Resources/OpiferMediaBundle/views/. All three are stable enough to lean on.How can I help you explore Laravel packages today?