geekcell/imagekit-bundle
GeekCell ImageKit Bundle provides Symfony integration for ImageKit.io, with dependency-injection configuration and helpers for uploading, transforming, and delivering optimized images via ImageKit’s CDN. It simplifies service setup for media workflows in PHP applications.
Read this first: it is a Symfony bundle, not a Laravel package. geekcell/imagekit-bundle ships a Bundle subclass plus a DI extension and services.yaml, so composer require will install fine but Laravel has no bundles.php and will never boot it. There is no service provider, no facade, no config publish. In a Laravel codebase you would get zero runtime behaviour out of this package.
Given that, plus 0 stars, 0 dependents, an archived repository and a last release of 2023-07-21, the correct day-to-day move is:
composer require imagekit/imagekit. Everything the bundle does is a thin wrapping of that client.composer.json (Symfony version constraints — this tells you immediately how stale it is), src/DependencyInjection/*Extension.php (the actual config tree), Resources/config/services.yaml (what gets registered and under which service id), and any Twig/ directory (the only part with reusable logic).The first use case you actually want in Laravel is almost always this one:
// config/imagekit.php (your own file, not the bundle's)
return [
'public_key' => env('IMAGEKIT_PUBLIC_KEY'),
'private_key' => env('IMAGEKIT_PRIVATE_KEY'),
'url_endpoint' => env('IMAGEKIT_URL_ENDPOINT'), // https://ik.imagekit.io/yourid
];
// app/Providers/ImageKitServiceProvider.php
public function register(): void
{
$this->app->singleton(\Imagekit\Imagekit::class, fn () => new \Imagekit\Imagekit(
config('imagekit.public_key'),
config('imagekit.private_key'),
config('imagekit.url_endpoint'),
));
}
Then generate a delivery URL:
app(\Imagekit\Imagekit::class)->url([
'path' => '/products/hero.jpg',
'transformation' => [['width' => 800, 'quality' => 80, 'format' => 'auto']],
]);
That is 90% of real usage: building transformation URLs into Blade templates. Uploads and deletes are the remaining 10%.
URL generation in views. The bundle's presumed value-add is a Twig function; the Laravel equivalent is a Blade directive or a small helper class. Prefer a dedicated ImageKitUrl class over a global helper so you can swap it, cache it, and mock it.
Blade::directive('ik', fn ($expr) => "<?php echo e(app(\App\Support\ImageKitUrl::class)->make($expr)); ?>");
// <img src="@ik(['/products/hero.jpg', ['width' => 400]])" alt="">
Upload as a queued job, not inline. Uploads are network I/O with variable latency. Put the SDK call in a ShouldQueue job, dispatch from an observer on model create/update, and store both file_id and url on the model. Never store only the URL — you cannot delete or update a file from a URL.
class UploadToImageKit implements ShouldQueue
{
public int $tries = 3;
public function __construct(public Product $product, public string $localPath) {}
public function handle(\Imagekit\Imagekit $client): void
{
$result = $client->uploadFile(fopen($this->localPath, 'r'), [
'fileName' => basename($this->localPath),
'folder' => '/products',
'useUniqueFileName' => true,
]);
$this->product->update([
'image_file_id' => $result->result->fileId,
'image_url' => $result->result->url,
]);
}
}
Client-side uploads via authentication parameters. The private key must never leave the server. Expose only the signature payload from a small endpoint and let the browser POST directly to ImageKit — this keeps large files off your app server:
Route::get('/imagekit/auth', fn () => response()->json(
app(\Imagekit\Imagekit::class)->getAuthenticationParameters()
));
// returns { token, expire, signature } — safe for the browser
Gate this route behind auth middleware and rate-limit it; a public signature endpoint lets anyone upload into your account.
Transformations belong in the URL, not at upload time. Upload the original at full quality and let w-, q-, f-auto do the work at delivery. This lets you change your responsive breakpoints later without re-processing a single asset.
Caching. The url() call is pure string concatenation — cheap, but if you render it in a loop over 50 products on every request, cache the resulting strings (Cache::remember("ik:{$path}:{$preset}", ...)) or memoise inside your wrapper. Also cache signed URLs slightly shorter than their expiry to avoid serving stale signatures at the boundary.
Local development and tests. The SDK makes real HTTP calls through its own transport, so Http::fake() will not intercept it. Bind a fake implementation of your own ImageKitUrl/uploader interface in testing/local:
$this->app->bind(ImageKitUrl::class, FakeImageKitUrl::class);
Otherwise your test suite will hit ImageKit, cost time, and flake.
TreeBuilder/ConfigurationInterface requirements. Pin it exactly if you insist on using it, and plan to fork.Symfony\Component\HttpKernel\Bundle\Bundle has no Laravel analogue. Any tutorial that says "install this bundle and add it to config/app.php" is wrong. Use the raw SDK.getAuthenticationParameters() output (token, expire, signature) is public-safe. private_key is not, and neither is calling uploadFile() from a browser context. Audit your JS bundle and any /api/config style debug endpoint.https://ik.imagekit.io/yourid) with no trailing slash. A trailing slash produces //path and silently 404s — ImageKit does not complain about malformed URLs, it just returns a broken image.widht-400 or qulity-80 is passed through verbatim and yields either the original image or a 400 on delivery. There is no client-side validation. Keep transformations in named constants or a preset map rather than string literals scattered across templates.? or # break the transformation URL construction. Sanitise or slugify filenames on upload — do not trust user-supplied names. useUniqueFileName: true also saves you from accidental overwrites.purgeCache() and accept the propagation delay. Never assume an upload is immediately visible.skip/limit loops; the SDK does not auto-page. Wrap bulk deletes in a job with a timeout well above the default.services.yaml, so you can override it in services_prod.yaml with your own decorated implementation. For logging/auditing, a Symfony Decorator around the client is cleaner than editing the bundle — and that same decorator pattern ports to Laravel as a wrapper class.fileId. Keep file_id and url in your own table and you can re-point at S3/CloudFront later with a single backfill job.How can I help you explore Laravel packages today?