Conversation
The PragmaRX Countries package returns the 'currencies' field in two
distinct shapes depending on the underlying data source:
1. A sequential list of ISO 4217 code strings, e.g. ["USD", "EUR"]
2. An associative map keyed by ISO 4217 code with detail objects as
values, e.g. {"USD": {"name": "United States dollar", "symbol": "$"}}
The previous code used Arr::first() unconditionally. For the list shape
this works correctly — Arr::first() returns the first element, which is
the code string. For the associative map shape, however, Arr::first()
returns the first *value* (an array), not the first *key* (the code
string). This caused a TypeError in getCurrenyFromCountryCode() because
the function's return type is declared as ?string but an array was
returned instead.
Affected territories (cca2): BQ, CC, CX, GP, GF, MQ, YT, RE, SJ, TK.
Changes:
- Introduce Utils::resolveCurrencyCode() which normalises both shapes:
* Sequential list → Arr::first() on values (existing behaviour)
* Associative map → array_key_first() to extract the code from keys
Coollection / Collection objects are converted via toArray() first so
that array_is_list() and array_key_first() work reliably.
- Replace Arr::first(...currencies...) with resolveCurrencyCode() in
getCountryData() (line 1202) so the cached country data always stores
a string currency code, never an array.
- Apply the same fix in getCountryCodeByCurrency() (line 1131) which
used the dot-notation shorthand currencies.0 — also broken for the
associative map shape.
- Guard the strtolower() comparison in getCountryCodeByCurrency() with
is_string() to prevent the mb_strtolower(null) deprecation warning
that surfaced when currency resolved to null for map-shape countries.
Fixes: TypeError: getCurrenyFromCountryCode(): Return value must be of
type ?string, array returned (Utils.php:1235)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two related errors were reported in production:
Root cause
The
fleetbase/countriespackage (a fork of PragmaRX Countries) returns thecurrenciesfield in two distinct shapes depending on the underlying data source:["USD"]{"USD": {"name": "United States dollar", "symbol": "$"}}The previous code used
Arr::first()unconditionally on thecurrenciescollection:Arr::first()returns the first element (the code string). ✅Arr::first()returns the first value (an array like["name" => "...", "symbol" => "..."]). ❌This array then propagated into the cached country data and was returned from
getCurrenyFromCountryCode(), whose return type is?string, causing theTypeError.A secondary issue existed in
getCountryCodeByCurrency()which used the dot-notation shorthandcurrencies.0(only valid for list-shape countries) and then calledstrtolower($country['currency'])without a null guard, triggering themb_strtolower(null)deprecation for map-shape territories.Fix
Introduce a new
Utils::resolveCurrencyCode($currencies): ?stringhelper that normalises both shapes:Changes
getCountryData()— replaceArr::first(...currencies...)withresolveCurrencyCode()so the cached country data always stores a string currency code, never an array.getCountryCodeByCurrency()— replacecurrencies.0dot-notation withresolveCurrencyCode()(fixes map-shape countries), and add anis_string()guard beforestrtolower()to eliminate themb_strtolower(null)deprecation.Affected territories
The following 10 territories had associative-map currencies and were broken before this fix: