Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Swap Bundle Laravel Package

part-db/swap-bundle

A Part-DB bundle for swapping electronic component data between Part-DB installations. It provides the server and client pieces needed to exchange parts and inventory with other instances, helping separate databases stay in sync.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register. composer require part-db/swap-bundle. With Symfony Flex the bundle is auto-registered in config/bundles.php; otherwise add PartDB\SwapBundle\SwapBundle::class => ['all' => true].

Check the version you're landing on first. v6.2.0 tracks upstream SWAP v6.0 — a major bump, not a patch. Before you write a line of application code, confirm three things: the PHP version constraint in composer.json (major upstream bumps routinely raise the floor), that florianv/swap resolved to the 6.x line in composer.lock (composer show part-db/swap-bundle florianv/swap), and that the bundle's own config tree still matches what you're about to write. If you're upgrading an existing install rather than starting fresh, read the Gotchas section before touching the YAML.

Find the config surface before writing any code. The bundle's only real API is the container config plus one or two services. Dump the reference rather than guessing keys:

bin/console config:dump-reference swap        # or part_db_swap — check the extension alias
bin/console debug:container --show-private | grep -i swap

That tells you the service ID for the configured Swap\Swap (or Exchanger) instance, which provider keys are supported, and how caching/HTTP client are wired. Do this first — the README is thin and the config tree is the actual documentation. On a v6.2.0 install, config:dump-reference is also your fastest confirmation that upstream v6 didn't rename the provider keys out from under you.

Minimal config. A working config/packages/swap.yaml needs a provider with credentials and a cache:

swap:
    providers:
        # provider name must match one the bundle registers
        exchangerate_host: ~
    cache:
        pool: cache.app
        ttl: 3600

First use case. Inject the exchange service into a controller or, better, a small domain service, and convert a stored amount:

final class CurrencyConverter
{
    public function __construct(private \Swap\Swap $swap) {}

    public function convert(float $amount, string $from, string $to): float
    {
        $rate = $this->swap->getExchangeRate($from, $to); // Swap\Model\ExchangeRate
        return $amount * $rate->getValue();
    }
}

Start with one direction (base currency → display currency) on a single screen. Everything else — historical rates, multi-provider fallback, Twig filters — is incremental.

Implementation Patterns

Wrap the library, don't inject it everywhere. A CurrencyConverter / ExchangeRateRepository service gives you a single place for rounding rules, caching strategy, fallback rates, and test doubles. Injecting Swap\Swap directly into ten controllers makes every one of those decisions unchangeable later. It also means an upstream major bump touches one class instead of a dozen — which is exactly the situation v6.2.0 puts you in.

Provider chain for resilience. Configure more than one provider where the bundle allows it and let SWAP fall through on failure. Free endpoints disappear and rate-limit without warning; a second provider turns an outage into a slightly stale rate instead of a 500 on your checkout page. Pair this with a PSR-6 pool that survives process restarts (cache.app backed by Redis/DB), not cache.array.

Persist the rate with the transaction. For anything financial-adjacent — orders, invoices, quotes — store amount, currency, rate_used, and rate_date on the row. Recomputing a historical total from today's rate is a silent bug class. If you need true historical rates, request them with the date argument at write time, not read time. This pattern is also your insurance against a provider silently changing quoting conventions between SWAP majors.

Warm the cache out-of-band. Add a console command (or a Symfony Scheduler task) that fetches the handful of currency pairs you actually support once a day and writes them into your cache pool. This keeps user-facing requests off the provider entirely, makes rate limits a non-issue, and gives you one place to alert when a fetch fails. Do not warm arbitrary pairs from user input — that is an unbounded cache and an unbounded API bill.

Resolve display currency per request, not per template. Use a request listener / Locale-to-currency map, or a user preference, and expose it as a small CurrencyContext service. Then the converter has a default target currency and templates don't thread currency codes through every include.

