8000 feature #31294 [Form] Add intl/choice_translation_locale option to Ti… · symfony/symfony@a326acc · GitHub
[go: up one dir, main page]

Skip to content

Commit a326acc

Browse files
committed
feature #31294 [Form] Add intl/choice_translation_locale option to TimezoneType (ro0NL)
This PR was merged into the 4.3 branch. Discussion ---------- [Form] Add intl/choice_translation_locale option to TimezoneType | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #28836 | License | MIT | Doc PR | symfony/symfony-docs#11503 final step :) for now i think any form of grouping is a user concern (i.e. by GMT offset or area name); see #31293 + #31295 having a special built in `group_by' => 'gmt_offset'` util would be nice, and can be done in the future. includes #31434 Commits ------- 001b930 [Form] Add intl/choice_translation_locale option to TimezoneType
2 parents 3a17701 + 001b930 commit a326acc

File tree

2 files changed

+111
-6
lines changed

2 files changed

+111
-6
lines changed

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

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313

1414
use Symfony\Component\Form\AbstractType;
1515
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
16+
use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader;
1617
use Symfony\Component\Form\Exception\LogicException;
1718
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeZoneToStringTransformer;
1819
use Symfony\Component\Form\Extension\Core\DataTransformer\IntlTimeZoneToStringTransformer;
1920
use Symfony\Component\Form\FormBuilderInterface;
21+
use Symfony\Component\Intl\Timezones;
2022
use Symfony\Component\OptionsResolver\Options;
2123
use Symfony\Component\OptionsResolver\OptionsResolver;
2224

@@ -40,19 +42,41 @@ public function buildForm(FormBuilderInterface $builder, array $options)
4042
public function configureOptions(OptionsResolver $resolver)
4143
{
4244
$resolver->setDefaults([
45+
'intl' => false,
4346
'choice_loader' => function (Options $options) {
44-
$regions = $options->offsetGet('regions', false);
4547
$input = $options['input'];
4648

49+
if ($options['intl']) {
50+
$choiceTranslationLocale = $options['choice_translation_locale'];
51+
52+
return new IntlCallbackChoiceLoader(function () use ($input, $choiceTranslationLocale) {
53+
return self::getIntlTimezones($input, $choiceTranslationLocale);
54+
});
55+
}
56+
57+
$regions = $options->offsetGet('regions', false);
58+
4759
return new CallbackChoiceLoader(function () use ($regions, $input) {
48-
return self::getTimezones($regions, $input);
60+
return self::getPhpTimezones($regions, $input);
4961
});
5062
},
5163
'choice_translation_domain' => false,
64+
'choice_translation_locale' => null,
5265
'input' => 'string',
5366
'regions' => \DateTimeZone::ALL,
5467
]);
5568

69+
$resolver->setAllowedTypes('intl', ['bool']);
70+
71+
$resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']);
72+
$resolver->setNormalizer('choice_translation_locale', function (Options $options, $value) {
73+
if (null !== $value && !$options['intl']) {
74+
throw new LogicException('The "choice_translation_locale" option can only be used if the "intl" option is set to true.');
75+
}
76+
77+
return $value;
78+
});
79+
5680
$resolver->setAllowedValues('input', ['string', 'datetimezone', 'intltimezone']);
5781
$resolver->setNormalizer('input', function (Options $options, $value) {
5882
if ('intltimezone' === $value && !class_exists(\IntlTimeZone::class)) {
@@ -64,6 +88,13 @@ public function configureOptions(OptionsResolver $resolver)
6488

6589
$resolver->setAllowedTypes('regions', 'int');
6690
$resolver->setDeprecated('regions', 'The option "%name%" is deprecated since Symfony 4.2.');
91+
$resolver->setNormalizer('regions', function (Options $options, $value) {
92+
if ($options['intl'] && \DateTimeZone::ALL !== (\DateTimeZone::ALL & $value)) {
93+
throw new LogicException('The "regions" option can only be used if the "intl" option is set to false.');
94+
}
95+
96+
return $value;
97+
});
6798
}
6899

69100
/**
@@ -82,10 +113,7 @@ public function getBlockPrefix()
82113
return 'timezone';
83114
}
84115

85-
/**
86-
* Returns a normalized array of timezone choices.
87-
*/
88-
private static function getTimezones(int $regions, string $input): array
116+
private static function getPhpTimezones(int $regions, string $input): array
89117
{
90118
$timezones = [];
91119

@@ -99,4 +127,19 @@ private static function getTimezones(int $regions, string $input): array
99127

100128
return $timezones;
101129
}
130+
131+
private static function getIntlTimezones(string $input, string $locale = null): array
132+
{
133+
$timezones = array_flip(Timezones::getNames($locale));
134+
135+
if ('intltimezone' === $input) {
136+
foreach ($timezones as $name => $timezone) {
137+
if ('Etc/Unknown' === \IntlTimeZone::createTimeZone($timezone)->getID()) {
138+
unset($timezones[$name]);
139+
}
140+
}
141+
}
142+
143+
return $timezones;
144+
}
102145
}

src/Symfony/Component/Form/Tests/Extension/Core/Type/TimezoneTypeTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
1313

1414
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
15+
use Symfony\Component\Intl\Util\IntlTestHelper;
1516

1617
class TimezoneTypeTest extends BaseTypeTest
1718
{
@@ -83,6 +84,17 @@ public function testFilterByRegions()
8384
$this->assertContains(new ChoiceView('Europe/Amsterdam', 'Europe/Amsterdam', 'Europe / Amsterdam'), $choices, '', false, false);
8485
}
8586

87+
/**
88+
* @group legacy
89+
* @expectedDeprecation The option "regions" is deprecated since Symfony 4.2.
90+
* @expectedException \Symfony\Component\Form\Exception\LogicException
91+
* @expectedExceptionMessage The "regions" option can only be used if the "intl" option is set to false.
92+
*/
93+
public function testFilterByRegionsWithIntl()
94+
{
95+
$this->factory->create(static::TESTED_TYPE, null, ['regions' => \DateTimeZone::EUROPE, 'intl' => true]);
96+
}
97+
8698
/**
8799
* @requires extension intl
88100
*/
@@ -116,4 +128,54 @@ public function testIntlTimeZoneInputWithBc()
116128
$this->assertNull($form->getData());
117129
$this->assertNotContains('Europe/Saratov', $form->getConfig()->getAttribute('choice_list')->getValues());
118130
}
131+
132+
/**
133+
* @requires extension intl
134+
*/
135+
public function testIntlTimeZoneInputWithBcAndIntl()
136+
{
137+
$form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'intltimezone', 'intl' => true]);
138+
$form->submit('Europe/Saratov');
139+
140+
$this->assertNull($form->getData());
141+
$this->assertNotContains('Europe/Saratov', $form->getConfig()->getAttribute('choice_list')->getValues());
142+
}
143+
144+
public function testTimezonesAreSelectableWithIntl()
145+
{
146+
IntlTestHelper::requireIntl($this, false);
147+
148+
$choices = $this->factory->create(static::TESTED_TYPE, null, ['intl' => true])
149+
->createView()->vars['choices'];
150+
151+
$this->assertContains(new ChoiceView('Europe/Amsterdam', 'Europe/Amsterdam', 'Central European Time (Amsterdam)'), $choices, '', false, false);
152+
$this->assertContains(new ChoiceView('Etc/UTC', 'Etc/UTC', 'Coordinated Universal Time'), $choices, '', false, false);
153+
}
154+
155+
/**
156+
* @requires extension intl
157+
*/
158+
public function testChoiceTranslationLocaleOptionWithIntl()
159+
{
160+
$choices = $this->factory
161+
->create(static::TESTED_TYPE, null, [
162+
'intl' => true,
163+
'choice_translation_locale' => 'uk',
164+
])
165+
->createView()->vars['choices'];
166+
167+
$this->assertContains(new ChoiceView('Europe/Amsterdam', 'Europe/Amsterdam', 'за центральноєвропейським часом (Амстердам)'), $choices, '', false, false);
168+
$this->assertContains(new ChoiceView('Etc/UTC', 'Etc/UTC', 'за всесвітнім координованим часом'), $choices, '', false, false);
169+
}
170+
171+
/**
172+
* @expectedException \Symfony\Component\Form\Exception\LogicException
173+
* @expectedExceptionMessage The "choice_translation_locale" option can only be used if the "intl" option is set to true.
174+
*/
175+
public function testChoiceTranslationLocaleOptionWithoutIntl()
176+
{
177+
$this->factory->create(static::TESTED_TYPE, null, [
178+
'choice_translation_locale' => 'uk',
179+
]);
180+
}
119181
}

0 commit comments

Comments
 (0)
0