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

florianv/swap-bundle

Symfony bundle for the Swap currency exchange library. It integrates exchange-rate providers into Symfony, enabling currency conversion, rate lookup, and configurable provider and caching setup through a simple service-oriented API.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Supersedes the prior assessment. Release 6.0.0 reviewed; the core verdict is unchanged, but three deltas are material: a PHP floor bump, a Symfony floor bump, and meaningfully improved engineering hygiene.

Architecture fit

  • Unchanged and now more firmly established: this is a Symfony bundle, not a Laravel package. Its value is DI glue — a SwapExtension, service definitions, and compiler passes reading config/packages/swap.yaml. Laravel has no bundle-extension lifecycle, so the package itself will not boot in Laravel. 6.0.0 does not change this; it reinforces it by typing FlorianvSwapExtension::load() to the Symfony 6.4+ signature (array $configs, ContainerBuilder $container): void), which is a ContainerBuilder API that Laravel does not expose.
  • The domain value still lives one layer down in florianv/swap — framework-agnostic provider adapters, CurrencyPair construction, fallback, PSR-6/PSR-16 caching. The bundle remains a thin config surface.
  • 6.0.0 removes the Symfony <4.2 compatibility branches in Configuration.php, so the bundle is now a cleaner, smaller reference implementation than it was at 5.5.0. That slightly improves its value in the one role we actually care about.
  • Verdict: poor fit as a package, strong fit as a reference implementation. In Laravel, read the bundle, then reproduce ~50–100 lines of service-provider code over florianv/swap. In a Symfony service, it is a genuine drop-in — and now specifically a Symfony 6.4/7.x/8.x drop-in.

Integration feasibility

  • Delta — PHP floor. 6.0.0 requires PHP ^8.2 (drops 7.x and 8.0/8.1). This aligns with Laravel 11/12 (both PHP 8.2+) and narrows the fit for Laravel 9 or Laravel 10 hosts pinned to 8.1. Verify our runtime floor before the spike; this is now a hard gate rather than a caution.
  • Delta — Symfony floor. Requires Symfony ^6.4 | ^7.0 | ^8.0, dropping 3.x/4.x/5.x. Since we do not install the bundle in Laravel this is mostly moot for us, but it converts the composer-coexistence check from "usually fine" to "must be verified": the oldest supported Laravel 10 patch sets sit on Symfony 6.2–6.3 components, and any transitive path through the bundle would now conflict. Verify whether florianv/swap itself carries the same floor — that is the package a Laravel consumer actually installs, and these release notes describe only the bundle.
  • Delta — HTTP adapter. php-http/guzzle6-adapter → php-http/guzzle7-adapter. Irrelevant in Laravel (we wire Guzzle 7 or symfony/http-client directly), but it removes a stale transitively-pulled adapter that could otherwise surface in a dependency audit.
  • Caching remains Symfony Cache in the bundle; in Laravel we substitute an Illuminate\Contracts\Cache\Repository PSR-16 adapter. Fallback chains and provider config translate cleanly to config/swap.php.
  • We still own the adapter code, its tests, and its upgrade path — small, but non-zero.

Technical risk

  • License: MIT — no legal blocker.
  • Delta — quality signal is better than the adoption numbers imply. Bus factor 1 was the leading concern; 6.0.0 partially offsets it:
    • Psalm level 1 static analysis gated in CI — the strongest available evidence of internal correctness, and it is aimed exactly at the type of silent-null/incorrect-return defects that plague provider glue.
    • Backward-compatibility check workflow — makes future majors (the expensive kind) cheaper to adopt.
    • Test matrix PHP 8.2/8.3/8.4/8.5 — forward-looking; 8.5 support pre-empts the annual PHP-version scramble.
    • Two new contributors, one authoring the Symfony 8 support PR. Bus factor is closer to ~1.5 than 1.0, and the release is not solely the maintainer's work.
  • Adoption is still thin (63 stars, 0 dependents), which still means no crowd-sourced bug surface and no tutorials. But "unmaintained toy" is now a demonstrably wrong read — budget for reading the source, not for expecting abandonment.
  • Provider risk remains the dominant risk, not package risk. Exchange-rate APIs deprecate endpoints, change auth, tighten quotas, and shift from free to paid tiers. Fallback mitigates outage, not systematic provider drift.
  • Correctness risk unchanged: stale-cache windows, rounding/precision policy, and date-boundary handling in historical rates are financial-correctness issues. A silently stale rate at checkout is revenue and compliance exposure, not a bug.
  • Key questions for the owning team:
    1. Which providers, and what is the monthly API-key/quota budget?
    2. What is the maximum acceptable rate staleness for (a) display, (b) checkout, (c) settlement/accounting?
    3. Fail-open (serve last-known rate, flagged) or fail-closed (block conversion)? Product decision, not engineering.
    4. Do we need historical/time-series rates, or spot only?
    5. Is the consuming service Laravel, Symfony, or both? If both, the bundle belongs in the Symfony service only.
    6. New: Are all candidate hosts on PHP ≥8.2, and does florianv/swap (not just the bundle) carry that floor?
    7. New: Confirm the 6.0.0 tag actually contains Symfony 8 support end-to-end — the release notes cite PR #61 for the feature while the contributor list references #55 and #57. Worth a one-line tag inspection before we treat Symfony 8 as a supported target.

Integration Approach

