genj/thumbnail-bundle
genj/thumbnail-bundle provides configurable thumbnail generation for Symfony applications, helping you create, cache, and serve resized images through services, Twig helpers, and flexible size definitions.
Be clear about what you are installing: genj/thumbnail-bundle is a Symfony bundle, not a Laravel package. It wraps liip/imagine-bundle and changes the URL/filename that Liip produces so the generated thumbnail carries a keyword-bearing name (e.g. my-photo-small.jpg) instead of Liip's default cache path (/media/cache/small/uploads/my-photo.jpg). If you are on Laravel, you cannot composer require it and call it a day — you either run it inside a Symfony app that fronts your media, or (more likely) you read its naming logic and reimplement the ~50 lines in Laravel.
Where to look first in the repo:
composer.json — confirms the Symfony/Liip version constraints (this is a 2015-era package, so expect Symfony 2.x and PHP 5.x constraints that will not resolve on a modern stack).DependencyInjection/ and Resources/config/services.yml — shows the service that wraps Liip's cache manager and how the Twig helper is registered.thumbnail(path, filter) or similar).Minimal install (Symfony only):
composer require genj/thumbnail-bundle
// app/AppKernel.php
new Genj\ThumbnailBundle\GenjThumbnailBundle(),
new Liip\ImagineBundle\LiipImagineBundle(),
Configure at least one Liip filter, then call the bundle's helper with an image path and that filter name to get a friendly URL.
First use case: an article/listing page with a cover_image column. You want <img src="/media/cache/small/uploads/2015/12/my-photo-small.jpg"> rather than the default cache URL — the filter name and original slug live in the filename, which is the whole point of the package.
1. Controller/service usage (Symfony). Inject the bundle's thumbnail service and generate URLs in your controller or a view model, keeping templates dumb:
$url = $this->get('genj.thumbnail')->getUrl($entity->getImagePath(), 'small');
2. Twig helper. The bundle ships a Twig function; the day-to-day pattern is:
<img src="{{ thumbnail(article.coverImage, 'small') }}" alt="{{ article.title }}">
3. The Laravel port (what you will actually do). Since the package is archived and Symfony-shaped, extract the naming convention into a small service and pair it with intervention/image or spatie/laravel-image:
class SeoThumbnail
{
public function url(string $path, string $filter): string
{
$name = pathinfo($path, PATHINFO_FILENAME);
$ext = pathinfo($path, PATHINFO_EXTENSION);
$slug = Str::slug($name);
return "/media/cache/{$filter}/{$slug}-{$filter}.{$ext}";
}
}
Then register a Blade directive or a Storage macro so views stay clean: @thumb($article->cover_image, 'small').
4. Pair with srcset/responsive images. The naming scheme really pays off when you emit several filters for one source:
<img
src="{{ thumb($post->image, 'medium') }}"
srcset="{{ thumb($post->image, 'small') }} 480w,
{{ thumb($post->image, 'medium') }} 960w,
{{ thumb($post->image, 'large') }} 1600w"
sizes="(max-width: 600px) 480px, 960px"
alt="{{ $post->title }}">
5. Integration tips.
composer.json constraints almost certainly conflict with PHP 8 / Symfony 5+; a composer require will fail or force you into dependency-hell workarounds.uploads/a/photo.jpg and uploads/b/photo.jpg), producing the same friendly output when you flatten to photo-small.jpg. Append a short hash of the full source path, and only strip it for display if you truly need clean names./media/cache/<filter>/.... If your new name changes that structure, you need either a rewrite that maps friendly names back to the Liip cache layout, or you generate-on-demand in a controller/route. Forgetting this yields 404s for every thumbnail.basename() + slugification; never trust the raw value from a DB row or upload.liip_imagine.filter_sets), confirm the cache directory is writable, run Liip's cache resolve command (e.g. liip:imagine:cache:resolve) to materialize files, and clear both Symfony's cache and the Liip media cache after config changes — stale config is the most common "my URL is wrong" cause.Str::slug() plus your image driver.How can I help you explore Laravel packages today?