Drop-in Symfony bundle for currency conversion. Multi-provider exchange rates with fallback, caching, and Symfony Cache integration. Maintained since 2014.
Install the bundle, drop a florianv_swap.yaml in config/packages/, and the florianv_swap.swap service is ready to inject. No service container plumbing, no boilerplate.
Symfony Swap is a drop-in package for Symfony currency conversion. Install it, configure providers in config/packages/florianv_swap.yaml, and pull Symfony exchange rates from multiple providers in one call. The bundle integrates with Symfony Cache out of the box and supports Symfony 6.4 / 7 / 8. Used in real-world Symfony applications since 2014.
- Symfony Swap is the Symfony integration of Swap, the PHP currency conversion library.
- It registers a
florianv_swap.swapservice in the container (Swap\Swapclass). - Configuration lives in
config/packages/florianv_swap.yaml. - Caching uses Symfony Cache (
array,apcu,filesystem, or any PSR-16 service ID). - Providers are tried in priority order (higher priority first).
- Use Symfony Swap when you need exchange rates inside a Symfony application: localized prices, invoice totals, multi-currency reporting, historical FX data.
- You do not need to install Swap separately. It is pulled in as a dependency, and Symfony Swap exposes it through Symfony's container and cache.
Using Swap directly inside a Symfony app means three pieces of plumbing on every project: registering the builder and the Swap service yourself, wiring Symfony Cache to the PSR-16 contract, and configuring providers in PHP rather than in the container. Doable, but boilerplate every project pays for.
Symfony Swap does this for you:
- Drop-in. Add the bundle to
config/bundles.phpand you are set. - Symfony Cache integration. Choose
array,apcu,filesystem, or any PSR-16 service ID undercache.type. - Container service.
florianv_swap.swapis ready to inject from any controller, service, or command. - Configurable.
config/packages/florianv_swap.yamlexposes providers, options, and the cache. - Priority-ordered providers. Each provider has a
priority; the bundle sorts them (higher priority tried first).
If you are not on Symfony, use Swap directly.
Symfony Swap requires PHP 8.2 or newer and Symfony 6.4, 7, or 8.
composer require florianv/swap-bundle symfony/http-client nyholm/psr7Register the bundle in config/bundles.php (Symfony Flex skips this step if a recipe applies):
// config/bundles.php
return [
// ...
Florianv\SwapBundle\FlorianvSwapBundle::class => ['all' => true],
];Skip to Quickstart.
Optional: any PSR-18 HTTP client paired with a PSR-17 factory works. If your app already uses Guzzle, swap symfony/http-client for php-http/guzzle7-adapter. See the documentation for alternatives.
Configure at least one provider in config/packages/florianv_swap.yaml. The European Central Bank works without an API key:
# config/packages/florianv_swap.yaml
florianv_swap:
providers:
european_central_bank:
priority: 0Inject the service:
use Swap\Swap;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
final class CurrencyController
{
public function __construct(
#[Autowire(service: 'florianv_swap.swap')]
private readonly Swap $swap,
) {}
public function rate(): array
{
// EUR β USD exchange rate
$rate = $this->swap->latest('EUR/USD');
return [
'value' => $rate->getValue(), // e.g. 1.0823
'date' => $rate->getDate()->format('Y-m-d'), // e.g. 2026-04-29
'provider' => $rate->getProviderName(), // 'european_central_bank'
];
}
}Or fetch directly from the container:
$swap = $container->get('florianv_swap.swap');
$rate = $swap->latest('EUR/USD');Add commercial providers under providers: and they will be chained with the configured priority order:
# config/packages/florianv_swap.yaml
florianv_swap:
cache:
ttl: 3600
type: filesystem
providers:
apilayer_fixer:
api_key: '%env(SWAP_FIXER_KEY)%'
priority: 10 # tried first
open_exchange_rates:
app_id: '%env(SWAP_OER_APP_ID)%'
priority: 5 # tried second
european_central_bank:
priority: 0 # free fallback for EUR-base pairsProviders are tried in priority order (higher first). If a provider does not support the requested currency pair, it is skipped silently. If a provider throws an error, the next provider is tried. If every provider fails, a ChainException is thrown with all collected errors.
Set cache in config/packages/florianv_swap.yaml:
# config/packages/florianv_swap.yaml
florianv_swap:
cache:
ttl: 3600
type: filesystem # array, apcu, filesystem, or a PSR-16 service IDFor a custom cache, point type at any service implementing Psr\SimpleCache\CacheInterface:
florianv_swap:
cache:
ttl: 3600
type: my_psr16_cache_servicePer-query overrides are documented in the full documentation.
- Display localized prices in multi-currency Symfony storefronts.
- Compute invoice totals across currencies in a Symfony API.
- Reconcile multi-currency ledgers using historical rates.
- Power internal FX dashboards with rate history.
- Build currency conversion infrastructure for Symfony-based fintech and ERP applications.
The Swap ecosystem is a layered toolkit for currency conversion in PHP:
- Swap. The easy-to-use, high-level API for plain PHP.
- Exchanger. Lower-level, more granular alternative; direct access to provider implementations.
- Laravel Swap. Laravel application of Swap.
- Symfony Swap. Symfony integration of Swap (this package).
All four packages are MIT-licensed and require PHP 8.2 or newer.
The full documentation, with the per-provider configuration reference, custom service registration, cache types, and FAQ, is in Resources/doc/index.md. The full provider list with capabilities is in the Swap README.
The Swap ecosystem:
- Swap: easy-to-use PHP currency conversion library.
- Exchanger: exchange rate provider layer.
- Laravel Swap: Laravel application of Swap.
- Symfony Swap: Symfony integration of Swap (this package).
The Swap ecosystem is open to selected sponsorships from exchange rate API providers and financial infrastructure companies.
Sponsorship can include:
- Documentation visibility
- Integration examples
- Ecosystem-level visibility across Swap, Exchanger, Laravel Swap, and Symfony Swap
For inquiries, contact the maintainer via GitHub.
Issues and pull requests are welcome. Please see the existing issues before opening a new one.
The MIT License (MIT). Please see LICENSE for more information.