Skip to content

Currency Providers

Directory: src/Services/Currency/Contract: Unusualify\Modularous\Contracts\CurrencyProviderInterface

The Currency namespace provides interchangeable implementations of CurrencyProviderInterface — the abstraction used when Modularous needs to resolve currency records from the database (e.g. for price conversion, multi-currency selects, and localisation). The active provider is resolved from the service container and swapped depending on which modules are installed.

Together with CurrencyExchangeService (live exchange-rate fetching) and the CurrencyExchange facade, these pieces cover everything currency-related in Modularous:

PieceResponsibility
CurrencyProviderInterface + implementationsData access — look up currency records stored in the database
CurrencyExchangeServiceRate fetching — hit an external API, cache rates, convert amounts
CurrencyExchange facadeShorthand for the exchange service
CurrencyExchangeControllerHTTP endpoints that expose the exchange service

In This Section

PagePurpose
Overview (this page)When each provider is used, configuration, binding
NullCurrencyProviderDefault fallback — safe empty returns
SystemPricingCurrencyProviderReads from the SystemPricing module's Currency entity
Usage PatternsCommon ways to call the provider from controllers, repositories, and views
Custom ProviderStep-by-step guide to implementing your own provider

How Provider Selection Works

                 ┌─────────────────────────┐
CurrencyProvider │ CurrencyProviderInterface │
                 └───────────┬─────────────┘
                             │ resolve()
                  ┌──────────┴──────────┐
                  │                     │
         SystemPricing enabled?         no pricing module
                  │                     │
                  ▼                     ▼
     SystemPricingCurrencyProvider   NullCurrencyProvider
  1. A module provides its own binding in a service provider (e.g. SystemPricing binds SystemPricingCurrencyProvider).
  2. If no module provides one, BaseServiceProvider falls back to NullCurrencyProvider.
  3. Downstream code always resolves the interface — it never references a concrete class:
php
$provider = app(CurrencyProviderInterface::class);

CurrencyProviderInterface

php
interface CurrencyProviderInterface
{
    public function findByIso4217(string $isoCode): ?object;
    public function getCurrenciesForSelect(): array;
    public function isAvailable(): bool;
}
MethodContract
findByIso4217(string $isoCode): ?objectReturn the currency record whose ISO 4217 code matches (case-insensitive), or null when it does not exist / the provider is not available.
getCurrenciesForSelect(): arrayReturn [['id' => int, 'name' => string, 'iso' => string], ...] — the shape consumed by Modularous select inputs. Return [] when the provider is not available.
isAvailable(): booltrue when the provider can return real data, false when it is the null fallback. Call this before relying on return values.

Why ?object?

The interface deliberately returns ?object rather than a concrete Currency model class. Implementations may back the data with different Eloquent models (or any value object) — the interface simply guarantees the three methods.

Configuration

php
// config/modularous.php (merged from packages/modularous/config/merges/services.php)
'services' => [
    'currency_exchange' => [
        'active'        => env('CURRENCY_EXCHANGE_ACTIVE', true),
        'api_key'       => env('CURRENCY_EXCHANGE_API_KEY'),
        'base_currency' => 'EUR',
        'endpoint'      => 'https://api.freecurrencyapi.com/v1/latest',
        'parameters'    => [
            'apiKey'        => 'apikey',
            'baseCurrency'  => 'base_currency',
        ],
        'rates_key'     => 'data',
    ],
],

Effect of services.currency_exchange.active

activeBehaviour
true (default)getCurrenciesForSelect() returns only the base currency. Forms expose one currency choice and the repository auto-converts to the others using CurrencyExchangeService.
falsegetCurrenciesForSelect() returns every currency. Forms let the operator pick any currency directly; no auto-conversion.

This is the key toggle that controls whether the system is effectively single-currency-with-conversion or multi-currency-manual.

Binding a Custom Provider

Bind from a service provider before BaseServiceProvider::register() runs — or use $this->app->extend() to replace the already-bound instance:

php
// AppServiceProvider::register()
$this->app->bind(
    \Unusualify\Modularous\Contracts\CurrencyProviderInterface::class,
    \App\Services\MyCurrencyProvider::class,
);

For a walkthrough with a working example, see Custom Provider.

Quick Reference

I want to…Use
Look up a currency by ISO codeapp(CurrencyProviderInterface::class)->findByIso4217('USD')
Populate a currency <select>app(CurrencyProviderInterface::class)->getCurrenciesForSelect()
Check whether currencies are available before rendering$provider->isAvailable()
Convert an amount at live ratesCurrencyExchange::convertTo($amount, 'USD')
Fetch the raw rates table (cached 1h)CurrencyExchange::fetchExchangeRates()

See Also