Skip to content

Commit f7c6103

Browse files
Merge branch '7.4' into 8.0
* 7.4: (28 commits) [Console] Rename `#[Input]` to `#[MapInput]` [FrameworkBundle] Fix support of dumping workflow when workflow is decorated by TraceableWorkflow [JsonStreamer] Fix documentation link in README [Meta] Better exception when symfony link cannot read a JSON [Form] Add new `active_at`, `not_active_at` and `legal_tender` options to `CurrencyType` [Intl] Support time in generated data in currencies validity [Validator] Improve and complete Japanese translations [HtmlSanitizer] Remove redundant assignment to promoted property $config in constructor [Validator] Fix Polish translation for word count validation message [DependencyInjection][Routing] Deprecate XML configuration format [Validator] Review and fix Czech translation [DependencyInjection][Routing] Handle declaring services and routes using PHP arrays that follow the same shape as corresponding yaml files [Mailer][MailJet] Fix forbidden headers case-sensitive comparison [DependencyInjection][Config][Routing] Deprecate using `$this` or the internal scope of the loader from PHP config files [Config] Add array-shapes to generated config builders [DependencyInjection] Handle returning arrays and config-builders from config files [WebProfilerBundle] Simplify toolbar CSS do not use deprecated PHPUnit features replace PHPUnit annotation with attribute [Serializer] xml empty array encoding ...
2 parents 08ed607 + cf449e8 commit f7c6103

File tree

4 files changed

+111
-4
lines changed

4 files changed

+111
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ CHANGELOG
1414

1515
* Add `input=date_point` to `DateTimeType`, `DateType` and `TimeType`
1616
* Add support for guessing form type of enum properties
17+
* Add `active_at`, `not_active_at` and `legal_tender` options to `CurrencyType`
1718

1819
7.3
1920
---

Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ protected function getNumberFormatter(): \NumberFormatter
173173
*/
174174
protected function castParsedValue(int|float $value): int|float
175175
{
176-
if (\is_int($value) && $value === (int) $float = (float) $value) {
176+
if (\is_int($value) && (($float = (float) $value) < \PHP_INT_MAX) && $value === (int) $float) {
177177
return $float;
178178
}
179179

Extension/Core/Type/CurrencyType.php

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Form\Exception\LogicException;
1818
use Symfony\Component\Intl\Currencies;
1919
use Symfony\Component\Intl\Intl;
20+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
2021
use Symfony\Component\OptionsResolver\Options;
2122
use Symfony\Component\OptionsResolver\OptionsResolver;
2223

@@ -31,15 +32,62 @@ public function configureOptions(OptionsResolver $resolver): void
3132
}
3233

3334
$choiceTranslationLocale = $options['choice_translation_locale'];
35+
$activeAt = $options['active_at'];
36+
$notActiveAt = $options['not_active_at'];
37+
$legalTender = $options['legal_tender'];
3438

35-
return ChoiceList::loader($this, new IntlCallbackChoiceLoader(static fn () => array_flip(Currencies::getNames($choiceTranslationLocale))), $choiceTranslationLocale);
39+
if (null !== $activeAt && null !== $notActiveAt) {
40+
throw new InvalidOptionsException('The "active_at" and "not_active_at" options cannot be used together.');
41+
}
42+
43+
$legalTenderCacheKey = match ($legalTender) {
44+
null => '',
45+
true => '1',
46+
false => '0',
47+
};
48+
49+
return ChoiceList::loader(
50+
$this,
51+
new IntlCallbackChoiceLoader(
52+
static function () use ($choiceTranslationLocale, $activeAt, $notActiveAt, $legalTender) {
53+
if (null === $activeAt && null === $notActiveAt && null === $legalTender) {
54+
return array_flip(Currencies::getNames($choiceTranslationLocale));
55+
}
56+
57+
$filteredCurrencyNames = [];
58+
59+
$active = match (true) {
60+
null !== $activeAt => true,
61+
null !== $notActiveAt => false,
62+
default => null,
63+
};
64+
65+
foreach (Currencies::getCurrencyCodes() as $code) {
66+
if (!Currencies::isValidInAnyCountry($code, $legalTender, $active, $activeAt ?? $notActiveAt)) {
67+
continue;
68+
}
69+
70+
$filteredCurrencyNames[$code] = Currencies::getName($code, $choiceTranslationLocale);
71+
}
72+
73+
return array_flip($filteredCurrencyNames);
74+
},
75+
),
76+
$choiceTranslationLocale.($activeAt ?? $notActiveAt)?->format('Y-m-d\TH:i:s').$legalTenderCacheKey,
77+
);
3678
},
3779
'choice_translation_domain' => false,
3880
'choice_translation_locale' => null,
81+
'active_at' => new \DateTimeImmutable('today', new \DateTimeZone('Etc/UTC')),
82+
'not_active_at' => null,
83+
'legal_tender' => true,
3984
'invalid_message' => 'Please select a valid currency.',
4085
]);
4186

