PHP code example of azaharizaman / nexus-currency

1. Go to this page and download the library: Download azaharizaman/nexus-currency 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/ */

    

azaharizaman / nexus-currency example snippets


use Nexus\Currency\ValueObjects\Currency;

// Currency with full ISO 4217 data
$usd = new Currency(
    code: 'USD',
    name: 'US Dollar',
    symbol: '$',
    decimalPlaces: 2,
    numericCode: '840'
);

// Access metadata
echo $usd->getCode();          // "USD"
echo $usd->getSymbol();        // "$"
echo $usd->getDecimalPlaces(); // 2

// Format amounts
echo $usd->formatAmount('1234.56');              // "$ 1,234.56"
echo $usd->formatAmount('1234.56', false, true); // "1,234.56 USD"

// Check decimal type
$jpy = new Currency('JPY', 'Japanese Yen', '¥', 0, '392');
$jpy->isZeroDecimal(); // true

use Nexus\Currency\ValueObjects\CurrencyPair;

// Create pair
$pair = new CurrencyPair('USD', 'EUR');

// Or from string notation
$pair = CurrencyPair::fromString('USD/EUR');

// Access components
echo $pair->getFromCode(); // "USD"
echo $pair->getToCode();   // "EUR"
echo $pair->toString();    // "USD/EUR"

// Get inverse
$inverse = $pair->inverse(); // EUR/USD

use Nexus\Currency\Services\CurrencyManager;

$manager = app(CurrencyManager::class);

// Get currency metadata
$usd = $manager->getCurrency('USD');

// Validate currency code
$manager->validateCode('USD'); // void (success)
$manager->validateCode('XXX'); // throws CurrencyNotFoundException

// Check existence
$manager->exists('EUR'); // true
$manager->exists('ZZZ'); // false

// Get decimal precision
$precision = $manager->getDecimalPrecision('JPY'); // 0

// Format amounts
$formatted = $manager->formatAmount('1234.5678', 'USD');
// "$ 1,234.57" (rounded to 2 decimals)

// Get all currencies
$all = $manager->getAllCurrencies();

// Search currencies
$results = $manager->searchCurrencies('dollar');

use Nexus\Currency\Services\ExchangeRateService;
use Nexus\Currency\ValueObjects\CurrencyPair;
use Nexus\Finance\ValueObjects\Money;

$service = app(ExchangeRateService::class);

// Get current exchange rate
$pair = new CurrencyPair('USD', 'EUR');
$rate = $service->getRate($pair); // Returns Nexus\Finance\ValueObjects\ExchangeRate

// Get historical rate
$date = new DateTimeImmutable('2024-01-15');
$historicalRate = $service->getRate($pair, $date);

// Convert money
$usd = Money::of(100, 'USD');
$eur = $service->convert($usd, 'EUR'); // Money in EUR

// Get multiple rates (batch operation)
$pairs = [
    new CurrencyPair('USD', 'EUR'),
    new CurrencyPair('USD', 'GBP'),
    new CurrencyPair('USD', 'JPY'),
];
$rates = $service->getRates($pairs);

// Refresh specific rates (bypass cache)
$service->refreshRates($pairs);

// Clear all cached rates
$service->clearCache();

// Check provider capabilities
$service->supportsHistoricalRates(); // true/false
$service->getProviderName();         // "ECB" or "Fixer.io"
$service->isProviderAvailable();     // true/false

namespace App\Repositories;

use Nexus\Currency\Contracts\CurrencyRepositoryInterface;
use Nexus\Currency\ValueObjects\Currency;
use Illuminate\Support\Facades\DB;

class DbCurrencyRepository implements CurrencyRepositoryInterface
{
    public function findByCode(string $code): ?Currency
    {
        $row = DB::table('currencies')
            ->where('code', $code)
            ->where('is_active', true)
            ->first();

        if (!$row) {
            return null;
        }

        return new Currency(
            code: $row->code,
            name: $row->name,
            symbol: $row->symbol,
            decimalPlaces: $row->decimal_places,
            numericCode: $row->numeric_code
        );
    }

