setono/kraken-io-bundle
Setono Kraken.io Bundle integrates Kraken.io image optimization into Symfony applications, automatically compressing uploaded images via the Kraken API to reduce file sizes, speed up page loads, and maintain visual quality with minimal configuration.
This is a thin Symfony bundle whose only real job is to wire kraken-io/kraken-php into the container: it reads api_key/api_secret, builds the SDK client, and registers it as a service. There is no image pipeline, no queue, no storage abstraction. Treat it as a config bridge, not a feature. The v1.1.0 release changes nothing about that shape — it is a dependency-constraint refresh, not a feature release.
Install and configure (Symfony app):
composer require setono/kraken-io-bundle
# config/packages/setono_kraken_io.yaml
setono_kraken_io:
api_key: '%env(KRAKEN_IO_API_KEY)%'
api_secret: '%env(KRAKEN_IO_API_SECRET)%'
Then confirm what you actually got — the service ID is the thing you'll inject everywhere:
bin/console debug:container kraken
First use case: optimize an uploaded image before it lands on your storage disk.
public function __construct(private Kraken\Client $kraken) {}
public function handle(UploadedFile $file): void
{
$this->kraken->upload([
'file' => $file->getPathname(),
'wait' => true,
]);
}
If you're in Laravel, stop here. This bundle is Symfony-only; there is no service provider, no vendor:publish, no Laravel recipe. The honest move is composer require kraken-io/kraken-php, bind the client as a singleton in AppServiceProvider, and read credentials from config/services.php. You lose nothing — the bundle adds roughly zero behaviour on top of the SDK. v1.1.0 does not change this: "upped dependencies" is not a Laravel bridge.
Wrap it behind your own interface. The single most valuable thing you can do with a low-signal dependency is refuse to depend on it directly. Define ImageOptimizerInterface::optimize(string $path, array $options): Result and adapt the Kraken client to it. This lets you swap to TinyPNG, ImageOptim, or Cloudflare Polish later without touching call sites, and lets you fake it in tests.
Async with wait => false. Kraken returns a kraken_id immediately; you poll status($id) until it's success. In Laravel that's a queued job plus a poll/retry loop; in Symfony it's a Messenger message and handler. Persist the kraken_id in your DB so a crashed worker can resume rather than re-upload and re-bill.
Callback URL flow. For large batches, pass callback_url and let Kraken POST the result back. This requires a public, CSRF-exempt endpoint (Laravel: routes/api.php; Symfony: a controller with #[Route]). Verify the payload before trusting it, and store the callback body for debugging.
Upload → optimize → store, with originals preserved. Don't optimize in place on your only copy. Write the original to one disk/bucket and the optimized variant to another, keyed by content hash. This makes re-optimization idempotent and free.
Flysystem is the idiomatic day-to-day path. Setono publishes a companion Flysystem filter bundle for Kraken; if you're on Flysystem (very common in Symfony apps and available in Laravel via league/flysystem), a write-time filter is far less code than hand-rolling upload hooks. Note that the v1.1.0 bump applies to this bundle, not necessarily the sibling filter — check the sibling package's PHP/Flysystem version constraints before committing. That's where the real integration friction lives.
Config through env, validated early. %env(KRAKEN_IO_API_KEY)% in Symfony, env('KRAKEN_IO_API_KEY') in Laravel. Add a boot-time assertion (compiler pass in Symfony, a check in your service provider or a health-check command in Laravel) so a missing credential fails at deploy, not at the first user upload.
Log every call. The bundle gives you no observability. Decorate the client (Symfony decorates:; Laravel $this->app->extend(...)) and log method, input bytes, output bytes, kraken_id, HTTP status, and latency. Kraken bills per call — this log is your cost dashboard and your debugging trail.
composer.json diff before assuming anything — confirm what the Symfony, PHP, and kraken-io/kraken-php constraints actually moved to. No new features, no new extension points, no new tests implied. The project is still low-signal with few dependents; budget for reading the source, which is small enough to read in ten minutes.composer require. That's genuinely useful — but it does not mean the service definitions were modernised. A dependency bump rarely touches deprecated aliases or private-service defaults. If the container won't compile, a manual service definition pointing at the SDK client is still usually faster than patching the bundle.config/bundles.php registration works regardless. Verify against your actual Symfony version with debug:container rather than trusting the constraint.kraken-io/kraken-php is older than the bundle and may not have received the same dependency refresh. Verify it installs on your PHP version, check for implicit-nullable and dynamic-property deprecations, and pin it explicitly in your composer.json so a future transitive bump doesn't move it under you. Run your own smoke test against the sandbox — don't infer compatibility from the bundle's composer.json alone.api_key is empty; you find out at runtime with an auth error deep in an upload. Validate explicitly.wait: true will stall your request. Large images can take many seconds. Never call it synchronously inside a web request that a user is waiting on — queue it, or use wait: false.lossy: true for photos; keep lossless for logos, screenshots, and anything with text. Expose this as a per-use-case option rather than hardcoding a quality value.api_key/api_secret are plain strings in bundle config, so %env()% (or Laravel's config/services.php reading env()) is mandatory. Never let a real key reach a committed file.How can I help you explore Laravel packages today?