Stack fit

  • Symfony consumer: install and configure. Lowest-effort path, unchanged — but the baseline is now Symfony 6.4+. A Symfony 5.4 LTS service is no longer eligible and needs upgrading first.
  • Laravel consumer: do not install the bundle. Install florianv/swap and rebuild the bundle's behavior:
    • SwapServiceProvider binding a singleton SwapInterface (or a narrower CurrencyConverter contract).
    • config/swap.php mirroring the bundle's provider/fallback/cache keys, so config semantics stay recognizable to anyone reading upstream docs.
    • Cache adapter over Laravel's cache repository implementing PSR-16, keyed by (base, quote, date).
    • HTTP: symfony/http-client or Guzzle 7, with explicit connect/read timeouts and a per-provider retry budget. Pin Guzzle 7 to match the adapter the bundle now standardizes on.
  • Anti-corruption layer is mandatory. Expose convert(Money $from, Currency $to): Money in our own namespace; never let Swap\ types leak into controllers, models, or Blade. This is what makes a future provider swap or library replacement a non-event.

Migration path

  1. Delta — version alignment check (hours): confirm PHP ≥8.2 on every host, confirm florianv/swap's own constraints, confirm no legacy Symfony 5.4 service is in scope.
  2. Spike (2–3 days): install the library on a branch, hit two real providers, record latency, quota headers, and failure behavior.
  3. Laravel wiring: provider + config + cache adapter, with feature tests against a faked HTTP client.
  4. Domain wrapper: CurrencyConverter contract, rounding policy as a named, tested rule.
  5. Observability: log provider used, cache hit/miss, and rate age per conversion.

If the team ever consolidates onto Symfony, the bundle is a drop-in for 6.4+ and the wrapper survives unchanged — the wrapper is the migration insurance.

Compatibility

  • Pin the library minor version and run the full suite on upgrade. Treat provider adapter classes as unstable API surface — they change more often than the swap core.
  • Delta: the 6.0.0 constraints are a clean, modern baseline (PHP 8.2+, Symfony 6.4+, PHPUnit 11/12, Psalm 1). That makes future upgrades more predictable, not less: the maintainer is tracking upstream majors rather than drifting.
  • Expect major-version churn tied to Symfony majors (roughly a two-year cadence). Plan it; it is cheap because the BC-check workflow and Psalm gate catch most of the fallout before we see it.

Sequencing

  • Do not block product work on the bundle decision. The library-first path is strictly lower risk and remains the only path available to a Laravel codebase.
  • If both stacks exist, standardize on one currency-conversion service (HTTP or shared package) rather than two independent implementations with divergent rounding rules — divergent rounding is a reconciliation bug waiting to happen.
  • Do not let the Symfony floor bump trigger an unscheduled Symfony 5.4 → 6.4 upgrade. Sequence the conversion workstream independently; it does not require the bundle.

Operational Impact

Maintenance

  • The glue we write is small and stable. 6.0.0 shows the bundle's maintenance profile: ~one major per Symfony major, with BC tooling to make it mechanical. That is a low-frequency, predictable cost.
  • The real maintenance load remains provider adapter upkeep — anticipate 1–2 breaking changes per year across the provider set. Unchanged by this release.
  • Keep the wrapper thin enough that a fork or replacement of florianv/swap is a contained change. Bus factor is modestly improved by the new contributors and CI investment, but forkability is still the actual continuity plan, not vendor support.

Support

  • MIT, community-only, no SLA. Psalm 1 and a BC-check workflow are quality assurances, not escalation paths. Internal runbook still required covering: provider outage, quota exhaustion, key rotation, cache corruption, stale-rate detection.
  • Assign a named owner. A conversion layer with no owner is how stale rates reach production.

Scaling

  • Unchanged. Lookups are I/O- and quota-bound, not CPU-bound. Provider quota is the scaling ceiling.
  • Cache per (base, quote, date) with TTL segmented by use case: minutes-to-hours for display, longer for settlement with explicit provenance recorded.
  • Pre-warm the currency pairs that matter at deploy/cron rather than converting on the request path.
  • Fallback improves availability but adds latency exactly when the system is already degraded — set aggressive timeouts so the last provider in the chain cannot hold a request open.
  • Watch cold-start cache stampedes on high-traffic pair sets; single-flight the fill.

Failure modes

  • Provider outage → chain exhaustion → stale-cache serve or hard failure. Decide the policy explicitly and encode it.
  • Silent stale rates — the dangerous one. Surface rate age to the domain and refuse to settle beyond a threshold.
  • Rounding drift across repeated conversions and currency triangulation; enforce one rounding policy centrally.
  • Quota exhaustion mid-month; alert well before the ceiling.
  • API key leakage via config dumps or logs.
  • Date/timezone boundary errors in historical lookups.
  • Delta — integration-time, not runtime: a PHP 8.1 host or a Symfony 6.2/6.3 component tree will fail dependency resolution outright. Loud and early, which is the good kind — but it surfaces as a blocker during the spike if step 0 is skipped.

Ramp-up

  • Symfony 6.4+ team: hours — idiomatic bundle configuration, and now with fewer legacy shims to read past.
  • Laravel team: ~1 sprint, unchanged — spike, provider wiring, wrapper, rounding policy, failure-mode tests, observability. The learning curve is provider API quirks and financial-correctness policy, not the PHP code.
  • Net assessment: adopt the library, not the bundle, in a Laravel stack; adopt the bundle directly in a Symfony 6.4+/7.x/8.x stack. 6.0.0 improves confidence in the upstream's longevity and lowers the cost of future upgrades, but it does not create a Laravel integration path that did not previously exist. The bundle's real contribution to this decision remains a well-scoped, now cleaner, design reference for a problem we should solve in under a hundred lines of our own, owned, tested code.
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.
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json
refinery29/php-cs-fixer-config
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules