greendot/image-puller-client
Laravel/PHP client for the Greendot Image Puller service, providing a simple integration to pull and retrieve images from a centralized image service. Configure endpoints and credentials, then request images directly from your Laravel application.
KORandi/greendot-image-puller is a small, single-purpose Laravel package: it pulls images from a remote Green Dot source and writes them through Laravel's filesystem layer. It is a convenience wrapper, not a framework — expect a thin API surface (one or two services plus a config file) rather than a full pipeline.
Steps to first value:
composer require korandi/greendot-image-puller — pin the constraint (^1.1) rather than dev-main; this package moves in patch releases with little ceremony.php artisan vendor:publish --provider="KORandi\\GreendotImagePuller\\...ServiceProvider" (or --tag= if a tag is registered — check the provider's boot() for the actual tag name; the README is thin here)..env (source endpoint/credentials and the target disk name), then php artisan config:clear.app(...) or the facade, if one is registered) and pull one asset to a local disk you can eyeball.Where to look first, in order: the published config/ file (it is the de facto API documentation for this package), the package's service provider (what is bound, whether a facade alias exists), then the puller class itself. Skip the README until you have those three — for a package this size the source is faster than the docs.
The canonical first use case: a scheduled artisan command that syncs a set of product/catalog images into storage/app/public/... on a nightly basis.
Wrap the puller in a job, not a loop. The puller likely does synchronous HTTP per image. For anything beyond a handful, dispatch one queued job per image so you get retries, backoff, and per-item failure isolation for free:
foreach ($imageIds as $id) {
PullImageJob::dispatch($id)->onQueue('images');
}
Set $tries = 3 and a backoff() on the job; remote image hosts are flaky in ways your app shouldn't inherit.
Config-driven, not hardcoded. Put the target disk, path prefix, and any source credentials in config/greendot-image-puller.php and reference them via config(). This is the main extension point the package gives you — use it rather than passing disks around in call sites, otherwise a disk migration becomes a grep exercise.
Idempotency by content, not by name. Derive the stored filename from a hash of the image ID or the response body, and check existence before pulling. Remote sources frequently re-serve identical bytes under rotating URLs; hashing saves bandwidth and keeps git-style diffs of your storage bucket quiet.
Post-processing via events, not inside the pull path. If the package fires an event on a successful pull (check the source), hang thumbnail generation / WebP conversion off a listener. If it doesn't, wrap your own thin service that calls the puller and then dispatches your own ImagePulled event. Either way, keep resizing out of the loop that does network I/O.
Pair with a command for ops. A php artisan images:pull {--since=} command wrapping the same service lets you backfill on demand and gives your scheduler something to call. Register it in routes/console.php (Laravel 11+) or Kernel::schedule().
Storage disks are the integration seam. Point the package at an S3-compatible disk in production and local in tests; use Storage::fake() in feature tests and assert assertExists() on the expected path. That's the cheapest way to test a package whose internals you don't control.
git diff v1.1.1..v1.1.2. A vaguely-titled first-contribution PR merged into a package that runs inside your app is worth thirty seconds of scrutiny — check that it touches only what it claims."^1.1" is safer than "*" or dev-main; you want the ability to hold a version.php artisan config:clear — a cached config is the single most common "why is it pulling to the wrong disk" cause in packages of this shape.Content-Type over the URL suffix when choosing an extension; sources routinely serve .jpg URLs returning WebP or HTML error pages. Guard against a 200-with-HTML that ends up as a "successful" pull.Storage::disk()->setVisibility()), or you'll get 403s that look like a package bug.ab/cd/abcdef...jpg).try/catch, log failures with the image ID and HTTP status, and let the queue's failed_jobs table be your audit trail. Don't rely on the package to report partial batch failures.Storage::fake() tests, and verify the public disk still resolves paths as before. If the diff is cosmetic, stay on v1.1.2 for hygiene; if it's unclear, v1.1.1 remains a fine target.How can I help you explore Laravel packages today?