PHPackages                             benjaminmal/exchangeratehost-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. benjaminmal/exchangeratehost-bundle

ActiveSymfony-bundle[API Development](/categories/api)

benjaminmal/exchangeratehost-bundle
===================================

ExchangeRate.host API bundle for Symfony

v1.0.0-beta6(3y ago)07[1 issues](https://github.com/benjaminmal/exchangeratehost-bundle/issues)MITPHPPHP ^8.1CI failing

Since Apr 27Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/benjaminmal/exchangeratehost-bundle)[ Packagist](https://packagist.org/packages/benjaminmal/exchangeratehost-bundle)[ RSS](/packages/benjaminmal-exchangeratehost-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (6)Dependencies (29)Versions (15)Used By (0)

[![Continuous integration](https://github.com/benjaminmal/exchangeratehost-bundle/actions/workflows/ci.yaml/badge.svg)](https://github.com/benjaminmal/exchangeratehost-bundle/actions/workflows/ci.yaml)

exchangerate.host bundle
========================

[](#exchangeratehost-bundle)

This bundle allows you to query the great (and free!) [exchangerate.host](https://exchangerate.host) API in a [Symfony](https://symfony.com/) app with ease. It supports [PSR-7](https://www.php-fig.org/psr/psr-7/), [PSR-17](https://www.php-fig.org/psr/psr-17/), [PSR-18](https://www.php-fig.org/psr/psr-18/) so you have full control of your dependencies! It uses also the [Symfony Cache](https://symfony.com/doc/current/cache.html).

⚠️ This bundle is unofficial. I'm not related to [exchangerate.host](https://exchangerate.host).

Summary
-------

[](#summary)

- [Requirements](#requirements)
- [Installation](#installation)
- [Getting started](#getting-started)
    - [Config](#config)
    - [Use the API client](#use-the-api-client)
- [Cache](#cache)
    - [Customizing the cache](#customizing-the-cache)
    - [Clearing the cache](#clearing-the-cache)
- [What's more](#whats-more)

Requirements
------------

[](#requirements)

- PHP ^8.1
- Symfony ^6.2

Installation
------------

[](#installation)

### Composer

[](#composer)

```
$ composer require benjaminmal/exchangeratehost-bundle
```

### PSRs

[](#psrs)

In order to use this bundle, you need to set [PSR-17](https://www.php-fig.org/psr/psr-17/) message factories and a [PSR-18](https://www.php-fig.org/psr/psr-18/) HTTP client.

If you already have PSR-17 factories and PSR-18 HTTP client in your services you're done! Otherwise, you can use these great libraries:

```
$ composer require nyholm/psr7 symfony/http-client
```

If you're using [Symfony Flex](https://symfony.com/doc/current/quick_tour/flex_recipes.html) and the recommended librairies, you're all set!

Otherwise, enable the bundle by adding it to the list of registered bundles in the `config/bundles.php` file of your project:

```
// config/bundles.php

return [
    // ...
    Benjaminmal\ExchangeRateHostBundle\ExchangeRateHostBundle::class => ['all' => true],
];
```

Then add your implementation of [PSR-17](https://www.php-fig.org/psr/psr-17/) and [PSR-18](https://www.php-fig.org/psr/psr-18/) services if they don't exist yet:

```
# services.yaml
services:
    Psr\Http\Message\RequestFactoryInterface: '@your_custom_psr17_request_factory'
    Psr\Http\Message\UriFactoryInterface: '@your_custom_psr17_uri_factory'
    Psr\Http\Client\ClientInterface: '@your_custom_psr18_http_client'
```

Getting started
---------------

[](#getting-started)

### Config

[](#config)

The following file is optional but here are the default config values:

```
# exchangerate_host.yaml
exchangerate_host:
    cache:
        # Enabled / disable caching. Optional. Disabling it is not recommended
        # (HTTP request can be long, rate limit could be hit).
        enabled: true

        # Set the cache pool. Optional. Set it to false if you don't want to use
        # this specific cache pool. Default to "exchangeratehost.cache", which extends the default "app.cache".
        pools:
            latest_rates: 'exchangeratehost.cache'
            convert_currency: 'exchangeratehost.cache'
            historical_rates: 'exchangeratehost.cache'
            timeseries_rates: 'exchangeratehost.cache'
            fluctuation_data: 'exchangeratehost.cache'
            supported_currencies: 'exchangeratehost.cache'
            eu_vat_rates: 'exchangeratehost.cache'
```

### Use the API client

[](#use-the-api-client)

The API client is available through autowiring via `ExchangeRateHostClientInterface` or via `benjaminmal.exchangerate_host_bundle.client` service id:

```
namespace App\Service;

use Benjaminmal\ExchangeRateHostBundle\Client\ExchangeRateHostClientInterface;
use Benjaminmal\ExchangeRateHostBundle\Model\Option\ConvertCurrencyOption;
use Benjaminmal\ExchangeRateHostBundle\Model\Option\EuVatRatesOption;
use Benjaminmal\ExchangeRateHostBundle\Model\Option\FluctuationDataOption;
use Benjaminmal\ExchangeRateHostBundle\Model\Option\HistoricalRatesOption;
use Benjaminmal\ExchangeRateHostBundle\Model\Option\LatestRatesOption;
use Benjaminmal\ExchangeRateHostBundle\Model\Option\SupportedSymbolsOption;
use Benjaminmal\ExchangeRateHostBundle\Model\Option\TimeSeriesDataOption;
use Benjaminmal\ExchangeRateHostBundle\Model\Output\FluctuationData;
use Benjaminmal\ExchangeRateHostBundle\Model\Output\SymbolData;
use Benjaminmal\ExchangeRateHostBundle\Model\Output\VatRates;

class MyService
{
    public function __construct(private readonly ExchangeRateHostClientInterface $client)
    {
    }

    public function getLatestRates()
    {
        // Get the latest rates
        $rates = $this->client->getLatestRates(
            options: new LatestRatesOption( // Optional
                base: 'EUR',
                symbols: ['USD', 'CZK'],
                amount: 1200,
                places: 2,
                source: 'ecb',
                callback: 'functionName',
            ),
        );

        /**
         * @var string $currency
         * @var float $rate
         */
        foreach ($rates as $currency => $rate) {
            // ...
        }

        // ...
    }

    public function convertCurrency(): int
    {
        // Convert price
        /** @var int $newAmount */
        $newAmount = $this->client->convertCurrency(
            fromCurrency: 'EUR', // Required
            toCurrency: 'USD', // Required
            amount: 1300, // Required
            options: new ConvertCurrencyOption(), // Optional
        );

        // ...
    }

    public function getHistoricalRates()
    {
        // Get rates from a specific day
        $rates = $this->client->getHistoricalRates(
            date: new \DateTimeImmutable('-10days'), // Required, will be converted in the url with the format 'Y-m-d'
            options: new HistoricalRatesOption(), // Optional
        );

        /**
         * @var string $currency
         * @var float $rate
         */
        foreach ($rates as $currency => $rate) {
            // ...
        }

        // ...
    }

    public function getTimeSeriesRates()
    {
        // Get the rates between 2 dates
        $rates = $this->client->getTimeSeriesRates(
            startDate: new \DateTimeImmutable('-89days'), // Required
            endDate: new \DateTimeImmutable('-10days'), // Required
            options: new TimeSeriesDataOption(), // Optional
        );

        /**
         * @var $date string formatted as 'Y-m-d'
         * @var $datum iterable
         */
        foreach ($rates as $date => $datum) {
            foreach ($datum as $currency => $rate) {
                // ...
            }
        }

        // ...
    }

    public function getFluctuationData()
    {
        // Get the fluctuation data between 2 dates
        $data = $this->client->getFluctuationData(
            startDate: new \DateTimeImmutable('-89days'), // Required
            endDate: new \DateTimeImmutable('-10days'), // Required
            options: new FluctuationDataOption(), // Optional
        );

        /**
         * @var FluctuationData $fluctuationData
         */
        foreach ($data as $currency => $fluctuationData) {
            echo $fluctuationData->startRate;
            echo $fluctuationData->endRate;
            echo $fluctuationData->change;
            echo $fluctuationData->changePct;
        }

        // ...
    }

    public function getCurrencies()
    {
        // Get the supported currencies
        $supportedCurrencies = $this->client->getSupportedCurrencies(
            options: new SupportedSymbolsOption(), // Optional
        );

        /**
         * @var SymbolData $supportedCurrency
         */
        foreach ($supportedCurrencies as $currency => $supportedCurrency) {
            echo $supportedCurrency->code;
            echo $supportedCurrency->description;
        }

        // ...
    }

    public function getEurVatRates()
    {
        // Get EU VAT rates
        $rates = $this->client->getEuVatRates(
            options: new EuVatRatesOption(), // Optional
        );

        /**
         * @var VatRates $vatRate
         */
        foreach ($rates as $countryCode => $vatRate) {
            echo $vatRate->countryName;
            echo $vatRate->standardRate;
            echo implode(', ', $vatRate->parkingRates);
            echo implode(', ', $vatRate->reducedRates);
            echo implode(', ', $vatRate->superReducedRates);
        }
    }
}
```

Cache
-----

[](#cache)

### Customizing the cache

[](#customizing-the-cache)

You want to change the default cache behavior? Let's do that:

```
# exchangerate_host.yaml
exchangerate_host:
    cache:
        pools:
            latest_rates: 'my_new_pool.cache'
```

```
# cache.yaml
framework:
    cache:
        pools:
            my_new_pool.cache:
                adapter: exchangeratehost.cache # extending the default bundle cache
                defaultLifetime: 3600 # 1 hour
                # ... your custom config
```

### Clearing the cache

[](#clearing-the-cache)

If you are using the cache (which is highly recommended) you may want to clear the cache at each new entry of the exchangerate.host API. So you need to set a cron job on your server just after 00:05am GMT everyday (found in the [FAQ](https://exchangerate.host/#/faq)).

The cron command:

```
6 0 * * *

```

⚠️ Cron generally works on local time! Adapt it to the timezone of your servers.

The command:

```
php path/to/my_project/bin/console cache:pool:clear exchangeratehost.cache
```

If you changed the default cache pool, use them instead of `exchangeratehost.cache`!

What's more?
------------

[](#whats-more)

- [exchangerate.host](https://exchangerate.host/#/#docs) for full documentations about the exchangerate.host API.
- [nyholm/psr7](https://github.com/Nyholm/psr7) for a PSR-7 and PSR-17 implementations.
- [symfony/http-client](https://symfony.com/doc/current/http_client.html) for a PSR-18 implementation and a great integration with Symfony.

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance61

Regular maintenance activity

Popularity4

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 81.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

6

Last Release

1101d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ce2276bdc3eeb394bfbb7aa55f92e43ab708da844a860d52b4740887ce597841?d=identicon)[benjaminmal](/maintainers/benjaminmal)

---

Top Contributors

[![benjaminmal](https://avatars.githubusercontent.com/u/58468686?v=4)](https://github.com/benjaminmal "benjaminmal (27 commits)")[![renovate[bot]](https://avatars.githubusercontent.com/in/2740?v=4)](https://github.com/renovate[bot] "renovate[bot] (6 commits)")

---

Tags

bundleexchange-ratessymfony-bundle

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/benjaminmal-exchangeratehost-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/benjaminmal-exchangeratehost-bundle/health.svg)](https://phpackages.com/packages/benjaminmal-exchangeratehost-bundle)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M651](/packages/sylius-sylius)[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k16.7M310](/packages/easycorp-easyadmin-bundle)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[ec-cube/ec-cube

EC-CUBE EC open platform.

78527.0k1](/packages/ec-cube-ec-cube)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
