PHPackages                             ihangan/laravel-moldova-exchange-rates - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. ihangan/laravel-moldova-exchange-rates

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

ihangan/laravel-moldova-exchange-rates
======================================

Official BNM (National Bank of Moldova) exchange rates for Laravel: fetch, store and convert, on a schedule.

v1.0.0(today)01↑2900%[1 PRs](https://github.com/ihangan/laravel-moldova-exchange-rates/pulls)MITPHPPHP ^8.3CI passing

Since Jun 30Pushed todayCompare

[ Source](https://github.com/ihangan/laravel-moldova-exchange-rates)[ Packagist](https://packagist.org/packages/ihangan/laravel-moldova-exchange-rates)[ Docs](https://github.com/ihangan/laravel-moldova-exchange-rates)[ RSS](/packages/ihangan-laravel-moldova-exchange-rates/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (13)Versions (3)Used By (0)

[![BNM rates for Laravel](art/social-card.png)](art/social-card.png)

BNM exchange rates for Laravel
==============================

[](#bnm-exchange-rates-for-laravel)

[![Latest version](https://camo.githubusercontent.com/337a5f02afafacf4d1134a9c867f9e501a972f3c5394dccace6e3795d26276c5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6968616e67616e2f6c61726176656c2d6d6f6c646f76612d65786368616e67652d72617465732e737667)](https://packagist.org/packages/ihangan/laravel-moldova-exchange-rates)[![Tests](https://github.com/ihangan/laravel-moldova-exchange-rates/actions/workflows/run-tests.yml/badge.svg)](https://github.com/ihangan/laravel-moldova-exchange-rates/actions/workflows/run-tests.yml)[![PHPStan](https://camo.githubusercontent.com/b6d441ad4fe8332cb16c72aa27f22cc685181dfd74ae34964afc92c6c1146b3c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c2532306d61782d627269676874677265656e2e737667)](https://github.com/ihangan/laravel-moldova-exchange-rates/actions/workflows/static.yml)[![Total downloads](https://camo.githubusercontent.com/d471c961176b0f541009b265e4caee33f8f02ae677691063c324dc88fa4a15a9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6968616e67616e2f6c61726176656c2d6d6f6c646f76612d65786368616e67652d72617465732e737667)](https://packagist.org/packages/ihangan/laravel-moldova-exchange-rates)[![License](https://camo.githubusercontent.com/2234ab05e4f79046f6a864d27f1fd9aefe8773c0ad8ee17a95fb3bc6f3a5d057/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6968616e67616e2f6c61726176656c2d6d6f6c646f76612d65786368616e67652d72617465732e737667)](LICENSE.md)

Pulls the official exchange rates published by the National Bank of Moldova (BNM), stores them, and lets you read or convert them. Rates come straight from the bank's public XML feed, normalised to MDL per one unit, and the whole thing runs on a schedule so your app always has the current numbers.

I built this for a rental site that shows prices in lei, euro and dollars, and pulled it out because every Moldovan app that touches money ends up needing the same thing.

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

[](#requirements)

- PHP 8.3 or higher
- Laravel 12 or 13

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

[](#installation)

```
composer require ihangan/laravel-moldova-exchange-rates
```

Publish and run the migration:

```
php artisan vendor:publish --tag="moldova-exchange-rates-migrations"
php artisan migrate
```

Then schedule the update (see [Keeping the rates fresh](#keeping-the-rates-fresh)) or run it once to get started:

```
php artisan bnm:update-rates
```

Usage
-----

[](#usage)

Everything goes through the `Bnm` facade.

```
use Ihangan\MoldovaExchangeRates\Facades\Bnm;

Bnm::rates();          // ['MDL' => 1.0, 'EUR' => 20.105, 'USD' => 17.308, ...]
Bnm::rate('EUR');      // 20.105
Bnm::date();           // '2026-06-04' — the day these rates are from

// Convert between any two currencies it knows about.
Bnm::convert(250, 'EUR', 'MDL'); // 5026.25
Bnm::convert(250, 'EUR', 'USD'); // 290.4

// Which way each currency moved against the previous publishing day.
Bnm::trends();         // ['EUR' => 'up', 'USD' => 'down', ...]
```

All rates are stored as "MDL per one unit", so MDL is the pivot and is always present with a rate of `1.0`. `convert()` and the reads return `null` / empty when there are no rates yet or a currency isn't tracked.

You can also reach the model directly:

```
use Ihangan\MoldovaExchangeRates\Models\ExchangeRate;

ExchangeRate::query()->where('currency', 'EUR')->latest('effective_date')->first();
```

Keeping the rates fresh
-----------------------

[](#keeping-the-rates-fresh)

The package ships the `bnm:update-rates` command. BNM updates rates on business days, so twice a day is plenty. Add it to your scheduler:

```
use Illuminate\Support\Facades\Schedule;

Schedule::command('bnm:update-rates')->twiceDaily(9, 15);
```

The fetch is a single light HTTP request, so the command runs inline. If you'd rather push it onto a queue, dispatch the job instead with the `--queue` flag (your worker runs it):

```
Schedule::command('bnm:update-rates --queue')->twiceDaily(9, 15);
```

Or skip the manual wiring and let the package schedule itself — set `schedule` in the config to `twice_daily`, `daily` or `hourly`.

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

[](#configuration)

```
php artisan vendor:publish --tag="moldova-exchange-rates-config"
```

```
return [
    'table' => 'bnm_exchange_rates',
    'connection' => null,
    'base' => 'MDL',
    'currencies' => ['EUR', 'USD', 'RON', 'UAH'],
    'endpoint' => env('BNM_RATES_ENDPOINT', 'https://www.bnm.md/en/official_exchange_rates'),
    'http' => ['timeout' => 15, 'retries' => 2, 'lookback_days' => 4],
    'cache' => ['key' => 'bnm-rates:snapshot', 'ttl' => 21600, 'store' => null],
    'schedule' => false, // false | 'twice_daily' | 'daily' | 'hourly'
];
```

- **currencies** — which codes to fetch and store. Anything BNM publishes works (EUR, USD, RON, UAH, GBP, RUB, ...).
- **lookback\_days** — BNM doesn't publish on weekends and holidays, so the client walks back up to this many days until it gets a valid response.
- **cache** — the latest snapshot is cached and refreshed automatically after each update.
- **table** — named `bnm_exchange_rates` so it won't clash with a table you already have.

How it reads BNM
----------------

[](#how-it-reads-bnm)

The bank exposes an XML feed at `bnm.md/en/official_exchange_rates?get_xml=1&date=dd.mm.yyyy`. Each currency carries a `Nominal` and a `Value`, so a rate quoted per 10 units (UAH, for example) is normalised to one unit: `rate = Value / Nominal`. The effective date comes from the feed itself, not from the request.

Testing
-------

[](#testing)

```
composer test
```

Tests fake the HTTP layer, so they never touch the BNM servers.

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) and the [releases](https://github.com/ihangan/laravel-moldova-exchange-rates/releases).

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

[](#contributing)

See [CONTRIBUTING.md](CONTRIBUTING.md).

Security
--------

[](#security)

Found a security issue? Email  instead of using the issue tracker. See [SECURITY.md](.github/SECURITY.md).

Credits
-------

[](#credits)

- [Igor Hangan](https://github.com/ihangan)
- Exchange-rate data is published by the [National Bank of Moldova](https://www.bnm.md).

License
-------

[](#license)

The MIT License. See [LICENSE.md](LICENSE.md).

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance100

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

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

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

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

---

Top Contributors

[![ihangan](https://avatars.githubusercontent.com/u/17790228?v=4)](https://github.com/ihangan "ihangan (1 commits)")

---

Tags

laravelcurrencyconverterexchange ratesMoldovaMDLbnm

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/ihangan-laravel-moldova-exchange-rates/health.svg)

```
[![Health](https://phpackages.com/badges/ihangan-laravel-moldova-exchange-rates/health.svg)](https://phpackages.com/packages/ihangan-laravel-moldova-exchange-rates)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.1M337](/packages/psalm-plugin-laravel)[spatie/laravel-health

Monitor the health of a Laravel application

87511.3M154](/packages/spatie-laravel-health)[larastan/larastan

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

6.4k51.0M7.8k](/packages/larastan-larastan)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9772.3M122](/packages/roots-acorn)[spatie/laravel-export

Create a static site bundle from a Laravel app

672139.5k6](/packages/spatie-laravel-export)[simplestats-io/laravel-client

Analytics for Laravel. Track visitors, registrations, and payments. Discover which channels actually drive revenue, not just traffic. Server-side, GDPR compliant, ad-blocker proof.

5019.3k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

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