PHPackages                             lemonade/component\_currency - 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. [Testing &amp; Quality](/categories/testing)
4. /
5. lemonade/component\_currency

ActiveLibrary[Testing &amp; Quality](/categories/testing)

lemonade/component\_currency
============================

Typed PHP currency conversion library using Czech National Bank exchange rates, filesystem cache, fallback values, and a lightweight hexagonal architecture.

v1.4.0(1mo ago)221MITPHPPHP &gt;=8.1CI passing

Since May 31Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/johnnyxlemonade/component_currency)[ Packagist](https://packagist.org/packages/lemonade/component_currency)[ Docs](https://github.com/johnnyxlemonade/component_currency)[ RSS](/packages/lemonade-component-currency/feed)WikiDiscussions master Synced yesterday

READMEChangelog (8)Dependencies (6)Versions (9)Used By (0)

[![PHP Version](https://camo.githubusercontent.com/effdc154293ad6782b432d15c59d117b6b685cfdbcb9a0ec9403ed9db372de2d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6c656d6f6e6164652f636f6d706f6e656e745f63757272656e6379)](https://packagist.org/packages/lemonade/component_currency)[![Packagist Version](https://camo.githubusercontent.com/896f831ba19782569a90d6b5b3e4c0eb42a7664d6e73b589131728e6d1cfa5b3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c656d6f6e6164652f636f6d706f6e656e745f63757272656e6379)](https://packagist.org/packages/lemonade/component_currency)[![Downloads](https://camo.githubusercontent.com/69a1a99e50d9643d474a4f760a5bd1acc9c64e72ff9fc4c472ea6094ad815e72/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6c656d6f6e6164652f636f6d706f6e656e745f63757272656e6379)](https://packagist.org/packages/lemonade/component_currency)[![PHPStan](https://camo.githubusercontent.com/d18b9a987aa81e64470a11caecf72caa66597c9ebd6b307bd1c2cb7a752b0dff/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c25323031302d627269676874677265656e2e737667)](https://phpstan.org/)[![Tests](https://github.com/johnnyxlemonade/component_currency/actions/workflows/phpunit.yml/badge.svg)](https://github.com/johnnyxlemonade/component_currency/actions/workflows/phpunit.yml)[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)

Lemonade Currency Conversion Library
====================================

[](#lemonade-currency-conversion-library)

**Lemonade Currency Conversion Library** provides a general-purpose currency converter using the Czech National Bank (CNB) as the primary data source.

The library exposes a simple developer-friendly API while internally using a layered, hexagonal-style architecture. This keeps the public API stable and easy to use, while infrastructure concerns such as CNB fetching, parsing, caching, and time resolution stay isolated behind explicit ports and adapters.

Features
--------

[](#features)

- Supports PHP 8.1+
- Fully typed and optimized for static analysis with PHPStan Level 10, strict rules, and bleeding edge
- Provides exchange rates and currency values for supported currencies
- Uses the Czech National Bank (CNB) as the primary data source
- Caches CNB yearly exchange-rate data in the filesystem
- Falls back to default values when CNB data is unavailable
- Supports nearest previous available rate lookup
- Automatically adjusts to CNB's publishing schedule:
    - Exchange rates are published on working days after 14:30.
    - Before 14:30, the previous day's rates are used as the current rate.
- Provides a backward-compatible facade API for simple usage

Supported Data Sources
----------------------

[](#supported-data-sources)

- Czech National Bank (CNB)

Supported Currencies
--------------------

[](#supported-currencies)

- CZK - Czech Republic
- EUR - Eurozone
- HUF - Hungary
- PLN - Poland
- GBP - Great Britain
- USD - United States

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

[](#installation)

Use Composer to install the library:

```
composer require lemonade/component_currency
```

Architecture
------------

[](#architecture)

The library is organized using a lightweight hexagonal architecture.

```
src/
  Domain/
    CurrencyCode.php
    CurrencyCatalog.php
    DefaultCurrencyRates.php
    ExchangeRateTable.php

  Application/
    CurrencyRateService.php
    CurrencyRateServiceFactory.php

  Port/
    Clock.php
    ExchangeRateCache.php
    ExchangeRateSource.php

  Infrastructure/
    Cache/
      FileExchangeRateCache.php
    Clock/
      SystemClock.php
    Cnb/
      CnbExchangeRateSource.php
      CnbRateParser.php
      LineSplitter.php
      RegexLineSplitter.php

  CurrencyRate.php
  CurrencyMarket.php
  CurrencyList.php
  CurrencyStorage.php
  CurrencyData.php
```

### Domain

[](#domain)

The domain layer contains the core currency model and rules:

- supported currency codes
- default currency values
- currency metadata such as symbols and names
- parsed exchange-rate table representation

It does not depend on CNB, filesystem, HTTP, or runtime environment.

### Application

[](#application)

The application layer contains the main use case:

- resolving the requested date
- applying CNB publishing-time rules
- reading rates from cache
- fetching rates from the configured source
- parsing CNB data
- falling back to default values when needed

The primary service is:

```
Lemonade\Currency\Application\CurrencyRateService
```

### Ports

[](#ports)

Ports define contracts for external concerns:

```
Lemonade\Currency\Port\ExchangeRateSource
Lemonade\Currency\Port\ExchangeRateCache
Lemonade\Currency\Port\Clock
```

This allows custom implementations for fetching rates, caching data, or controlling time in tests.

### Infrastructure

[](#infrastructure)

Infrastructure contains concrete adapters:

- `CnbExchangeRateSource` fetches CNB data
- `CnbRateParser` parses CNB text data
- `FileExchangeRateCache` stores CNB data in the filesystem
- `SystemClock` provides current runtime time
- `RegexLineSplitter` splits CNB text data into lines

### Facade API

[](#facade-api)

The public facade classes remain available for simple usage and backward compatibility:

```
Lemonade\Currency\CurrencyRate
Lemonade\Currency\CurrencyMarket
Lemonade\Currency\CurrencyList
```

Usage
-----

[](#usage)

### Basic static API

[](#basic-static-api)

```
use DateTimeImmutable;
use Lemonade\Currency\CurrencyRate;

// Get the ratio of a foreign currency against the local currency.
$eurRatio = CurrencyRate::getRatio(currency: 'EUR');

// Get the value of a foreign currency against CZK.
$usdValue = CurrencyRate::getValue(currency: 'USD');

// Resolve a rate for a specific date.
$eurRatioForDate = CurrencyRate::getRatio(
    currency: 'EUR',
    date: new DateTimeImmutable('2023-12-01')
);

$usdValueForDate = CurrencyRate::getValue(
    currency: 'USD',
    date: new DateTimeImmutable('2023-12-01')
);
```

### CurrencyCode enum

[](#currencycode-enum)

```
use DateTimeImmutable;
use Lemonade\Currency\CurrencyRate;
use Lemonade\Currency\Domain\CurrencyCode;

$eurValue = CurrencyRate::getValue(CurrencyCode::EUR);

$usdValueForDate = CurrencyRate::getValue(
    currency: CurrencyCode::USD,
    date: new DateTimeImmutable('2023-12-01')
);
```

### Shortcut methods

[](#shortcut-methods)

```
use DateTimeImmutable;
use Lemonade\Currency\CurrencyRate;

$eur = CurrencyRate::eur();
$usd = CurrencyRate::usd();
$gbp = CurrencyRate::gbp();
$pln = CurrencyRate::pln();
$huf = CurrencyRate::huf();

$eurForDate = CurrencyRate::eur(new DateTimeImmutable('2023-12-01'));
```

### Market object API

[](#market-object-api)

String currency codes are still supported for backward compatibility.

```
use DateTimeImmutable;
use Lemonade\Currency\CurrencyMarket;
use Lemonade\Currency\Domain\CurrencyCode;

$market = new CurrencyMarket(new DateTimeImmutable('2023-12-01'));

$eurRatio = $market->getRatio(CurrencyCode::EUR);
$usdValue = $market->getValue(CurrencyCode::USD);
```

### Currency metadata

[](#currency-metadata)

```
use Lemonade\Currency\CurrencyList;
use Lemonade\Currency\Domain\CurrencyCode;

$currencies = CurrencyList::getCurrencies();

$symbols = CurrencyList::getCurrencySymbolList();

$eurSymbol = CurrencyList::getCurrencySymbol(CurrencyCode::EUR);

$eurName = CurrencyList::getCurrencyLanguageName(CurrencyCode::EUR);
```

Advanced Usage
--------------

[](#advanced-usage)

### Custom storage directory

[](#custom-storage-directory)

By default, the library stores CNB cache files in:

```
storage/export/cnb
```

You can create the application service manually with a custom storage directory:

```
use Lemonade\Currency\Application\CurrencyRateServiceFactory;

$service = CurrencyRateServiceFactory::createDefault(
    storageDirectory: __DIR__ . '/var/cache/cnb'
);

$value = $service->getValue('EUR');
```

### Custom cache, source, parser, or clock

[](#custom-cache-source-parser-or-clock)

For full control, instantiate the application service directly:

```
use Lemonade\Currency\Application\CurrencyRateService;
use Lemonade\Currency\Domain\DefaultCurrencyRates;
use Lemonade\Currency\Infrastructure\Cache\FileExchangeRateCache;
use Lemonade\Currency\Infrastructure\Clock\SystemClock;
use Lemonade\Currency\Infrastructure\Cnb\CnbExchangeRateSource;
use Lemonade\Currency\Infrastructure\Cnb\CnbRateParser;

$service = new CurrencyRateService(
    cache: new FileExchangeRateCache(__DIR__ . '/var/cache/cnb'),
    source: new CnbExchangeRateSource(),
    parser: new CnbRateParser(),
    defaults: new DefaultCurrencyRates(),
    clock: new SystemClock(),
);

$value = $service->getValue('EUR');
```

This is useful when integrating the library into applications that already have their own cache layer, HTTP transport, or deterministic clock.

### Custom exchange-rate source

[](#custom-exchange-rate-source)

Implement the `ExchangeRateSource` port to fetch data from a different source.

```
use Lemonade\Currency\Port\ExchangeRateSource;

final class CustomExchangeRateSource implements ExchangeRateSource
{
    public function fetchYear(int $year): string
    {
        // Return raw yearly exchange-rate data in the format expected by the configured parser.
        return 'Datum|1 EUR' . PHP_EOL . '2.1.2024|24,725';
    }

    public function getUrl(int $year): string
    {
        return 'custom://currency-rates/' . $year;
    }
}
```

CNB Data Notes
--------------

[](#cnb-data-notes)

CNB yearly exchange-rate data uses multipliers in the header, for example:

```
Datum|1 EUR|100 HUF|1 PLN
2.1.2024|24,725|6,505|5,688
```

The parser normalizes values to a single currency unit. For example, `100 HUF` with value `6,505` is stored as `0.06505` per `1 HUF`.

Configuration
-------------

[](#configuration)

The default filesystem cache directory is:

```
storage/export/cnb
```

Ensure this directory is writable by the PHP process when using the default service factory.

Testing
-------

[](#testing)

Run unit tests:

```
vendor/bin/phpunit
```

Run static analysis:

```
vendor/bin/phpstan analyse
```

Quality
-------

[](#quality)

The library is designed for:

- strict typing
- PHPStan Level 10
- strict rules
- bleeding-edge static analysis
- isolated domain logic
- testable infrastructure adapters
- stable backward-compatible facade API

Contributing
------------

[](#contributing)

Feel free to submit issues or create pull requests to improve this library.

License
-------

[](#license)

This library is licensed under the MIT License. See the `LICENSE` file for details.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance90

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~102 days

Recently: every ~130 days

Total

8

Last Release

46d ago

PHP version history (2 changes)v1.0.0PHP &gt;=8.1

v1.1.0PHP &gt;=8.1 &lt;8.5

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3079458?v=4)[Johnny X. Lemonade](/maintainers/johnnyxlemonade)[@johnnyxlemonade](https://github.com/johnnyxlemonade)

---

Top Contributors

[![johnnyxlemonade](https://avatars.githubusercontent.com/u/3079458?v=4)](https://github.com/johnnyxlemonade "johnnyxlemonade (27 commits)")

---

Tags

cnbcomposer-packagecurrencycurrency-converterczech-national-bankexchange-rateshexagonal-architecturephpphpstanphpunitPHPStancurrencyexchange ratescurrency-converterhexagonal-architecturecnbczech national bank

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/lemonade-component-currency/health.svg)

```
[![Health](https://phpackages.com/badges/lemonade-component-currency/health.svg)](https://phpackages.com/packages/lemonade-component-currency)
```

###  Alternatives

[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.5k55.4M8.4k](/packages/larastan-larastan)[szepeviktor/phpstan-wordpress

WordPress extensions for PHPStan

33110.3M1.4k](/packages/szepeviktor-phpstan-wordpress)[shipmonk/dead-code-detector

Dead code detector to find unused PHP code via PHPStan extension. Can automatically remove dead PHP code. Supports libraries like Symfony, Doctrine, PHPUnit etc. Detects dead cycles. Can detect dead code that is tested.

4853.5M91](/packages/shipmonk-dead-code-detector)[ekino/phpstan-banned-code

Detected banned code using PHPStan

3016.2M119](/packages/ekino-phpstan-banned-code)[staabm/phpstan-todo-by

2052.1M84](/packages/staabm-phpstan-todo-by)[shipmonk/phpstan-rules

Various extra strict PHPStan rules we found useful in ShipMonk.

1542.2M185](/packages/shipmonk-phpstan-rules)

PHPackages © 2026

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