Skip to content

Commit a6020c7

Browse files
Crovitche-1623nicolas-grekas
authored andcommitted
[Form][Intl] Allow the developer to choose if he want to include/exclude currencies that do not have validity dates.
1 parent b4ca291 commit a6020c7

File tree

4 files changed

+23
-19
lines changed

4 files changed

+23
-19
lines changed

src/Symfony/Component/Form/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ CHANGELOG
66

77
* Add `input=date_point` to `DateTimeType`, `DateType` and `TimeType`
88
* Add support for guessing form type of enum properties
9-
* Add `active_at`, `not_active_at` and `legal_tender` options to `CurrencyType`
9+
* Add `active_at`, `not_active_at` and `legal_tender`, `include_undated` options to `CurrencyType`
1010
* Add `FormFlow` for multistep forms management
1111

1212
7.3

src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,22 @@ public function configureOptions(OptionsResolver $resolver): void
3535
$activeAt = $options['active_at'];
3636
$notActiveAt = $options['not_active_at'];
3737
$legalTender = $options['legal_tender'];
38+
$includeUndated = $options['include_undated'];
3839

3940
if (null !== $activeAt && null !== $notActiveAt) {
4041
throw new InvalidOptionsException('The "active_at" and "not_active_at" options cannot be used together.');
4142
}
4243

4344
$legalTenderCacheKey = match ($legalTender) {
44-
null => '',
45+
null => 'X',
4546
true => '1',
4647
false => '0',
4748
};
4849

4950
return ChoiceList::loader(
5051
$this,
5152
new IntlCallbackChoiceLoader(
52-
static function () use ($choiceTranslationLocale, $activeAt, $notActiveAt, $legalTender) {
53+
static function () use ($choiceTranslationLocale, $activeAt, $notActiveAt, $legalTender, $includeUndated) {
5354
if (null === $activeAt && null === $notActiveAt && null === $legalTender) {
5455
return array_flip(Currencies::getNames($choiceTranslationLocale));
5556
}
@@ -63,7 +64,7 @@ static function () use ($choiceTranslationLocale, $activeAt, $notActiveAt, $lega
6364
};
6465

6566
foreach (Currencies::getCurrencyCodes() as $code) {
66-
if (!Currencies::isValidInAnyCountry($code, $legalTender, $active, $activeAt ?? $notActiveAt)) {
67+
if (!Currencies::isValidInAnyCountry($code, $legalTender, $active, $activeAt ?? $notActiveAt, $includeUndated)) {
6768
continue;
6869
}
6970

@@ -73,13 +74,14 @@ static function () use ($choiceTranslationLocale, $activeAt, $notActiveAt, $lega
7374
return array_flip($filteredCurrencyNames);
7475
},
7576
),
76-
$choiceTranslationLocale.($activeAt ?? $notActiveAt)?->format('Y-m-d\TH:i:s').$legalTenderCacheKey,
77+
$choiceTranslationLocale.($activeAt ?? $notActiveAt)?->format('Y-m-d\TH:i:s').$legalTenderCacheKey.(int) $includeUndated,
7778
);
7879
},
7980
'choice_translation_domain' => false,
8081
'choice_translation_locale' => null,
8182
'active_at' => new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC')),
8283
'not_active_at' => null,
84+
'include_undated' => true,
8385
'legal_tender' => true,
8486
'invalid_message' => 'Please select a valid currency.',
8587
]);
@@ -88,6 +90,7 @@ static function () use ($choiceTranslationLocale, $activeAt, $notActiveAt, $lega
8890
$resolver->setAllowedTypes('active_at', [\DateTimeInterface::class, 'null']);
8991
$resolver->setAllowedTypes('not_active_at', [\DateTimeInterface::class, 'null']);
9092
$resolver->setAllowedTypes('legal_tender', ['bool', 'null']);
93+
$resolver->setAllowedTypes('include_undated', 'bool');
9194
}
9295

9396
public function getParent(): ?string

src/Symfony/Component/Intl/Currencies.php

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public static function forNumericCode(int $numericCode): array
149149
*
150150
* @throws MissingResourceException if the given $country does not exist
151151
*/
152-
public static function forCountry(string $country, ?bool $legalTender = true, ?bool $active = true, \DateTimeInterface $date = new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC'))): array
152+
public static function forCountry(string $country, ?bool $legalTender = true, ?bool $active = true, \DateTimeInterface $date = new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC')), bool $includeUndated = true): array
153153
{
154154
$currencies = [];
155155

@@ -164,7 +164,7 @@ public static function forCountry(string $country, ?bool $legalTender = true, ?b
164164
continue;
165165
}
166166

167-
if (self::isDateActive($country, $currency, $currencyMetadata, $date) !== $active) {
167+
if (self::isDateActive($currencyMetadata, $date, $includeUndated) !== $active) {
168168
continue;
169169
}
170170

@@ -181,7 +181,7 @@ public static function forCountry(string $country, ?bool $legalTender = true, ?b
181181
* @param ?bool $active Indicates whether the currency should always be active for the given $date; null to not filter anything
182182
* @param \DateTimeInterface $date The date that will be checked when $active is set to true
183183
*/
184-
public static function isValidInCountry(string $country, string $currency, ?bool $legalTender = true, ?bool $active = true, \DateTimeInterface $date = new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC'))): bool
184+
public static function isValidInCountry(string $country, string $currency, ?bool $legalTender = true, ?bool $active = true, \DateTimeInterface $date = new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC')), bool $includeUndated = true): bool
185185
{
186186
if (!self::exists($currency)) {
187187
throw new \InvalidArgumentException("The currency $currency does not exist.");
@@ -201,7 +201,7 @@ public static function isValidInCountry(string $country, string $currency, ?bool
201201
return true;
202202
}
203203

204-
return self::isDateActive($country, $currency, $currencyMetadata, $date) === $active;
204+
return self::isDateActive($currencyMetadata, $date, $includeUndated) === $active;
205205
}
206206

207207
/**
@@ -213,16 +213,15 @@ private static function isLegalTender(array $currencyMetadata): bool
213213
}
214214

215215
/**
216-
* @param string $country e.g. 'FR'
217-
* @param string $currency e.g. 'USD'
218216
* @param array{from?: string, to?: string} $currencyMetadata
219217
* @param \DateTimeInterface $date The date on which the check will be performed
218+
* @param bool $includeUndated Whether the currency should be included or not when there are no validity dates
220219
*/
221-
private static function isDateActive(string $country, string $currency, array $currencyMetadata, \DateTimeInterface $date): bool
220+
private static function isDateActive(array $currencyMetadata, \DateTimeInterface $date, bool $includeUndated): bool
222221
{
223222
if (!\array_key_exists('from', $currencyMetadata)) {
224223
// Note: currencies that are not legal tender don't have often validity dates.
225-
throw new \RuntimeException("Cannot check whether the currency $currency is active or not in $country because they are no validity dates available.");
224+
return $includeUndated;
226225
}
227226

228227
$from = \DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s', $currencyMetadata['from'], new \DateTimeZone('Etc/UTC'));
@@ -242,7 +241,7 @@ private static function isDateActive(string $country, string $currency, array $c
242241
* @param ?bool $active Indicates whether the currency should always be active for the given $date; null to not filter anything
243242
* @param \DateTimeInterface $date the date on which the check will be performed if $active is set to true
244243
*/
245-
public static function isValidInAnyCountry(string $currency, ?bool $legalTender = true, ?bool $active = true, \DateTimeInterface $date = new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC'))): bool
244+
public static function isValidInAnyCountry(string $currency, ?bool $legalTender = true, ?bool $active = true, \DateTimeInterface $date = new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC')), bool $includeUndated = true): bool
246245
{
247246
if (!self::exists($currency)) {
248247
throw new \InvalidArgumentException("The currency $currency does not exist.");
@@ -262,7 +261,7 @@ public static function isValidInAnyCountry(string $currency, ?bool $legalTender
262261
return true;
263262
}
264263

265-
if (self::isDateActive($countryCode, $currencyCode, $currencyMetadata, $date) !== $active) {
264+
if (self::isDateActive($currencyMetadata, $date, $includeUndated) !== $active) {
266265
continue;
267266
}
268267

src/Symfony/Component/Intl/Tests/CurrenciesTest.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -866,12 +866,14 @@ public function testChfCurrencyNotConsideredLegalTender()
866866
$this->assertFalse(Currencies::isValidInCountry('CH', 'CHF', false, null));
867867
}
868868

869-
public function testCheCurrencyDoesNotHaveValidityDatesInSwitzerland()
869+
public function testCheCurrencyIncluded()
870870
{
871-
$this->expectException(\RuntimeException::class);
872-
$this->expectExceptionMessage('Cannot check whether the currency CHE is active or not in CH because they are no validity dates available.');
871+
$this->assertTrue(Currencies::isValidInCountry('CH', 'CHE', false, true, includeUndated: true));
872+
}
873873

874-
Currencies::isValidInCountry('CH', 'CHE', false, false);
874+
public function testCheCurrencyExcluded()
875+
{
876+
$this->assertFalse(Currencies::isValidInCountry('CH', 'CHE', false, true, includeUndated: false));
875877
}
876878

877879
/**

0 commit comments

Comments
 (0)