kami/icobench-bundle
A lightweight Kami bundle for integrating ICOBench into your PHP application. It provides a simple wrapper for fetching and displaying ICO listings, ratings, and related details, with straightforward configuration that makes it easy to surface ICOBench data on your site or dashboard.
The first thing to internalize is that this is a Symfony bundle, not a Laravel package. There is no IcoBenchServiceProvider, no facade, and no config/icobench.php — it registers a service into Symfony's DI container via a Bundle class plus DependencyInjection/*Extension.php. In a Laravel app you cannot composer require kami/icobench-bundle and have it "just work"; it pulls in symfony/framework-bundle expectations.
Practical starting path for a Laravel developer:
DependencyInjection/Configuration.php and DependencyInjection/KamiIcobenchExtension.php in the repo — they show exactly what config keys it exposes (typically a public API key and possibly a private key) and how it constructs the underlying icobench/icobench-client. That's the whole value of the bundle: a reference wiring.composer require icobench/icobench-client. That library is framework-agnostic and is the thing that actually talks to api.icobench.com/v1.AppServiceProvider as a singleton using config from .env, then wrap it in your own thin IcoBenchService so your code never depends on the raw client.First use case to validate the integration: fetch a single ICO by ID (/ico/{id}) and dump the payload. If that returns the expected array, the wiring is correct; everything else (search, trending, ratings, people) is the same shape.
Singleton binding with config — mirror the bundle's extension logic in AppServiceProvider:
$this->app->singleton(\Icobench\Api\Client::class, function () {
return new \Icobench\Api\Client(
config('services.icobench.public_key'),
config('services.icobench.private_key'), // if the client requires it
);
});
Put the keys in config/services.php reading from ICOBENCH_PUBLIC_KEY / ICOBENCH_PRIVATE_KEY in .env, matching the bundle's config keys so porting is trivial.
Repository/service wrapper — never call the client from controllers. Create App\Services\IcoBenchService with intent-revealing methods (findIco($id), searchIcos(array $filters), trending()), map the raw array into a DTO or Eloquent model, and let the wrapper own retries/caching.
Cache everything. The client is a naive HTTP wrapper; without caching you'll hammer the API and pay latency on every request. Cache::remember("icobench.ico.{$id}", now()->addDay(), fn () => $this->client->getIco($id)). Invalidate on a scheduled sync, not on read.
Scheduled ingestion, not live reads. The cleanest production pattern is an Artisan command (icobench:sync) that pulls a list of IDs, upserts into a local icos table, and stores the raw JSON in a payload column. Your UI then reads from your DB — the API becomes a batch source, not a request-time dependency. This also insulates you from the API going away.
Testing. Bind a fake implementation of your IcoBenchService in the container ($this->app->instance(...)) rather than mocking the vendor client. For contract tests, record real responses as fixtures and assert your DTO mapping against them.
FrameworkBundle/DependencyInjection. Treat it as documentation and a config template, not a dependency. Adding it will bloat composer.json and may conflict with Laravel's Symfony component versions.api.icobench.com endpoints are not a reliable live data source. Plan for this: expect connection failures, 404s, or stale last-known data. Your error handling must degrade gracefully (return cached/DB values, log and continue) rather than throwing 500s into a request path.kami_icobench:); if you're copying its config, match the key names it reads — mismatches fail silently as null credentials and surface as unexpected 401s from the API.team, milestones, nulls). Always normalize with defensive accessors ($data['rating']['overall'] ?? null) instead of assuming keys exist.usleep or Http::retry-style backoff, and checkpoint progress so a mid-run failure doesn't restart from zero.Configuration-style array in config/services.php, a singleton binding, and a facade over your own service — never a facade over the vendor client directly.How can I help you explore Laravel packages today?