presta/cms-media-bundle
PrestaCMS Media Bundle adds media management to Symfony-based PrestaCMS sites, letting editors upload, organize, and reuse images and files across pages. It provides storage, thumbnail handling, and CMS integration for content assets.
Reality check before anything else. presta/cms-media-bundle is a Symfony 2.x bundle for PrestaCMS (Symfony CMF + Sonata Admin), last released 2014-02-26 and archived. It has no Laravel service provider, no illuminate/* compatibility, and its composer constraints (symfony/* ~2.3, PHP 5.x) will conflict immediately with any modern Laravel app. composer require presta/cms-media-bundle in a Laravel project is a dead end — expect a dependency-resolution wall, not a working install.
That leaves two realistic entry points:
Where to look first, in order:
Block/ — the block classes are the product. Everything else is wiring.Resources/config/services.yml and DependencyInjection/Configuration.php — service ids and the config keys you'll actually set.Entity/ — the media model and how a block references it (almost certainly by id, not by embedded object).Resources/views/Block/ — Twig rendering of each block type.Resources/public/ — the CKEditor plugin (JS + icons) that opens the media browser.First use case to validate the install: add a "Media" block to a CMS page that renders one image/video/file with caption and alignment, and click the CKEditor toolbar button to insert an existing media item into rich text by id. If both work, the rest is template polish. Minimum legacy steps: require the bundle, register it in AppKernel after the bundles it depends on (Sonata Admin, the block/CMF bundle, CKEditor bundle, and whatever supplies the media entity), register its admin, run assets:install --symlink, then expose the block in the PrestaCMS block configuration and page-editor picker.
Block-registration over subclassing. Media blocks are declared through configuration and resolved by a block factory keyed on service ids. The durable pattern is: add the block to the config array, override only its Twig template. Subclassing a block class is fragile because the factory and the admin form type both assume the original id.
Id-reference, resolve-at-render. The single most reusable idea in this package: a block stores a media id plus display options (caption, alignment, size, link), and the template resolves that id to an entity via a helper/Twig function at render time. Never serialize the file path or the entity into block content — it breaks on file replacement, storage migration, and CDN moves.
Template override as the customization seam. Overrides live at app/Resources/PrestaCMSMediaBundle/views/Block/*.html.twig. Do all presentation work there; keep the block class and form type stock so upgrades (such as they are) don't fight you.
Token-in-rich-text, not raw HTML. The CKEditor plugin inserts a media reference into the editor payload (an id-bearing element or placeholder token), and a filter/renderer resolves it server-side. Copy this contract verbatim in Laravel — it stops editors from pasting <img src="/uploads/..."> directly into copy, which is the usual source of broken images after a storage change.
End-to-end workflow to mirror:
media_id and option payload.Laravel rebuild mapping if you go the port route:
| Bundle concept | Laravel equivalent |
|---|---|
| Block classes + block factory | Blade component + blocks table or JSON column on a page model |
| Sonata media type / media entity | spatie/laravel-medialibrary (or plank/laravel-mediable) |
| Twig block templates | Blade component views, @props for options |
CKEditor plugin in Resources/public |
CKEditor 5 custom plugin posting to a small JSON endpoint |
| Twig renderer resolving ids | Blade component + Media::findMany() eager-loaded |
cache:clear after every config edit.Resources/public; without assets:install --symlink (or with a wrong web root) the toolbar button simply doesn't appear. Also verify the editor's extraPlugins / toolbars config actually includes it — it registers as a plugin but is not always added to the toolbar by default.getBlockPrefix/getName to find each block's form type, template, and admin registration — that chain is the real documentation.app/config → subclassing (avoid).How can I help you explore Laravel packages today?