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

Media Bundle Laravel Package

symfony-cmf/media-bundle

Symfony CMF Media Bundle adds media management to Symfony CMF apps: upload, browse, edit, and organize images and documents with PHPCR-backed storage and integration into the CMF content framework.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the reality check: symfony-cmf/media-bundle is a Symfony bundle (namespace Symfony\Cmf\Bundle\MediaBundle), not a Laravel package. There is no service provider, no facade, no config/app.php entry, and no artisan command. It registers itself through CmfMediaBundle in a Symfony kernel and hard-depends on doctrine/phpcr-odm, symfony/framework-bundle, symfony/form, and liip/imagine-bundle for image work. You cannot composer require it into a Laravel app and have it behave like a normal Laravel dependency — the PHPCR storage, form upload integration, and image variation pipeline all assume an HttpKernel + Doctrine bundle lifecycle that Illuminate does not provide.

That leaves two realistic entry points for a Laravel developer:

  1. You already operate a Symfony CMF site and this bundle is part of it — you're a consumer.
  2. You deliberately stand up a small Symfony service (media manager + optional Sonata admin UI) that owns assets, and have Laravel talk to it over HTTP.

Minimal steps for scenario 2:

  • Scaffold a Symfony 3.x app (the last release, 1.3.1, only claims Symfony 3.0; Symfony 4+ needs shims).
  • composer require symfony-cmf/media-bundle:^1.3 liip/liip-imagine-bundle doctrine/phpcr-odm doctrine/phpcr-bundle jackalope/jackalope-doctrine-dbal
  • Register CmfMediaBundle, DoctrinePhpcrBundle, LiipImagineBundle in app/AppKernel.php.
  • Configure the cmf_media extension: media_manager.media_basepath: /cms/media, a media_class (e.g. …\Doctrine\Phpcr\Image), plus a doctrine_phpcr session. Run bin/console doctrine:phpcr:init.
  • First use case: accept an upload, pass it through UploadFileHelper to persist a File/Image document, then ask the configured Imagine thumbnail generator for a named variation and hand back a public URL.

Where to look first in the source:

  • DependencyInjection/Configuration.php — the authoritative config tree (media_manager, thumbnail_generators, upload_file_helper, etc.).
  • Resources/config/*.xml — real service IDs: cmf_media.manager, cmf_media.upload_file_helper, and the cmf_media.thumbnail_generator.* implementations.
  • Model/MediaInterface.php and Model/ImageInterface.php — the contracts your application code should type against.
  • Doctrine/Phpcr/MediaManager.php — the API you'll actually call every day.

Implementation Patterns

Talk to the manager, not the documents. Inject cmf_media.manager (MediaManagerInterface) and use createMedia(), findMediaById(), getUrlSafeFilename(), getMediaBasepath(). Resolving PHPCR nodes directly couples you to node paths, which is exactly what breaks on upgrade and what makes the bundle feel "fragile" when it isn't.

Uploads are Symfony UploadedFile territory. UploadFileHelper expects Symfony\Component\HttpFoundation\File\UploadedFile and pulls the request from RequestStack. On the Symfony side you bind this through a form; from Laravel you're calling a Symfony controller endpoint with a multipart body, so keep that controller thin — take the UploadedFile, delegate to the helper, return {id, url, mime, size}.

Image variations via configuration, not code. Declare filter sets once under the thumbnail/Imagine config, then reference them by name in templates or in a ?variation=thumb query param. The bundle's cache resolver writes variations under the Imagine cache directory. Don't hand-roll Imagine filters in application code — you bypass the cache resolver and regenerate on every request.

Extending media types. Subclass Doctrine\Phpcr\File or Image, add fields, and point media_manager.media_class (or the per-class mapping) at your class. Wire the extra fields into Sonata admin if editors need them. This is the intended extension seam — resist adding logic to MediaManager itself.

Laravel-side pattern (the realistic one). Store only the Symfony media ID (a PHPCR UUID/path string), the resolved public URL, mime type, dimensions, and a variation_version in MySQL. Create on upload, cache the returned metadata on save, and render pages by reading the cached URL — never call the Symfony service at render time. Treat the media service like an asset store, not a runtime dependency; the moment it becomes a synchronous render-time call, you've added a single point of failure to every page.

Content references. Symfony CMF content documents hold PHPCR ODM references to MediaInterface. On the Laravel side, mirror that as a media_id column behind a small MediaReference value object, so the two storage systems never share a raw ID type.

Gotchas and Tips

  • Archived and stale. Last release was 2016-06-14 (1.3.1) — a Symfony 3.0 compatibility bump, not a feature release. No security fixes since. It will not run on Symfony 5/6 or PHP 8 without a fork. Budget for that before you build on it.
  • PHPCR-ODM is the real commitment. Jackrabbit needs a Java service in production; jackalope-doctrine-dbal lets you run on MySQL but is slower, has edge cases around references and node moves, and its own maintenance is thin. If you don't already operate PHPCR, the storage layer is the cost — not the media manager.
  • media_basepath vs. web path. Media lives under a logical basepath (/cms/media) that must be mapped to a web-served directory. The classic "thumbnails 404" bug is a mismatch here, or a missing/unwritable Imagine cache directory. Check those before blaming the bundle.
  • No Laravel facade — don't fake one. Trying to load a Symfony bundle into the Illuminate container is a losing fight against two incompatible HttpFoundation lifecycles and two service containers. The only sustainable integration is an HTTP boundary or a shared PHPCR-backed data tier.
  • Wrap the manager, listen for hooks. Prefer your own thin service interface over subclassing MediaManager, and use the manager's pre/post-save hooks (or a decorator) for side effects. When you eventually replace this bundle, a decorator drops out cleanly; a subclass drags half the class with it.
  • Debugging failed uploads. Enable the Symfony profiler and watch the phpcr_odm and cmf_media channels. bin/console doctrine:phpcr:node:dump on the media root is faster than var_dump inside a controller, and it shows you whether the failure is at persist time or at document-creation time.
  • Cache invalidation across the boundary. Imagine variation URLs are stable per filter set; if you edit filter config you must bin/console liip:imagine:cache:remove, and bump the variation_version you cache in Laravel. Otherwise Laravel keeps serving stale URLs to variations that no longer exist.
  • Config keys drift between docs and source. The README lags 1.3.1. When bin/console config:dump-reference cmf_media disagrees with the docs, believe the console — that's the tree the extension actually loads.
  • Version note. If you're sitting on Symfony 2.7 and nothing forces 3.0, skip 1.3.1; it's a pure compatibility patch and there is no later release coming. If you need it for a Laravel 5.2/5.3-era stack where the Symfony components land at 3.0, pin ^1.3.1 so later (hypothetical) patches land — but accept that there almost certainly won't be any.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core