1. Go to this page and download the library: Download peterlupu/curs-bnr library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
peterlupu / curs-bnr example snippets
use CursBnr\CursBnr;
$bnr = new CursBnr();
// The latest communicated rate
$rate = $bnr->latest('EUR');
$rate->value; // 5.246 (RON per 1 EUR)
$rate->communicatedOnYmd(); // '2026-08-04'
// The rate legally valid on a given date (this is the one you invoice with!)
$rate = $bnr->validOn('EUR', new DateTimeImmutable('2024-01-27'));
$rate->value; // 4.9763 — communicated Friday Jan 26
// Convert between any two currencies
$factor = $bnr->pair('EUR', 'RON', new DateTimeImmutable('2024-01-27'));
$amountInRon = $amountInEur * $factor;
$rate = $bnr->validOn('HUF', new DateTimeImmutable('2024-01-27'));
$rate->currency; // 'HUF'
$rate->value; // 0.013620 — RON per 1 HUF (multiplier already applied!)
$rate->multiplier; // 100 — BNR quotes HUF per 100 units; we normalize for you
$rate->communicatedAt; // DateTimeImmutable of the communication date
$rate->validFrom(); // communicatedAt + 1 day, per art. 290
$bnr->pair('EUR', 'RON'); // 4.9763 — the rate valid TODAY
$bnr->pair('RON', 'EUR'); // 0.20095... — full precision, no rounding
$bnr->pair('EUR', 'USD'); // cross rate via RON
$bnr->pair('EUR', 'EUR'); // 1.0 — no HTTP request at all
$bnr->pair('EUR', 'RON', new DateTimeImmutable('2024-01-27')); // valid-on-date semantics
$day = $bnr->latestDay(); // one HTTP call
$day->rate('EUR')->value;
$day->rate('USD')->value;
$day->rate('CHF')->value;
$day->communicatedAt; // when this Cube was communicated
$day->validFrom(); // the day these rates become valid
$day->has('MDL'); // true
foreach ($day->rates as $code => $rate) { /* all ~30 of them */ }
$bnr->validDayOn(new DateTimeImmutable('2024-01-27')); // rates valid on that day
$bnr->communicatedDayOn(new DateTimeImmutable('2024-01-26')); // rates communicated that exact day
use CursBnr\Exception\CursBnrException;
try {
$rate = $bnr->validOn('EUR', $date);
} catch (CursBnrException $e) {
// network down, feed broken, unknown currency, ... — one catch to rule them all
}
use CursBnr\CursBnr;
use CursBnr\FeedUrls;
use CursBnr\Http\RetryPolicy;
$bnr = new CursBnr(
retryPolicy: new RetryPolicy(attempts: 5, backoffMs: [100, 500, 2000]),
maxWalkBackDays: 30,
);
new RetryPolicy(attempts: 4, backoffMs: fn (int $retry) => $retry * 250);
RetryPolicy::none(); // fail fast
$bnr = new CursBnr(clock: fn () => new DateTimeImmutable('2024-01-29'));
use CursBnr\Http\HttpClientInterface;
final class MyClient implements HttpClientInterface
{
public function get(string $url): string { /* ... */ }
}
$bnr = new CursBnr(httpClient: new MyClient());
use CursBnr\Http\Psr18HttpClient;
$bnr = new CursBnr(httpClient: new Psr18HttpClient(
new \GuzzleHttp\Client(),
new \GuzzleHttp\Psr7\HttpFactory(),
));
$bnr = new CursBnr(urls: new FeedUrls(
daily: 'https://my-mirror.example/nbrfxrates.xml',
yearlyTemplate: 'https://my-mirror.example/years/nbrfxrates{year}.xml',
));
use CursBnr\CursBnr;
use CursBnr\ExchangeRates;
final class InvoiceTotals
{
public function __construct(private readonly ExchangeRates $bnr) {}
public function inRon(float $amountEur, \DateTimeInterface $issuedOn): float
{
return $amountEur * $this->bnr->pair('EUR', 'RON', $issuedOn);
}
}
// production wiring: bind ExchangeRates => new CursBnr()
use CursBnr\Testing\FakeCursBnr;
$bnr = FakeCursBnr::constant(['EUR' => 5.0, 'USD' => 4.5]);
$totals = new InvoiceTotals($bnr);
$totals->inRon(100.0, new DateTimeImmutable('2024-01-27')); // 500.0 — always
$bnr = (new FakeCursBnr())
->communicate('2024-01-25', ['EUR' => 4.9765])
->communicate('2024-01-26', ['EUR' => 4.9763]);
// nothing on 27-28 — the weekend
$bnr->validOn('EUR', new DateTimeImmutable('2024-01-26'))->value; // 4.9765 — Thursday's (strictly before!)
$bnr->validOn('EUR', new DateTimeImmutable('2024-01-27'))->value; // 4.9763 — Friday's
$bnr->latest('EUR')->value; // 4.9763 — most recent registration
$bnr->communicatedOn('EUR', new DateTimeImmutable('2024-01-27')); // NoRateCommunicatedException (weekend)
$bnr->latest('CHF'); // UnknownCurrencyException (not registered)
FakeCursBnr::constant(['EUR' => 5.0], maxWalkBackDays: 3); // bound configurable, like the real thing
// pin "today" to make the future-date guard deterministic in tests
new FakeCursBnr(today: '2024-01-29');
$service = new InvoiceTotals(FakeCursBnr::constant(['EUR' => 5.0]));
// app/Providers/AppServiceProvider.php
public function register(): void
{
$this->app->singleton(\CursBnr\ExchangeRates::class, \CursBnr\CursBnr::class);
}
// in a feature test — every resolved service now sees the fake
$this->app->instance(
\CursBnr\ExchangeRates::class,
\CursBnr\Testing\FakeCursBnr::constant(['EUR' => 5.0]),
);
// in a KernelTestCase / WebTestCase
static::getContainer()->set(
\CursBnr\ExchangeRates::class,
\CursBnr\Testing\FakeCursBnr::constant(['EUR' => 5.0]),
);
// PHP-DI example
return [
CursBnr\ExchangeRates::class => DI\autowire(CursBnr\CursBnr::class),
];
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.