calliostro/last-fm-client-bundle
Symfony bundle that integrates the modern calliostro/lastfm-client with autowiring and Guzzle. Configure your API key, secret, session key, user agent, and optional rate limiter to access Last.fm music data and scrobbling.
Installation:
composer require calliostro/last-fm-client-bundle
Ensure calliostro/lastfm-client (v2.1.0+ recommended for automatic retry support) is also installed as a dependency.
Configuration: Publish the default config:
php bin/console config:dump-reference calliostro_lastfm
Update config/packages/calliostro_lastfm.yaml with your API key, rate-limiting settings, and retry behavior:
calliostro_lastfm:
api_key: '%env(LASTFM_API_KEY)%'
rate_limiter: true
limit: 1000 # requests/hour
auto_retry: true # default: true - retries on HTTP 429 / 503
max_retries: 3 # default: 3
First Use Case:
Inject Calliostro\LastFm\LastFmClient into a service/controller:
use Calliostro\LastFm\LastFmClient;
class ArtistController
{
public function __construct(private LastFmClient $lastFmClient) {}
public function show(string $artistName)
{
$info = $this->lastFmClient->getArtistInfo($artistName);
return response()->json($info);
}
}
public function __construct(
private LastFmClient $lastFmClient,
private RateLimiterInterface $rateLimiter
) {}
container->get(); use constructor injection or #[Inject] attribute (Symfony 6.4+).429) and server overload (503), with exponential backoff. Defaults: auto_retry: true, max_retries: 3.# config/packages/test/calliostro_lastfm.yaml
calliostro_lastfm:
auto_retry: false
Disable retries in tests or low-latency paths where a fallback path already exists.rate_limiter: true). The bundle integrates with symfony/rate-limiter:
calliostro_lastfm:
rate_limiter:
enabled: true
limit: 1000
interval: 3600 # seconds
$tracks = $lastFmClient->getRecentTracks('username');
$albums = $lastFmClient->getTopAlbums('artist', limit: 5);
try/catch with Calliostro\LastFm\Exception\LastFmException. Retries are exhausted before the exception surfaces, so catch only terminal failures:
try {
$lastFmClient->getArtistInfo('nonexistent_artist');
} catch (LastFmException $e) {
// Handle API errors after retries have been exhausted
}
LastFmClient in tests, and disable auto_retry in the test config to avoid slow, flaky suites:
$this->mock(LastFmClient::class)->shouldReceive('getArtistInfo')->andReturn($mockData);
$this->messageBus->dispatch(new FetchArtistInfo($artistName));
$cache = $this->cacheItemPool->getItem('lastfm_artist_' . $artistName);
if (!$cache->isHit()) {
$cache->set($lastFmClient->getArtistInfo($artistName));
$cache->expiresAfter(3600);
}
The v2.1.0 release introduces no breaking changes. If you are still on v1.x, migrate via the v2.0.0 notes below first.
Namespace Update:
Calliostro\LastFm\LastFmServiceCalliostro\LastFm\LastFmClient (capital F).Configuration:
lastfm key in config.calliostro_lastfm key.php bin/console config:dump-reference calliostro_lastfm to regenerate config.Dependency:
calliostro/php-lastfm-api with calliostro/lastfm-client (v2.1.0+ for retry support).Migration:
auto_retry: true means a failing request can take up to max_retries × backoff seconds before throwing. Keep this in mind for synchronous user-facing endpoints — move to Messenger or reduce max_retries there.auto_retry.LastFmClient or via the BeforeRequest/AfterResponse events — a 3-retry request is a signal that your rate limiter needs tuning.bin/console debug:container symfony_rate_limiter
Customize limits per endpoint by overriding LastFmClient or using middleware.max_retries: 1 and auto_retry: false to confirm whether failures are transient (429/503) or genuine (invalid artist, auth).calliostro_lastfm:
debug: true
Logs will include raw API responses for troubleshooting (including each retry attempt).phpstan.neon.dist (Level 8) ships with the package — mirror it in your project if you extend LastFmClient.$results = $lastFmClient->batch([
'getArtistInfo' => ['artist' => 'Arctic Monkeys'],
'getTopTracks' => ['artist' => 'Arctic Monkeys', 'period' => '7day'],
]);
$cacheKey = 'lastfm_top_artists_' . $period;
if (!$cached = cache()->get($cacheKey)) {
$cached = $lastFmClient->getTopArtists($period);
cache()->put($cacheKey, $cached, now()->addHours(1));
}
Cache is still cheaper than a successful retry — layer caching in front of retries.Custom Clients:
class CustomLastFmClient extends LastFmClient
{
public function getArtistTopFans(string $artistName, int $limit = 10): array
{
return $this->call('artist.getTopFans', [
'artist' => $artistName,
'limit' => $limit,
]);
}
}
Register as a service:
services:
App\Service\CustomLastFmClient:
arguments:
$client: '@calliostro_lastfm.client'
Middleware:
$lastFmClient->getMiddlewareStack()->add(
new AddUserAgentMiddleware('MyApp/1.0')
);
Event Listeners:
$dispatcher->addListener(LastFmClientEvents::BEFORE_REQUEST, function (BeforeRequestEvent $event) {
// Log request details (fires once per attempt, including retries)
});
How can I help you explore Laravel packages today?