    public function getAll(): array
    {
        $rows = DB::table('currencies')
            ->where('is_active', true)
            ->get();

        $currencies = [];
        foreach ($rows as $row) {
            $currencies[$row->code] = new Currency(
                code: $row->code,
                name: $row->name,
                symbol: $row->symbol,
                decimalPlaces: $row->decimal_places,
                numericCode: $row->numeric_code
            );
        }

        return $currencies;
    }

    public function exists(string $code): bool
    {
        return DB::table('currencies')
            ->where('code', $code)
            ->where('is_active', true)
            ->exists();
    }

    // Implement other methods...
}

// database/migrations/xxxx_create_currencies_table.php
Schema::create('currencies', function (Blueprint $table) {
    $table->string('code', 3)->primary();
    $table->string('name', 100);
    $table->string('symbol', 10);
    $table->tinyInteger('decimal_places')->default(2);
    $table->string('numeric_code', 3);
    $table->boolean('is_active')->default(true);
    $table->timestamps();
});

// database/seeders/CurrencySeeder.php
DB::table('currencies')->insert([
    ['code' => 'USD', 'name' => 'US Dollar', 'symbol' => '$', 'decimal_places' => 2, 'numeric_code' => '840'],
    ['code' => 'EUR', 'name' => 'Euro', 'symbol' => '€', 'decimal_places' => 2, 'numeric_code' => '978'],
    ['code' => 'GBP', 'name' => 'British Pound', 'symbol' => '£', 'decimal_places' => 2, 'numeric_code' => '826'],
    ['code' => 'JPY', 'name' => 'Japanese Yen', 'symbol' => '¥', 'decimal_places' => 0, 'numeric_code' => '392'],
    ['code' => 'MYR', 'name' => 'Malaysian Ringgit', 'symbol' => 'RM', 'decimal_places' => 2, 'numeric_code' => '458'],
    ['code' => 'SGD', 'name' => 'Singapore Dollar', 'symbol' => 'S$', 'decimal_places' => 2, 'numeric_code' => '702'],
    ['code' => 'CNY', 'name' => 'Chinese Yuan', 'symbol' => '¥', 'decimal_places' => 2, 'numeric_code' => '156'],
    ['code' => 'BHD', 'name' => 'Bahraini Dinar', 'symbol' => 'BD', 'decimal_places' => 3, 'numeric_code' => '048'],
    // Add more currencies as needed...
]);

namespace App\Services\ExchangeRates;

use Nexus\Currency\Contracts\ExchangeRateProviderInterface;
use Nexus\Currency\ValueObjects\CurrencyPair;
use Nexus\Finance\ValueObjects\ExchangeRate;
use Nexus\Connector\Services\ConnectorManager;
use DateTimeImmutable;

class EcbExchangeRateProvider implements ExchangeRateProviderInterface
{
    public function __construct(
        private readonly ConnectorManager $connector
    ) {}

    public function getRate(CurrencyPair $pair, ?DateTimeImmutable $asOf = null): ExchangeRate
    {
        // Use Nexus\Connector with circuit breaker and retry logic
        $response = $this->connector->execute(
            connectionId: 'ecb-api',
            method: 'GET',
            endpoint: $asOf 
                ? "/history/{$asOf->format('Y-m-d')}" 
                : '/latest',
            params: [
                'base' => $pair->getFromCode(),
                'symbols' => $pair->getToCode(),
            ]
        );

        $data = json_decode($response->getBody(), true);

        if (!isset($data['rates'][$pair->getToCode()])) {
            throw ExchangeRateNotFoundException::forPair($pair, $asOf);
        }

        return ExchangeRate::create(
            fromCurrency: $pair->getFromCode(),
            toCurrency: $pair->getToCode(),
            rate: $data['rates'][$pair->getToCode()],
            effectiveDate: $asOf ?? new DateTimeImmutable()
        );
    }

    public function supportsHistoricalRates(): bool
    {
        return true;
    }