Twig filter, thin. If you register a convert_currency filter, keep it a one-liner over the converter service and format at the edge (NumberFormatter with the currency's fraction digits). Don't do provider calls, rounding policy, or fallback logic in the extension.

Testing. Bind a stub Swap\Swap in config/services_test.yaml returning fixed ExchangeRate objects, so tests never hit the network and assert on stable numbers. Alternatively use the library's mock provider if the bundle exposes it. Also assert on the stored rate column, which is the contract you actually care about. Re-run this full suite immediately after the v6.2.0 upgrade — it is the cheapest way to find out whether the upstream major changed a method signature or a return shape.

Gotchas and Tips

v6.2.0 is an upstream major bump wearing a minor version number. The bundle went 6.1.0 → 6.2.0 but pulled in SWAP v6.0. Treat it as breaking until proven otherwise. Practical upgrade sequence: pin the exact versions, composer update part-db/swap-bundle -W, capture config:dump-reference swap before and after and diff, then run the test suite with network stubs. Things upstream majors historically touch: PHP minimum version, provider class names and namespaces, the ExchangeRate accessor set, PSR-6 vs PSR-16 cache adapters, and HTTP client discovery (PSR-18/HTTPlug). If you decorated or extended any of those, assume breakage and verify rather than hope.

Custom providers are the most likely upgrade casualty. If you registered your own ExchangeRateProvider (see the extension-point note below), check it still satisfies the interface the new upstream version expects — signature changes there fail at container compile time, which is at least loud, but only if the service is actually instantiated.

Direction and base currency are the #1 bug. getExchangeRate('EUR', 'USD') is "how many USD per 1 EUR". If your amounts are already in the provider's base currency you multiply; if you're converting into the base you divide. Write one helper, document the direction in a docblock, and never do ad-hoc * $rate in a template.

Floats are not money. ExchangeRate::getValue() is a float and provider precision is provider-dependent (often 4–6 decimals). Round once, at display, and use bcmath, moneyphp/money, or integer minor units for arithmetic. Never accumulate floats across a line-item loop and expect a total to match an invoice.

Zero-decimal and three-decimal currencies. JPY, KRW, KWD, BHD break number_format($x, 2). Drive formatting from currency metadata, not a hard-coded precision.

Weekends and holidays return nothing. Historical requests for Saturday/Sunday or market holidays may throw or return an empty rate depending on provider. Catch, then walk back to the previous business day. Cache negative results briefly so you don't hammer the provider retrying the same dead date.

Wrap every call in try/catch. SWAP throws for unavailable rates and provider failures. Decide the policy explicitly: use a configured fallback rate, use the last-known rate from your cache, or block the operation. An uncaught exception in a Twig filter during rendering is the worst version of this — it fails a page, not a calculation.

Config key mismatches produce confusing errors. There is no extension able to load the configuration for "swap" means you guessed the alias wrong, or the bundle isn't registered. InvalidConfigurationException on an unknown provider key means the provider name differs from the upstream library's class name. Re-run config:dump-reference after every composer update — doubly so on v6.2.0, where the upstream major may have moved provider keys. Pin the version in composer.json; the release notes here are a single line, so you get very little warning about what changed inside.

Credentials and HTTP behaviour. API keys belong in SWAP_* env vars, not in the committed YAML, and never in exception messages you log. Also configure the underlying HTTP client (timeout ~2–5s, one retry) — provider latency should not be able to hold a web request open. If the bundle doesn't expose client config, decorate the service instead. HTTP client wiring is one of the things most likely to shift in an upstream major, so re-verify your timeouts survived the upgrade.

Don't invent a currency list. ISO 4217 has edge cases (historical currencies, non-ISO codes in payment providers). If you need a supported-currency dropdown, source it from a maintained list, not from what your provider happens to return today.

Extension point to know. The bundle is small enough that upstream SWAP is your extension surface: register a custom ExchangeRateProvider (e.g. a fixed internal rate table for a B2B contract) as a service tagged/configured per the bundle's provider config. That is the clean way to override rates for specific customers without forking the bundle — and it's the seam that lets you survive the next upstream major without touching business logic.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console