4287
$resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']);
88+
$resolver->setAllowedTypes('active_at', [\DateTimeInterface::class, 'null']);
89+
$resolver->setAllowedTypes('not_active_at', [\DateTimeInterface::class, 'null']);
90+
$resolver->setAllowedTypes('legal_tender', ['bool', 'null']);
4391
}
4492

4593
public function getParent(): ?string

Tests/Extension/Core/Type/CurrencyTypeTest.php

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
1616
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
1717
use Symfony\Component\Intl\Util\IntlTestHelper;
18+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
1819

1920
class CurrencyTypeTest extends BaseTypeTestCase
2021
{
@@ -34,7 +35,6 @@ public function testCurrenciesAreSelectable()
3435

3536
$this->assertContainsEquals(new ChoiceView('EUR', 'EUR', 'Euro'), $choices);
3637
$this->assertContainsEquals(new ChoiceView('USD', 'USD', 'US Dollar'), $choices);
37-
$this->assertContainsEquals(new ChoiceView('SIT', 'SIT', 'Slovenian Tolar'), $choices);
3838
}
3939

4040
#[RequiresPhpExtension('intl')]
@@ -49,7 +49,6 @@ public function testChoiceTranslationLocaleOption()
4949
// Don't check objects for identity
5050
$this->assertContainsEquals(new ChoiceView('EUR', 'EUR', 'євро'), $choices);
5151
$this->assertContainsEquals(new ChoiceView('USD', 'USD', 'долар США'), $choices);
52-
$this->assertContainsEquals(new ChoiceView('SIT', 'SIT', 'словенський толар'), $choices);
5352
}
5453

5554
public function testSubmitNull($expected = null, $norm = null, $view = null)
@@ -61,4 +60,63 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = 'EUR', $expected
6160
{
6261
parent::testSubmitNullUsesDefaultEmptyData($emptyData, $expectedData);
6362
}
63+
64+
#[RequiresPhpExtension('intl')]
65+
public function testAnActiveAndLegalTenderCurrencyIn2006()
66+
{
67+
$choices = $this->factory
68+
->create(static::TESTED_TYPE, null, [
69+
'choice_translation_locale' => 'fr',
70+
'active_at' => new \DateTimeImmutable('2006-01-01', new \DateTimeZone('Etc/UTC')),
71+
'legal_tender' => true,
72+
])
73+
->createView()->vars['choices'];
74+
75+
$this->assertContainsEquals(new ChoiceView('SIT', 'SIT', 'tolar slovène'), $choices);
76+
}
77+
78+
#[RequiresPhpExtension('intl')]
79+
public function testAnExpiredCurrencyIn2007()
80+
{
81+
$choices = $this->factory
82+
->create(static::TESTED_TYPE, null, [
83+
'choice_translation_locale' => 'fr',
84+
'legal_tender' => true,
85+
// The SIT currency expired on 2007-01-14.
86+
'active_at' => new \DateTimeImmutable('2007-01-15', new \DateTimeZone('Etc/UTC')),
87+
])
88+
->createView()->vars['choices'];
89+
90+
$this->assertNotContainsEquals(new ChoiceView('SIT', 'SIT', 'tolar slovène'), $choices);
91+
}
92+
93+
#[RequiresPhpExtension('intl')]
94+
public function testRetrieveExpiredCurrenciesIn2007()
95+
{
96+
$choices = $this->factory
97+
->create(static::TESTED_TYPE, null, [
98+
'choice_translation_locale' => 'fr',
99+
'legal_tender' => true,
100+
'active_at' => null,
101+
// The SIT currency expired on 2007-01-14.
102+
'not_active_at' => new \DateTimeImmutable('2007-01-15', new \DateTimeZone('Etc/UTC')),
103+
])
104+
->createView()->vars['choices'];
105+
106+
$this->assertContainsEquals(new ChoiceView('SIT', 'SIT', 'tolar slovène'), $choices);
107+
}
108+
109+
public function testAnExceptionShouldBeThrownWhenTheActiveAtAndNotActiveAtOptionsAreBothSet()
110+
{
111+
$this->expectException(InvalidOptionsException::class);
112+
113+
$this->expectExceptionMessage('The "active_at" and "not_active_at" options cannot be used together.');
114+
115+
$this->factory
116+
->create(static::TESTED_TYPE, null, [
117+
'active_at' => new \DateTimeImmutable(),
118+
'not_active_at' => new \DateTimeImmutable(),
119+
])
120+
->createView();
121+
}
64122
}

0 commit comments

Comments
 (0)