    public function getProviderName(): string
    {
        return 'European Central Bank';
    }

    public function isAvailable(): bool
    {
        return $this->connector->isHealthy('ecb-api');
    }

    // Implement getRates()...
}

namespace App\Services\ExchangeRates;

use Nexus\Currency\Contracts\RateStorageInterface;
use Nexus\Currency\ValueObjects\CurrencyPair;
use Nexus\Finance\ValueObjects\ExchangeRate;
use Illuminate\Support\Facades\Redis;
use DateTimeImmutable;

class RedisRateStorage implements RateStorageInterface
{
    private const PREFIX = 'exchange_rate:';

    public function get(CurrencyPair $pair, ?DateTimeImmutable $asOf = null): ?ExchangeRate
    {
        $key = $this->buildKey($pair, $asOf);
        $data = Redis::get($key);

        if (!$data) {
            return null;
        }

        $decoded = json_decode($data, true);

        return ExchangeRate::create(
            fromCurrency: $decoded['from'],
            toCurrency: $decoded['to'],
            rate: $decoded['rate'],
            effectiveDate: new DateTimeImmutable($decoded['date'])
        );
    }

    public function put(CurrencyPair $pair, ExchangeRate $rate, int $ttl = 3600): bool
    {
        $key = $this->buildKey($pair, $rate->getEffectiveDate());
        $data = json_encode([
            'from' => $rate->getFromCurrency(),
            'to' => $rate->getToCurrency(),
            'rate' => $rate->getRate(),
            'date' => $rate->getEffectiveDate()->format('Y-m-d H:i:s'),
        ]);

        return Redis::setex($key, $ttl, $data);
    }

    public function forget(CurrencyPair $pair, ?DateTimeImmutable $asOf = null): bool
    {
        $key = $this->buildKey($pair, $asOf);
        return Redis::del($key) > 0;
    }

    public function flush(): bool
    {
        $keys = Redis::keys(self::PREFIX . '*');
        return count($keys) > 0 ? Redis::del($keys) > 0 : true;
    }

    public function has(CurrencyPair $pair, ?DateTimeImmutable $asOf = null): bool
    {
        $key = $this->buildKey($pair, $asOf);
        return Redis::exists($key) > 0;
    }

    private function buildKey(CurrencyPair $pair, ?DateTimeImmutable $asOf): string
    {
        $dateStr = $asOf ? $asOf->format('Y-m-d') : 'current';
        return self::PREFIX . $pair->toString() . ':' . $dateStr;
    }
}

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Nexus\Currency\Contracts\CurrencyRepositoryInterface;
use Nexus\Currency\Contracts\ExchangeRateProviderInterface;
use Nexus\Currency\Contracts\RateStorageInterface;
use Nexus\Currency\Contracts\CurrencyManagerInterface;
use Nexus\Currency\Services\CurrencyManager;
use Nexus\Currency\Services\ExchangeRateService;
use App\Repositories\DbCurrencyRepository;
use App\Services\ExchangeRates\EcbExchangeRateProvider;
use App\Services\ExchangeRates\RedisRateStorage;

class CurrencyServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Bind repository
        $this->app->singleton(
            CurrencyRepositoryInterface::class,
            DbCurrencyRepository::class
        );

        // Bind exchange rate provider
        $this->app->singleton(
            ExchangeRateProviderInterface::class,
            EcbExchangeRateProvider::class
        );

        // Bind rate storage
        $this->app->singleton(
            RateStorageInterface::class,
            RedisRateStorage::class
        );

        // Bind currency manager
        $this->app->singleton(
            CurrencyManagerInterface::class,
            CurrencyManager::class
        );

        // Bind exchange rate service
        $this->app->singleton(ExchangeRateService::class);
    }
}

// In Nexus\Finance\ValueObjects\Money
use Nexus\Currency\Contracts\CurrencyManagerInterface;

