Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 50 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,32 @@

> _Drop-in Symfony bundle for currency conversion. Multi-provider exchange rates with fallback, caching, and Symfony Cache integration. Maintained since 2014._

<table>
<tr>
<td width="220" align="center">
<a href="https://www.fastforex.io" target="_blank" rel="noopener">
<img src="https://console.fastforex.io/img/fastforex/logo-bk-1k.svg" width="180px" alt="fastFOREX"/>
</a>
</td>
<td>
<strong>Sponsored by <a href="https://www.fastforex.io" target="_blank" rel="noopener">fastFOREX</a>.</strong> Real-time JSON API, 160+ currencies, 55+ years of history, 500+ cryptocurrencies. <strong>Free tier</strong>; paid plans from $18/month.
<a href="https://www.fastforex.io" target="_blank" rel="noopener"><strong>→ Get a free fastFOREX API key</strong></a>
</td>
</tr>
</table>

**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 a drop-in package for **Symfony currency conversion**. Install it, configure providers in `config/packages/florianv_swap.yaml`, and pull 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.

## 💡 What is Symfony Swap?

- Symfony Swap is the Symfony integration of [Swap](https://github.com/florianv/swap), the PHP currency conversion library.
- It registers a `florianv_swap.swap` service in the container (`Swap\Swap` class).
- The Symfony integration of [Swap](https://github.com/florianv/swap), the PHP currency conversion library.
- Registers a `florianv_swap.swap` service in the container (`Swap\Swap` class).
- 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).

## 🎯 When should you use Symfony Swap?

- 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](https://github.com/florianv/swap) separately. It is pulled in as a dependency, and Symfony Swap exposes it through Symfony's container and cache.

## 🧠 Why Symfony Swap and not raw Swap?

Using [Swap](https://github.com/florianv/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.php` and you are set.
- **Symfony Cache integration.** Choose `array`, `apcu`, `filesystem`, or any PSR-16 service ID under `cache.type`.
- **Container service.** `florianv_swap.swap` is ready to inject from any controller, service, or command.
- **Configurable.** `config/packages/florianv_swap.yaml` exposes 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](https://github.com/florianv/swap) directly.

## 📦 Installation

Symfony Swap requires PHP 8.2 or newer and Symfony 6.4, 7, or 8.
Expand All @@ -56,22 +51,22 @@ return [
];
```

Skip to [Quickstart](#-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](Resources/doc/index.md) for alternatives._

## ⚡ Quickstart

Configure at least one provider in `config/packages/florianv_swap.yaml`. The European Central Bank works without an API key:
Configure providers in `config/packages/florianv_swap.yaml`. The recommended primary provider is **[fastFOREX](https://www.fastforex.io)** (the project's sponsor): a real-time JSON API behind a single `api_key`, [free tier available](https://www.fastforex.io).

```yaml
# config/packages/florianv_swap.yaml
florianv_swap:
cache:
ttl: 3600
type: filesystem
providers:
fastforex:
api_key: '%env(SWAP_FASTFOREX_KEY)%'
priority: 10 # tried first
european_central_bank:
priority: 0
priority: 0 # free fallback for EUR-base pairs
```

Inject the service:
Expand All @@ -95,7 +90,7 @@ final class CurrencyController
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'
'provider' => $rate->getProviderName(), // 'fastforex'
];
}
}
Expand All @@ -108,26 +103,21 @@ $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:
Providers 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.

<details>
<summary>No API key? Start with the European Central Bank (free, EUR-base only).</summary>

```yaml
# 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 pairs
priority: 0
```

Providers 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.
The European Central Bank publishes EUR-base rates with daily granularity. For non-EUR base pairs, more frequent updates, or a wider currency list, switch to fastFOREX or another commercial provider.
</details>

## 💾 Caching

Expand All @@ -150,7 +140,18 @@ florianv_swap:
type: my_psr16_cache_service
```

Per-query overrides are documented in the [full documentation](Resources/doc/index.md#-caching).
Per-query overrides are documented in the [full documentation](Resources/doc/index.md#-per-query-options).

## 📊 Providers

Symfony Swap supports the 30 exchange rate providers from the underlying [Swap](https://github.com/florianv/swap) library. The recommended starting point for new projects is **[fastFOREX](https://www.fastforex.io)** (`fastforex`), the project's sponsor: live rates across 160+ fiat currencies and 500+ cryptocurrencies, with up to 55 years of history.

The full per-provider configuration reference (option name, optional flags, capabilities) is in the [documentation](Resources/doc/index.md#provider-configuration).

## 🎯 When should you use Symfony Swap?

- 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](https://github.com/florianv/swap) separately. It is pulled in as a dependency, and Symfony Swap exposes it through Symfony's container and cache.

## 🛠 Common use cases

Expand All @@ -164,37 +165,16 @@ Per-query overrides are documented in the [full documentation](Resources/doc/ind

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).
- [**Swap**](https://github.com/florianv/swap). The easy-to-use, high-level API for plain PHP.
- [**Exchanger**](https://github.com/florianv/exchanger). Lower-level, more granular alternative; direct access to provider implementations.
- [**Laravel Swap**](https://github.com/florianv/laravel-swap). Laravel application of Swap.
- [**Symfony Swap**](https://github.com/florianv/symfony-swap). Symfony integration of Swap (this package).

All four packages are MIT-licensed and require PHP 8.2 or newer.

## 📚 Documentation

The full documentation, with the per-provider configuration reference, custom service registration, cache types, and FAQ, is in [Resources/doc/index.md](Resources/doc/index.md). The full provider list with capabilities is in the [Swap README](https://github.com/florianv/swap#-providers).

## 🧩 Related packages

The Swap ecosystem:

- [**Swap**](https://github.com/florianv/swap): easy-to-use PHP currency conversion library.
- [**Exchanger**](https://github.com/florianv/exchanger): exchange rate provider layer.
- [**Laravel Swap**](https://github.com/florianv/laravel-swap): Laravel application of Swap.
- [**Symfony Swap**](https://github.com/florianv/symfony-swap): Symfony integration of Swap (this package).

## 🤝 Sponsorship

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](https://github.com/florianv).
The full documentation, with the per-provider configuration reference, custom service registration, cache types, and FAQ, is in [Resources/doc/index.md](Resources/doc/index.md).

## 🙌 Contributing

Expand Down
63 changes: 34 additions & 29 deletions Resources/doc/index.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
# Documentation

## 💡 What is Symfony Swap?

- Symfony Swap is the Symfony integration of [Swap](https://github.com/florianv/swap), the PHP currency conversion library.
- It registers a `florianv_swap.swap` service in the container (`Swap\Swap` class).
- 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).

For the wider ecosystem (Swap, Exchanger, Laravel Swap), see the [README](../../README.md).

## 🎯 When should you use Symfony Swap?

- 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](https://github.com/florianv/swap) separately. It is pulled in as a dependency, and Symfony Swap exposes it through Symfony's container and cache.

## 🧠 Why Symfony Swap and not raw Swap?

- **Drop-in.** Add the bundle to `config/bundles.php` and you are set.
- **Symfony Cache integration.** Choose `array`, `apcu`, `filesystem`, or any PSR-16 service ID under `cache.type`.
- **Container service.** `florianv_swap.swap` is ready to inject from any controller, service, or command.
- **Configurable.** `config/packages/florianv_swap.yaml` exposes providers, options, and the cache.
- **Priority-ordered providers.** Each provider has a `priority`; the bundle sorts them (higher priority tried first), unlike Swap and Laravel Swap, which use declaration order.
<table>
<tr>
<td width="220" align="center">
<a href="https://www.fastforex.io" target="_blank" rel="noopener">
<img src="https://console.fastforex.io/img/fastforex/logo-bk-1k.svg" width="180px" alt="fastFOREX"/>
</a>
</td>
<td>
<strong>Sponsored by <a href="https://www.fastforex.io" target="_blank" rel="noopener">fastFOREX</a>.</strong> Real-time JSON API, 160+ currencies, 55+ years of history, 500+ cryptocurrencies. <strong>Free tier</strong>; paid plans from $18/month.
<a href="https://www.fastforex.io" target="_blank" rel="noopener"><strong>→ Get a free fastFOREX API key</strong></a>
</td>
</tr>
</table>

This is the technical reference for Symfony Swap. For the project overview and ecosystem (Swap, Exchanger, Laravel Swap), see the [README](../../README.md).

## Index

Expand Down Expand Up @@ -73,22 +66,27 @@ Create the configuration file at `config/packages/florianv_swap.yaml` (see [Conf

### Config tree

A typical config pins fastFOREX (the project's sponsor) as the primary provider, with the European Central Bank as a free fallback:

```yaml
# config/packages/florianv_swap.yaml
florianv_swap:
cache:
ttl: 3600
type: filesystem
providers:
fastforex:
api_key: '%env(SWAP_FASTFOREX_KEY)%'
priority: 10 # tried first
european_central_bank:
priority: 0
priority: 0 # free fallback for EUR-base pairs
```

At least one provider is required. Each provider accepts a `priority` integer (higher priority is tried first) and the provider-specific options listed below.

### Provider configuration

Public providers (central banks, national banks, `cryptonator`, `webservicex`) need only a `priority`:
Public providers (central banks, national banks) need only a `priority`:

```yaml
florianv_swap:
Expand All @@ -99,10 +97,12 @@ florianv_swap:
priority: 0
```

Commercial providers require an API key. The option name varies by provider:
Commercial providers require an API key. The option name varies by provider. The project's sponsor [fastFOREX](https://www.fastforex.io) (`fastforex`) is the recommended starting point.

| Identifier | Required option | Optional flags |
| -------------------------------- | --------------- | --------------------- |
| ⭐ **`fastforex`** | **`api_key`** | |
| | | |
| `abstract_api` | `api_key` | |
| `apilayer_currency_data` | `api_key` | |
| `apilayer_exchange_rates_data` | `api_key` | |
Expand All @@ -118,11 +118,16 @@ Commercial providers require an API key. The option name varies by provider:
| `xchangeapi` | `api-key` | (note the hyphen) |
| `xignite` | `token` | |

Example:
> Note: `cryptonator`, `exchangeratehost` and `webservicex` are commercial upstream services but the current Exchanger wrapper does not enforce any option for them. They can be added with only a `priority`.

Example chaining fastFOREX as the primary provider with a couple of fallbacks:

```yaml
florianv_swap:
providers:
fastforex:
api_key: '%env(SWAP_FASTFOREX_KEY)%'
priority: 20
apilayer_fixer:
api_key: '%env(SWAP_FIXER_KEY)%'
priority: 10
Expand Down Expand Up @@ -226,7 +231,7 @@ $rate->getCurrencyPair(); // Exchanger\CurrencyPair
$rate->getProviderName(); // string, the identifier that returned the rate
```

`getProviderName()` is useful when several providers are configured: the returned value is the identifier of the provider that actually answered, for example `european_central_bank`.
`getProviderName()` is useful when several providers are configured: the returned value is the identifier of the provider that actually answered, for example `fastforex`.

## 💾 Per-query options

Expand Down Expand Up @@ -354,7 +359,7 @@ Swap throws an `Exchanger\Exception\ChainException`. Calling `$exception->getExc

#### Can I use Symfony Swap without an API key?

Yes. The European Central Bank, the national banks, `cryptonator`, and `webservicex` do not require an API key. See the [Swap README's Providers table](https://github.com/florianv/swap#-providers) for the full list.
Yes. The European Central Bank and the national banks listed in the [Provider configuration](#provider-configuration) section require no key. A few commercial providers (`cryptonator`, `exchangeratehost`, `webservicex`) can also currently be used without one, since the Exchanger wrapper does not yet enforce an option for them.

#### How does Symfony Swap relate to Swap?

Expand All @@ -374,4 +379,4 @@ Implement `Exchanger\Contract\ExchangeRateService` (or extend `HttpService` / `S

#### Where is the full provider list with capabilities?

In the [Swap README's Providers table](https://github.com/florianv/swap#-providers). It lists every supported identifier with its base currency, quote currency, and historical support.
In the [Provider configuration](#provider-configuration) section above (option reference) and the [Swap README's Providers table](https://github.com/florianv/swap#-providers) (base currency, quote currency, historical support).
Loading