slauta/avalanche123-imagine-bundle
A Symfony bundle that integrates the Imagine image manipulation library, letting you define filters and generate cached thumbnails, crops, and resized images through configurable routes and Twig helpers. Useful for responsive image workflows and on-the-fly asset processing.
This bundle is a thin Symfony wrapper around the Imagine PHP image library. Its whole job is to let you declare named image filters in YAML and apply them to images from Twig (and PHP), generating and caching the transformed images on first request. It is a fork of the long-deprecated avalanche123/imagine-bundle, so treat it as a legacy integration for Symfony 2.x / early 3.x — the useful steps are the same as the original.
Minimal setup:
Install with the fork's package name (the original was avalanche123/imagine-bundle):
composer require slauta/avalanche123-imagine-bundle
This pulls in imagine/imagine (check which version lands; ~0.6/0.7 era API). Make sure the GD or Imagick extension is present on the host.
Register the bundle in app/AppKernel.php (namespace is inherited from the original — confirm the exact class name in the package's vendor/ tree before pasting):
new Avalanche\Bundle\ImagineBundle\AvalancheImagineBundle(),
Import the bundle routing so the controller that serves generated images is reachable:
# app/config/routing.yml
_imagine:
resource: "@AvalancheImagineBundle/Resources/config/routing.xml"
prefix: /
Configure at least one filter under the bundle's config key (avalanche_imagine in the original; verify if the fork renamed it):
# app/config/config.yml
avalanche_imagine:
driver: gd
web_root: %kernel.root_dir%/../web
cache_prefix: media/cache
filters:
thumb:
type: thumbnail
options: { size: [120, 90], mode: outbound }
First use case — a thumbnail in a template. The canonical usage is the bundle's Twig filter (original name apply_filter; forks have used imagine_filter):
<img src="{{ 'images/photo.jpg' | apply_filter('thumb') }}" alt="Photo">
The output is a URL like /media/cache/thumb/images/photo.jpg. On first hit, the controller reads images/photo.jpg, applies the thumb filter via Imagine, writes the result into web/media/cache/..., then serves it (typically via redirect). Subsequent hits skip Imagine entirely.
Where to look first: the bundle's Resources/config/ (services, routing, Twig extension) and its DependencyInjection/Configuration.php. Those three files tell you the real service IDs, the actual Twig filter name, the config root key, and the supported option shapes — all of which drift between forks. Do not trust blog posts written for the upstream bundle.
Best first use case: fixed-size thumbnails/avatars in a listing page. It is the lowest-risk, most obviously valuable filter, and it validates the whole pipeline (driver → route → cache dir → Twig) in one shot.
Declarative filters, applied by name. Every transformation lives in config; templates only reference the name. This is the core value of the package — designers/devs don't hand-write Imagine code.
avalanche_imagine:
filters:
avatar: { type: thumbnail, options: { size: [64, 64], mode: outbound } }
hero: { type: relative_resize, options: { widen: 1200 } }
square: { type: crop, options: { start: [0, 0], size: [300, 300] } }
rotated: { type: rotate, options: { angle: 90 } }
branded: { type: watermark, options: { image: "%kernel.root_dir%/../web/logo.png", position: bottomright, x: 10, y: 10 } }
type maps to Imagine's FilterInterface implementations (thumbnail, resize, relative_resize, crop, rotate, paste, watermark, grayscale, strip, …). options is passed straight through as the Imagine option array, so the authoritative reference is Imagine's own docs, not this bundle's.
Multiple sizes from one source. Define thumb_sm, thumb_md, thumb_lg against the same original and switch in templates. This is the idiomatic pre-srcset approach and still works fine for fixed layouts.
Twig as the primary surface, PHP for everything else. In templates, pipe the raw relative path through the filter. When you need the URL outside a template (emails, JSON APIs, sitemaps), resolve the same route in PHP:
$url = $this->get('router')->generate('_imagine', [
'path' => 'images/photo.jpg',
'filter' => 'thumb',
]);
Generating the URL is cheap; generation of the image only happens when that URL is requested.
Cache warming on deploy. Because generation is lazy and synchronous, the first visitor after a deploy eats the latency. Warm it: after cache:clear, iterate your known image list and curl (or file_get_contents) each _imagine URL, or drive the filter manager service directly:
$filter = $this->get('imagine.filter.manager')->get('thumb'); // verify service id
$image = $this->get('imagine')->open($absolutePath); // verify service id
$filter->apply($image)->save($cachePath);
Put this in a console command and run it as a deploy step.
Custom filters. For anything Imagine does not provide, implement Imagine's FilterInterface and register it with the filter manager through a service definition + a compiler pass or an explicit addFilter call in a bundle extension. This is the intended extension point; config filters remain the default path for 95% of needs.
Composition with Symfony assets. The filter returns a path, so wrap it in asset() if you version assets or serve from a CDN subdomain. Be aware that means the generated file must exist in whatever directory that CDN/origin publishes — the web_root + cache_prefix must match your deployment layout.
avalanche_imagine), Twig filter name (apply_filter vs imagine_filter), bundle class namespace, route name (_imagine), and service IDs can all differ from the upstream docs. Grep Resources/config/*.xml and DependencyInjection/Configuration.php first; half of all "it doesn't work" reports here are name mismatches.path and filter from the URL. If the controller does not sanitize, you have path traversal / arbitrary file read (../../app/config/parameters.yml) and a CPU-exhaustion vector (anyone can request any filter against any path). Mitigate at the web-server level: only allow known filter names in the route requirement and deny .. segments; ideally restrict the source directory.web/media/cache (or your cache_prefix) must exist and be writable by the PHP/web-server user. A permissions failure surfaces as a 500 on the image URL, not a friendly error — check var/logs//app/logs/.cache:clear wipes Symfony's container cache but not web/media/cache. Change a filter's options and you will keep seeing the old output until you manually delete that directory. Make "clear the imagine cache" an explicit step whenever filter config changes.gd is ubiquitous but lossy, memory-hungry on large images, and lacks some filters (quality/perf differ). imagick is usually better but must be installed and enabled; confirm with php -m. Setting driver to something unavailable fails at request time.thumbnail wants size + mode (inset/outbound); crop wants start + size; relative_resize wants widen/heighten/increase/scale, not width/height. Cross-check against the exact Imagine version in composer.lock.#, ? or non-ASCII must be URL-encoded before being routed through the filter; otherwise the generated URL 404s or the controller receives a truncated path. Prefer slugged filenames.cache_prefix / web_root mismatch = 404s. The bundle writes to web_root + cache_prefix but the URL it returns is built from the same prefix. If your vhost document root, a symlinked current/ release, or a CDN origin points somewhere else, images generate successfully yet never resolve. Verify the physical file exists at the exact URL path when debugging. In capistrano-style deploys, make the cache dir a shared, symlinked path.media/cache (or keyed subdirectories) and delete derivatives when the source is replaced._imagine URL directly in the browser (not the <img>), watch for the redirect target, then confirm that file lands on disk. If the URL 404s, it's routing/config. If the file lands but the image is broken, it's the driver or filter options. If the file doesn't update, it's the media cache./media/cache/{filter}/{path} — the prefix is configurable and your hand-built string will silently stop matching after a config change.How can I help you explore Laravel packages today?