Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Image Cache Laravel Package

bagisto/image-cache

Bagisto Image Cache is a Laravel package that caches Bagisto storefront images, generating optimized cached versions of product and category images to speed up page loads and reduce repeated image processing. Configure cache storage, image sizes, and cleanup for faster, lighter stores.

View on GitHub
Deep Wiki
Context7

Getting Started

Verify the stack before writing a line of integration code. This is a Bagisto-internal fork of intervention/imagecache, with zero stars and zero dependents — the only trustworthy docs are src/ and composer.json.

composer show intervention/image   # must report ^2.x
php -v                              # check against the fork's constraint

The cache layer depends on ImageManagerStatic and Intervention\Image\Response, both removed in Intervention Image v3. If you're on v3, stop — you're porting, not installing, and a ~150-line decorator you own is the better trade.

Install and confirm the provider. Auto-discovery may not fire because the fork often keeps the upstream namespace (Intervention\Image\ImageCacheServiceProvider) while the Composer package is bagisto/image-cache. Check composer.json's extra.laravel.providers; register manually if absent.

composer require bagisto/image-cache
php artisan vendor:publish --provider="Intervention\Image\ImageCacheServiceProvider"

Read the published config immediately. Expect config/imagecache.php with route, paths, templates, lifetime, and cache driver. If any of these are hardcoded rather than configurable, note it now — that fact determines whether roll-out is config or surgery later.

First use case: a category listing thumbnail. Highest fan-out, lowest risk, cheapest to measure.

use Intervention\Image\ImageManagerStatic as Image;

Image::cache(function ($image) {
    return $image->make(storage_path('app/public/product/'.$sku.'.jpg'))
                 ->resize(300, 300, function ($c) {
                     $c->aspectRatio();
                     $c->upsize();
                 });
}, 60, true); // 60 minutes, return Response object

The install is not the milestone. Verify the derivative exists under paths.cache, and that the second request does not touch GD/Imagick. That second check is the moment you actually know the package works.

Where to look first: composer.json (namespace, version constraints), src/ (key derivation, storage writes, route handler), then config/imagecache.php (what's actually tunable). Everything day-to-day lives in those three places.

Implementation Patterns

Wrap the entire transform chain inside the closure. The cache key derives from the closure's parameters, not from individual method calls. Chaining outside silently bypasses the cache:

// Wrong — resize() runs on every request
$cached = Image::cache(fn ($image) => $image->make($path), 60, true);
$cached->resize(300, 300)->save($out);

// Right — hash reflects the full transform
Image::cache(fn ($image) => $image->make($path)->resize(300, 300), 60, true);

Define derivative presets in templates, never inline dimensions. thumb, pdp_zoom, cart, og belong in config and get referenced by name. This is the package's one genuine architectural affordance: it converts "how many derivative sizes per SKU" from a scatter of magic numbers across Blade files into an explicit, reviewable config diff.

Choose the return shape deliberately. Third argument $returnObj = true gives an Image you can encode, stream, or feed into a larger composition. Default false returns a Response with cache headers — correct when you return directly from a controller, wrong for anything you want to post-process or hand to a view.

Use route-based delivery for public assets, closure mode for everything else. The /imagecache/{template}/{filename} endpoint lets CDNs and browsers cache derivatives independently of your PHP layer. Validate the paths allow-list before enabling it (see Gotchas). Closure mode is right for admin previews, queued jobs, and anything you need to return as an object.

Centralise behind a domain helper rather than calling Image::cache() in views. A single thin class gives you one seam for key versioning, placeholders, and instrumentation when you need them:

class ProductImage
{
    public function url(string $sku, string $template = 'thumb'): string
    {
        return Image::cache(
            fn ($image) => $image->make($this->sourcePath($sku))
                                 ->resize(...config("imagecache.templates.$template")),
            60,
            false
        )->getTargetPath();
    }
}

Warm the cache out-of-band after imports, deploys, and manual clears. A cold cache on a full catalog produces a regeneration storm. Queue a warm-up job that iterates your catalog for the two or three hottest templates only, and rate-limit it. Let everything else stay on-demand.

Test the key, not the pixels. Assert that two identical requests produce one file on disk; that changing a dimension produces two; and that replacing the source file produces whatever you decided it should. Without that last assertion you have no invalidation story and no confidence in roll-out.

Version the key when you need invalidate-on-replace. Feed a token (file mtime, updated_at, or a content hash) into the path or parameters. This is the one change to make before going live — see Gotchas.

Gotchas and Tips

Lifetime is in minutes, not seconds. This lineage defaults $lifetime to 5 (minutes) while Laravel's cache TTL is seconds. Mixing them produces a cache that expires five seconds after warm-up, which looks identical to a cache that isn't working at all — and wastes an hour of debugging on the wrong hypothesis.

Stale derivatives on image replacement is the worst failure mode. The key is source path + parameters, so swapping sku-123.jpg for a new photo does not change the key. Customers keep seeing the old product image until TTL expiry. Put a version token into the path or parameters — this is the single fix to make before launch.

Check src/ for file_put_contents vs. the Storage facade. file_put_contents means ephemeral container filesystems lose the cache on every deploy (recoverable, just cold) and multi-node deploys get per-node caches — hit rate falls roughly with node count. Neither breaks the app; both break your capacity assumptions. Fixing this via the Storage facade is a worthwhile early patch.

Nothing evicts. There is no cap on disk growth. Compute the number up front: derivatives × SKU count × average size, and write a scheduled find -mtime sweep or an artisan prune command yourself. Treat the cache directory as a disk-space budget line, not a free resource.

Cold-cache thundering herd has no mitigation. No locking, no atomic-write coordination, no request coalescing. Under a campaign launch, N concurrent requests for the same uncached derivative all regenerate it. Acceptable for low-traffic templates; pre-warm the ones that matter to the business.

Path traversal on the route endpoint is your responsibility to audit. The route mode takes a filename from the URL. Confirm the paths config is a strict allow-list and the filename is normalised. User-influenced cache keys are both traversal and cache-poisoning vectors, and with zero dependents you should assume nobody has audited this for you.

Silent 100% miss degradation is the real operational risk. A Laravel or Intervention upgrade can break ImageManagerStatic resolution without throwing — you just quietly stop hitting cache and start regenerating. Emit a hit/miss metric (a cache-directory stat, or a counter inside your helper) so a latency alert has a cause attached to it. This is the highest-value thing you add to this package.

Pin exactly and vendor the source. composer require bagisto/image-cache:1.0.x, commit the lock file, read the source when it breaks — there is no upstream to file an issue against. Budget an hour per quarter to re-check compatibility against Laravel and Intervention upgrades.

Know where it stops. It is not an optimizer: no WebP/AVIF Accept negotiation, no compression tuning, no CDN, no signed URLs, no srcset generation. Those are separate roadmap items. If you need them, the answer is edge transforms, not a patch to this package.

The escape hatch is cheap — keep it documented. The whole surface is a hash-to-file decorator. If the fork rots, a ~150-line ImageCache using the Storage facade, a version token in the key, and an eviction command takes half a day and removes the dependency entirely. Cost it now, treat it as the fallback plan you've already paid for, not a failure mode.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager