rokka/client-bundle
Symfony bundle that integrates the Rokka image CDN service, providing service configuration, dependency injection, and helpers to generate and manage optimized image URLs and stacks in your Symfony applications.
The bundle is thin glue: it wires the official rokka/client PHP client into Symfony's container and adds a Twig helper. Day-to-day you will spend most of your time in the rokka/client docs, not the bundle's.
Install (Flex usually registers the bundle automatically; otherwise add Rokka\ClientBundle\RokkaClientBundle to config/bundles.php):
composer require rokka/client-bundle
As of 1.4.1 the bundle allows Symfony 7 and is tested on PHP 8.3, so the same release works on Symfony 6.4 and 7.x. If you are on Symfony 7 you need ^1.4.1 — earlier 1.x releases cap the constraint below 7.
Configure with an API key from the Rokka dashboard. Keep it in .env.local / secrets, never in VCS:
# config/packages/rokka.yaml
rokka:
api_key: '%env(ROKKA_API_KEY)%'
# .env.local
ROKKA_API_KEY=your-key-here
Look first at the bundle's README for the exact service IDs it registers (it exposes the Rokka\Client API client as a service), then at the rokka/client README for the operations (upload, getStack, createStack, getSourceImage, URL helpers).
First use case — upload an image to a stack and render it in Twig:
use Rokka\Client\Api; // or Rokka\Client\Image, depending on client version
public function __construct(private Api $rokka) {}
public function __invoke(string $path): string
{
$image = $this->rokka->upload(file_get_contents($path), 'my-images', 'photo.jpg');
return $image->getHash(); // store this, not the URL
}
<img src="{{ rokka_image_url('my-images', hash, 'display') }}" alt="">
If the bundle exposes a Twig function/filter (typically rokka_image_url/rokka_image), prefer it over hand-built URLs — the host pattern (https://{org}.rokka.io/...) and stack encoding is fiddly.
Store hashes, compose URLs at read time. Persist source_hash (and the stack name) on your entity. Rebuilding the URL later lets you change stacks, add signed access, or swap organizations without a data migration. Never store the rendered *.rokka.io URL in a database column.
Inject the client, don't reach into the container. Autowire the registered client service into upload services, Messenger handlers, or CLI commands. That keeps it mockable in tests and lets you decorate it (e.g. add logging or retries).
Push uploads off the request path. Uploads are network calls. In an admin edit flow, dispatch a UploadImageToRokka message with the local path and update the entity in the handler; the web request stays fast and you get retries for free.
Define stacks declaratively. Keep stack names and operations in config (or a small PHP data provider) and write a console command that iterates them, checks getStack()/getStackStatus(), and creates missing stacks. This makes stack definitions code-reviewable and lets a fresh Rokka organisation be bootstrapped in CI.
Render through a single Twig helper. Wrap the bundle's Twig extension in your own image_url() helper that injects the stack name and any signing/versioning logic. When Rokka URLs need a ?v= cache-buster or a signed token, you change it in one place instead of across templates.
Use it alongside EasyAdmin / Sonata / UX. A RokkaImageType form field or a Twig rokka_thumb() filter gives editors live previews of uploaded-async images while the underlying entity only holds a hash.
Separate environments. Use a distinct API key (and, ideally, org) for dev/test so uploads and stack experiments don't pollute production assets. Add ROKKA_API_KEY= to phpunit.xml.dist and replace the client service with a stub in services_test.yaml.
Sign restricted stacks. For private/user-uploaded content, generate signed URLs server-side (the client exposes a signing helper) rather than relying on obscure stack names. The bundle doesn't do auth for you.
composer update. Conversely, if composer require resolves to an older 1.x on a Symfony 7 app, you pinned yourself out of the fix — check composer why-not rokka/client-bundle 1.4.1.createStack() with a stack name that already exists but with different operations returns a conflict/error (or silently keeps the old definition). When you change operations, publish under a new stack name and update config; don't mutate in place.?v=2) or, better, use a new stack name.rokka.client vs rokka.api — run bin/console debug:container rokka and wire to what exists; consider aliasing it in services.yaml to a stable interface of your own.upload() with the right source name and persists the returned hash — not that a real image exists.symfony/mime) before calling the API so failures surface as form errors, not 500s from a remote call.Rokka\Client\ClientException/transport errors into user-facing messages; remote 4xx/5xx otherwise bubble up as generic 500s.rokka/client in sync. The bundle is a thin adapter; features, bug fixes, and signing helpers land in the client first. Check the client changelog before assuming a capability is missing from the bundle.vendor/rokka/ code are the real docs.How can I help you explore Laravel packages today?