From f9b9dd21f9e19f55f7c43389bcdd9bb0c1204e38 Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Sat, 6 Feb 2021 14:24:44 +0100 Subject: [PATCH] Use "sokil/php-isocodes" on CurrencyCode Since "sokil/php-isocodes" is a dependency of our repository already, it makes sense to use it as a source of currency codes instead of keeping a list of currencies ourselves. By using that library, we can also validate currency codes using different sets. Signed-off-by: Henrique Moody --- .github/workflows/update-currency-codes.yaml | 33 --- bin/update-currency-codes | 39 ---- docs/rules/CurrencyCode.md | 8 + library/Rules/CurrencyCode.php | 234 ++++--------------- tests/unit/Rules/CurrencyCodeTest.php | 25 +- 5 files changed, 69 insertions(+), 270 deletions(-) delete mode 100644 .github/workflows/update-currency-codes.yaml delete mode 100755 bin/update-currency-codes diff --git a/.github/workflows/update-currency-codes.yaml b/.github/workflows/update-currency-codes.yaml deleted file mode 100644 index c49ef4da..00000000 --- a/.github/workflows/update-currency-codes.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: Update currency codes - -on: - schedule: - - cron: '0 0 * * 0' - -jobs: - update-currency-codes: - name: Update currency codes - - runs-on: ubuntu-latest - - steps: - - name: Install xmlstarlet - run: sudo apt install xmlstarlet - - - name: Checkout - uses: actions/checkout@v2 - with: - ref: ${{ secrets.LAST_MINOR_VERSION }} - - - name: Execute script - run: bin/update-currency-codes - - - name: Create pull request - uses: peter-evans/create-pull-request@v2 - with: - committer: The Respect Panda - author: The Respect Panda - commit-message: Update list of currency codes - title: Update list of currency codes - base: ${{ secrets.LAST_MINOR_VERSION }} - branch: "workflows/update-currency-codes" diff --git a/bin/update-currency-codes b/bin/update-currency-codes deleted file mode 100755 index 837b3fe4..00000000 --- a/bin/update-currency-codes +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# Usage: {script} -# Update the list of currency codes - -set -euo pipefail - -declare -r IFS=$'\n' - -declare -r LIST_URL="https://www.currency-iso.org/dam/downloads/lists/list_one.xml" -declare -r LIST_FILENAME=$(mktemp) - -declare -r RULE_FILENAME=$(dirname "${BASH_SOURCE}")/../library/Rules/CurrencyCode.php -declare -r RULE_FILENAME_TEMPORARY=$(mktemp) - -echo "- Downloading list" -curl --silent --location "${LIST_URL}" --output "${LIST_FILENAME}" - -declare -r CURRENCY_CODES_COUNT=$(grep "" "${LIST_FILENAME}" | wc --lines) - -echo "- Creating temporary file" -{ - sed -n "/^ "${RULE_FILENAME_TEMPORARY}" - -echo "- Updating content of '$(basename ${RULE_FILENAME})'" -mv "${RULE_FILENAME_TEMPORARY}" "${RULE_FILENAME}" - -echo "Finished!" diff --git a/docs/rules/CurrencyCode.md b/docs/rules/CurrencyCode.md index 466ecc4c..d1affc7e 100644 --- a/docs/rules/CurrencyCode.md +++ b/docs/rules/CurrencyCode.md @@ -1,13 +1,18 @@ # CurrencyCode - `CurrencyCode()` +- `CurrencyCode(string $set)` Validates an [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code like GBP or EUR. ```php v::currencyCode()->validate('GBP'); // true +v::currencyCode('alpha-3')->validate('EUR'); // true +v::currencyCode('numeric')->validate('840'); // true ``` +This rule uses data from [sokil/php-isocodes][]. + ## Categorization - ISO codes @@ -17,6 +22,7 @@ v::currencyCode()->validate('GBP'); // true Version | Description --------|------------- + 2.2.0 | Allow to use different sets 2.0.0 | Became case-sensitive 1.0.0 | Created @@ -25,3 +31,5 @@ See also: - [CountryCode](CountryCode.md) - [SubdivisionCode](SubdivisionCode.md) + +[sokil/php-isocodes]: https://github.com/sokil/php-isocodes diff --git a/library/Rules/CurrencyCode.php b/library/Rules/CurrencyCode.php index db3fcd48..c2ea16cc 100644 --- a/library/Rules/CurrencyCode.php +++ b/library/Rules/CurrencyCode.php @@ -13,6 +13,16 @@ declare(strict_types=1); namespace Respect\Validation\Rules; +use Respect\Validation\Exceptions\ComponentException; +use Sokil\IsoCodes\IsoCodesFactory; +use Sokil\IsoCodes\TranslationDriver\DummyDriver; + +use function implode; +use function in_array; +use function is_int; +use function is_string; +use function sprintf; + /** * Validates currency codes in ISO 4217. * @@ -21,195 +31,49 @@ namespace Respect\Validation\Rules; * @author Tim Strijdhorst * @author William Espindola */ -final class CurrencyCode extends AbstractSearcher +final class CurrencyCode extends AbstractRule { + public const ALPHA3 = 'alpha-3'; + public const NUMERIC = 'numeric'; + + /** + * @var string + */ + private $set; + + /** + * @var IsoCodesFactory + */ + private $factory; + + public function __construct(string $set = self::ALPHA3) + { + if (!in_array($set, [self::ALPHA3, self::NUMERIC])) { + throw new ComponentException(sprintf( + '"%s" is not a valid set for ISO 4217 (Available: %s)', + $set, + implode(', ', [self::ALPHA3, self::NUMERIC]) + )); + } + + $this->set = $set; + $this->factory = new IsoCodesFactory(null, new DummyDriver()); + } + /** - * @see http://www.currency-iso.org/en/home/tables/table-a1.html - * * {@inheritDoc} */ - protected function getDataSource(): array + public function validate($input): bool { - return [ - 'AED', // UAE Dirham - 'AFN', // Afghani - 'ALL', // Lek - 'AMD', // Armenian Dram - 'ANG', // Netherlands Antillean Guilder - 'AOA', // Kwanza - 'ARS', // Argentine Peso - 'AUD', // Australian Dollar - 'AWG', // Aruban Florin - 'AZN', // Azerbaijan Manat - 'BAM', // Convertible Mark - 'BBD', // Barbados Dollar - 'BDT', // Taka - 'BGN', // Bulgarian Lev - 'BHD', // Bahraini Dinar - 'BIF', // Burundi Franc - 'BMD', // Bermudian Dollar - 'BND', // Brunei Dollar - 'BOB', // Boliviano - 'BOV', // Mvdol - 'BRL', // Brazilian Real - 'BSD', // Bahamian Dollar - 'BTN', // Ngultrum - 'BWP', // Pula - 'BYN', // Belarusian Ruble - 'BZD', // Belize Dollar - 'CAD', // Canadian Dollar - 'CDF', // Congolese Franc - 'CHE', // WIR Euro - 'CHF', // Swiss Franc - 'CHW', // WIR Franc - 'CLF', // Unidad de Fomento - 'CLP', // Chilean Peso - 'CNY', // Yuan Renminbi - 'COP', // Colombian Peso - 'COU', // Unidad de Valor Real - 'CRC', // Costa Rican Colon - 'CUC', // Peso Convertible - 'CUP', // Cuban Peso - 'CVE', // Cabo Verde Escudo - 'CZK', // Czech Koruna - 'DJF', // Djibouti Franc - 'DKK', // Danish Krone - 'DOP', // Dominican Peso - 'DZD', // Algerian Dinar - 'EGP', // Egyptian Pound - 'ERN', // Nakfa - 'ETB', // Ethiopian Birr - 'EUR', // Euro - 'FJD', // Fiji Dollar - 'FKP', // Falkland Islands Pound - 'GBP', // Pound Sterling - 'GEL', // Lari - 'GHS', // Ghana Cedi - 'GIP', // Gibraltar Pound - 'GMD', // Dalasi - 'GNF', // Guinean Franc - 'GTQ', // Quetzal - 'GYD', // Guyana Dollar - 'HKD', // Hong Kong Dollar - 'HNL', // Lempira - 'HRK', // Kuna - 'HTG', // Gourde - 'HUF', // Forint - 'IDR', // Rupiah - 'ILS', // New Israeli Sheqel - 'INR', // Indian Rupee - 'IQD', // Iraqi Dinar - 'IRR', // Iranian Rial - 'ISK', // Iceland Krona - 'JMD', // Jamaican Dollar - 'JOD', // Jordanian Dinar - 'JPY', // Yen - 'KES', // Kenyan Shilling - 'KGS', // Som - 'KHR', // Riel - 'KMF', // Comorian Franc - 'KPW', // North Korean Won - 'KRW', // Won - 'KWD', // Kuwaiti Dinar - 'KYD', // Cayman Islands Dollar - 'KZT', // Tenge - 'LAK', // Lao Kip - 'LBP', // Lebanese Pound - 'LKR', // Sri Lanka Rupee - 'LRD', // Liberian Dollar - 'LSL', // Loti - 'LYD', // Libyan Dinar - 'MAD', // Moroccan Dirham - 'MDL', // Moldovan Leu - 'MGA', // Malagasy Ariary - 'MKD', // Denar - 'MMK', // Kyat - 'MNT', // Tugrik - 'MOP', // Pataca - 'MRU', // Ouguiya - 'MUR', // Mauritius Rupee - 'MVR', // Rufiyaa - 'MWK', // Malawi Kwacha - 'MXN', // Mexican Peso - 'MXV', // Mexican Unidad de Inversion (UDI) - 'MYR', // Malaysian Ringgit - 'MZN', // Mozambique Metical - 'NAD', // Namibia Dollar - 'NGN', // Naira - 'NIO', // Cordoba Oro - 'NOK', // Norwegian Krone - 'NPR', // Nepalese Rupee - 'NZD', // New Zealand Dollar - 'OMR', // Rial Omani - 'PAB', // Balboa - 'PEN', // Sol - 'PGK', // Kina - 'PHP', // Philippine Peso - 'PKR', // Pakistan Rupee - 'PLN', // Zloty - 'PYG', // Guarani - 'QAR', // Qatari Rial - 'RON', // Romanian Leu - 'RSD', // Serbian Dinar - 'RUB', // Russian Ruble - 'RWF', // Rwanda Franc - 'SAR', // Saudi Riyal - 'SBD', // Solomon Islands Dollar - 'SCR', // Seychelles Rupee - 'SDG', // Sudanese Pound - 'SEK', // Swedish Krona - 'SGD', // Singapore Dollar - 'SHP', // Saint Helena Pound - 'SLL', // Leone - 'SOS', // Somali Shilling - 'SRD', // Surinam Dollar - 'SSP', // South Sudanese Pound - 'STN', // Dobra - 'SVC', // El Salvador Colon - 'SYP', // Syrian Pound - 'SZL', // Lilangeni - 'THB', // Baht - 'TJS', // Somoni - 'TMT', // Turkmenistan New Manat - 'TND', // Tunisian Dinar - 'TOP', // Pa’anga - 'TRY', // Turkish Lira - 'TTD', // Trinidad and Tobago Dollar - 'TWD', // New Taiwan Dollar - 'TZS', // Tanzanian Shilling - 'UAH', // Hryvnia - 'UGX', // Uganda Shilling - 'USD', // US Dollar - 'USN', // US Dollar (Next day) - 'UYI', // Uruguay Peso en Unidades Indexadas (UI) - 'UYU', // Peso Uruguayo - 'UYW', // Unidad Previsional - 'UZS', // Uzbekistan Sum - 'VES', // Bolívar Soberano - 'VND', // Dong - 'VUV', // Vatu - 'WST', // Tala - 'XAF', // CFA Franc BEAC - 'XAG', // Silver - 'XAU', // Gold - 'XBA', // Bond Markets Unit European Composite Unit (EURCO) - 'XBB', // Bond Markets Unit European Monetary Unit (E.M.U.-6) - 'XBC', // Bond Markets Unit European Unit of Account 9 (E.U.A.-9) - 'XBD', // Bond Markets Unit European Unit of Account 17 (E.U.A.-17) - 'XCD', // East Caribbean Dollar - 'XDR', // SDR (Special Drawing Right) - 'XOF', // CFA Franc BCEAO - 'XPD', // Palladium - 'XPF', // CFP Franc - 'XPT', // Platinum - 'XSU', // Sucre - 'XTS', // Codes specifically reserved for testing purposes - 'XUA', // ADB Unit of Account - 'XXX', // The codes assigned for transactions where no currency is involved - 'YER', // Yemeni Rial - 'ZAR', // Rand - 'ZMW', // Zambian Kwacha - 'ZWL', // Zimbabwe Dollar - ]; + if (!is_string($input) && !is_int($input)) { + return false; + } + + $currencies = $this->factory->getCurrencies(); + if ($this->set === self::ALPHA3) { + return $currencies->getByLetterCode((string) $input) !== null; + } + + return $currencies->getByNumericCode($input) !== null; } } diff --git a/tests/unit/Rules/CurrencyCodeTest.php b/tests/unit/Rules/CurrencyCodeTest.php index e4da358a..ba5493f4 100644 --- a/tests/unit/Rules/CurrencyCodeTest.php +++ b/tests/unit/Rules/CurrencyCodeTest.php @@ -31,14 +31,15 @@ final class CurrencyCodeTest extends RuleTestCase */ public function providerForValidInput(): array { - $rule = new CurrencyCode(); - return [ - [$rule, 'EUR'], - [$rule, 'GBP'], - [$rule, 'XAU'], - [$rule, 'XBA'], - [$rule, 'XXX'], + [new CurrencyCode(), 'EUR'], + [new CurrencyCode(), 'GBP'], + [new CurrencyCode(), 'XAU'], + [new CurrencyCode(CurrencyCode::ALPHA3), 'XBA'], + [new CurrencyCode(CurrencyCode::ALPHA3), 'XXX'], + [new CurrencyCode(CurrencyCode::NUMERIC), '784'], + [new CurrencyCode(CurrencyCode::NUMERIC), '971'], + [new CurrencyCode(CurrencyCode::NUMERIC), '008'], ]; } @@ -47,13 +48,11 @@ final class CurrencyCodeTest extends RuleTestCase */ public function providerForInvalidInput(): array { - $rule = new CurrencyCode(); - return [ - [$rule, 'BTC'], - [$rule, 'GGP'], - [$rule, 'USA'], - [$rule, 'xxx'], + [new CurrencyCode(), 'BTC'], + [new CurrencyCode(), 'GGP'], + [new CurrencyCode(), 'USA'], + [new CurrencyCode(), 'xxx'], ]; } }