tourze/easy-admin-image-preview-field-bundle
A Tourze bundle that adds an image preview field for EasyAdmin, letting administrators see thumbnails directly in list and detail views instead of raw file paths. Easy to configure, it improves media management and makes image-heavy admin panels quicker to scan and verify.
What you're getting. tourze/easy-admin-image-preview-field-bundle is a Tourze-published bundle that adds an image-preview field type for the EasyAdmin admin generator. Note the stack mismatch up front: EasyAdmin is a Symfony package, not Laravel. In a pure Laravel app you cannot consume this directly — there's no service provider, no Blade views, no config/ publish tag. If your day-to-day is Laravel, this package only matters to you if you're maintaining a Symfony/EasyAdmin back-office alongside a Laravel API, or you're being asked to evaluate it for that context. Confirm that before spending time on it.
Install and inspect (5 minutes):
composer require tourze/easy-admin-image-preview-field-bundle:^1.0
Then read, in this order:
composer.json — the require block tells you which EasyAdmin major and PHP version you're locked to. This is the single most important file, because the release ships no notes.src/*Bundle.php — the bundle class; check whether it's registered via extra.symfony.bundle (Flex auto-discovery) or needs a manual line in config/bundles.php.src/Field/ (or equivalent) — the field class; note its parent (Field, ConfiguratorField, etc.) and any setTemplatePath defaults.templates/ — the Twig template that actually renders the <img>. This is where you'll be doing 90% of your customization.First use case. Replace a plain TextField/UrlField on an entity's CRUD controller with the preview field so editors can see the cover image in the index and detail views:
public function configureFields(string $pageName): iterable
{
yield ImagePreviewField::new('coverUrl')
->setLabel('Cover');
}
Point the field at an accessor that returns a publicly resolvable URL, not a storage path — the template will drop it straight into src="".
Field-per-context, not global config. Most EasyAdmin field bundles have no meaningful configuration tree; customization happens at the field instance. Set the template explicitly so an upstream template rename in a patch release doesn't silently blank your column:
yield ImagePreviewField::new('coverUrl')
->setTemplatePath('@EasyAdminImagePreviewField/custom/thumbnail.html.twig');
Override the template in your app, don't fork. Symfony's bundle template override convention (templates/bundles/<BundleName>/...) means you can control sizing, loading="lazy", placeholder behaviour, and the click-through to full size without touching vendor code:
{# templates/bundles/EasyAdminImagePreviewFieldBundle/.../preview.html.twig #}
{% if field.value %}
<a href="{{ field.value }}" target="_blank" rel="noopener">
<img src="{{ field.value }}" alt="" loading="lazy"
style="max-height: 48px; max-width: 96px; object-fit: cover;">
</a>
{% else %}
<span class="text-muted">—</span>
{% endif %}
Pair it with your upload pipeline. The field only renders; it does not store. Wire it to whatever writes the file (VichUploader, a custom preUpdate listener, or an S3/Flysystem adapter) and expose a getCoverUrl(): ?string accessor on the entity. Keeping the URL behind an accessor lets you swap disks (local in dev, S3 in prod) without touching the admin config.
Collections and galleries. For multi-image fields, don't stack N preview fields. Use EasyAdmin's CollectionField with a nested ImagePreviewField, or a single TextField with setTemplatePath() pointing at a grid template that iterates the relation. The former is less code; the latter is faster to render.
Verify in a functional test. A cheap smoke test catches template-path breakage after every EasyAdmin upgrade:
$client->request('GET', '/admin/product');
$this->assertSelectorExists('img[src*="cover"]');
Pin both sides. "tourze/easy-admin-image-preview-field-bundle": "^1.0" in composer.json, but also pin easyadmin itself to a minor range and commit composer.lock. A bundle that hooks upstream Twig block names has an implicit version contract that Composer cannot infer.
1.0.0 here reads as "first tag," not "API frozen." Diff the tag against main before assuming anything about BC guarantees, and re-diff before every minor bump.src/ end-to-end — it's usually a few hundred lines, and that reading is the actual documentation.extra.symfony.bundle in the package's composer.json, nothing registers and you'll get "unknown field type" errors with no hint. Add it manually to config/bundles.php and move on.@EasyAdmin/crud/field/... blocks. An EasyAdmin minor release that renames a block fails silently (blank cell) rather than loudly. Keep the smoke test above in CI.asset() for CSS/JS shipped in assets/, run php bin/console assets:install (or asset-map:compile under AssetMapper). Missing assets show as an unstyled oversized image, which reads like a template bug but isn't.max-width/max-height and serve a thumbnail rendition rather than the original. Add loading="lazy" and a fixed width/height to avoid layout shift.src. Ensure the accessor returns a URL built from a trusted disk, never a raw DB string an editor can control — otherwise you've added an open-redirect/XSS surface to your admin.bin/console debug:container --tag=twig.extension and debug:twig to confirm the field is wired; if the cell is blank, check var/log/dev.log for a Twig LoaderError before assuming the field is broken.setTemplatePath() → app-level template override → decorating the field class in services.yaml → forking. Anything past step three means you should be asking whether the dependency is worth keeping.How can I help you explore Laravel packages today?