private function validateCurrency(string $currency): void
{
    // Get CurrencyManager from container (or inject if refactoring to service)
    $currencyManager = app(CurrencyManagerInterface::class);
    
    // Delegate validation to Currency package
    try {
        $currencyManager->validateCode($currency);
    } catch (\Nexus\Currency\Exceptions\InvalidCurrencyCodeException $e) {
        throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
    } catch (\Nexus\Currency\Exceptions\CurrencyNotFoundException $e) {
        throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
    }
}

// In Nexus\Finance\ValueObjects\Money
public function formatWithCurrency(CurrencyManagerInterface $currencyManager): string
{
    return $currencyManager->formatAmount(
        amount: $this->amount,
        currencyCode: $this->currency,
        

$money = Money::of(1234.5678, 'USD');
$currencyManager = app(CurrencyManagerInterface::class);

echo $money->formatWithCurrency($currencyManager); // "$ 1,234.57"

$jpy = Money::of(1234.5678, 'JPY');
echo $jpy->formatWithCurrency($currencyManager); // "¥ 1,235" (zero decimals)

// In Money VO
private const PRECISION = 4;

$usd = $currencyManager->getCurrency('USD');
$usd->getDecimalPlaces(); // 2

$jpy = $currencyManager->getCurrency('JPY');
$jpy->getDecimalPlaces(); // 0

$bhd = $currencyManager->getCurrency('BHD');
$bhd->getDecimalPlaces(); // 3 (Bahraini Dinar)

// Internal calculation (4 decimals)
$subtotal = Money::of(100.00, 'USD');
$tax = $subtotal->multiply(0.06); // 6.0000
$total = $subtotal->add($tax);    // 106.0000

// Display with currency-specific precision (2 decimals for USD)
$formatted = $total->formatWithCurrency($currencyManager);
// Result: "$ 106.00"

// For JPY (0 decimals)
$jpyTotal = Money::of(1234.5678, 'JPY');
$formatted = $jpyTotal->formatWithCurrency($currencyManager);
// Result: "¥ 1,235" (rounded, no decimals)

use Nexus\Currency\Exceptions\CurrencyNotFoundException;
use Nexus\Currency\Exceptions\InvalidCurrencyCodeException;
use Nexus\Currency\Exceptions\ExchangeRateNotFoundException;
use Nexus\Currency\Exceptions\ExchangeRateProviderException;

try {
    $currency = $manager->getCurrency('XXX');
} catch (CurrencyNotFoundException $e) {
    // "Currency with code 'XXX' not found. Ensure it exists in the currency repository."
}

try {
    $manager->validateCode('12');
} catch (InvalidCurrencyCodeException $e) {
    // "Currency code must be 3 characters, got 2: '12'"
}

try {
    $rate = $service->getRate(new CurrencyPair('USD', 'FAKE'));
} catch (ExchangeRateNotFoundException $e) {
    // "Exchange rate not found for currency pair USD/FAKE..."
}

try {
    $rate = $service->getRate(new CurrencyPair('USD', 'EUR'));
} catch (ExchangeRateProviderException $e) {
    // "Exchange rate provider 'ECB' API failed. Please try again later."
}

use Nexus\Currency\Contracts\CurrencyRepositoryInterface;
use Nexus\Currency\ValueObjects\Currency;

class InMemoryCurrencyRepository implements CurrencyRepositoryInterface
{
    private array $currencies = [];

    public function __construct()
    {
        // Seed with common currencies for testing
        $this->currencies = [
            'USD' => new Currency('USD', 'US Dollar', '$', 2, '840'),
            'EUR' => new Currency('EUR', 'Euro', '€', 2, '978'),
            'JPY' => new Currency('JPY', 'Japanese Yen', '¥', 0, '392'),
            'MYR' => new Currency('MYR', 'Malaysian Ringgit', 'RM', 2, '458'),
        ];
    }

    public function findByCode(string $code): ?Currency
    {
        return $this->currencies[$code] ?? null;
    }

    public function getAll(): array
    {
        return $this->currencies;
    }

    public function exists(string $code): bool
    {
        return isset($this->currencies[$code]);
    }

    // Implement other methods...
}