From f05a1ca98ef5c24c2023f79e721320919c1e26e8 Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Fri, 21 Sep 2018 16:50:32 +0200 Subject: [PATCH 1/3] [Form] Allow to configure selectable locales --- .../Extension/Core/ArrayInclusionFilter.php | 32 +++++++++++++++++++ .../Form/Extension/Core/Type/LocaleType.php | 14 ++++++-- .../Extension/Core/Type/LocaleTypeTest.php | 10 ++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php diff --git a/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php b/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php new file mode 100644 index 0000000000000..7868e8cc0934f --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core; + +/** + * @author Sebastiaan Stok + * + * @internal + */ +final class ArrayInclusionFilter +{ + private $acceptedKeys; + + public function __construct(array $acceptedKeys) + { + $this->acceptedKeys = array_fill_keys($acceptedKeys, true); + } + + public function __invoke(string $k) + { + return isset($this->acceptedKeys[$k]); + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index c0de1c933bd17..70f8b389db598 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; +use Symfony\Component\Form\Extension\Core\ArrayInclusionFilter; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -42,16 +43,25 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setDefaults(array( 'choice_loader' => function (Options $options) { $choiceTranslationLocale = $options['choice_translation_locale']; + $supportedLocales = $options['supported_locales']; - return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getLocaleBundle()->getLocaleNames($choiceTranslationLocale)); + return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $supportedLocales) { + $locales = Intl::getLocaleBundle()->getLocaleNames($choiceTranslationLocale); + + if (null !== $supportedLocales) { + $locales = array_filter($locales, new ArrayInclusionFilter($supportedLocales), ARRAY_FILTER_USE_KEY); + } + + return array_flip($locales); }); }, 'choice_translation_domain' => false, 'choice_translation_locale' => null, + 'supported_locales' => null, )); $resolver->setAllowedTypes('choice_translation_locale', array('null', 'string')); + $resolver->setAllowedTypes('supported_locales', array('null', 'string[]')); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php index ab0dfa4bf17d3..06fec590834f6 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php @@ -35,6 +35,16 @@ public function testLocalesAreSelectable() $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false); } + public function testSupportedLocalesAreConfigurable() + { + $choices = $this->factory->create(static::TESTED_TYPE, null, ['supported_locales' => ['en', 'zh_Hant_MO']]) + ->createView()->vars['choices']; + + $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false); + $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false); + $this->assertNotContains(new ChoiceView('en_GB', 'en_GB', 'English (United Kingdom)'), $choices, '', false, false); + } + /** * @requires extension intl */ From a199522b4fb2892be1e605c3968352f6b9823a53 Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Fri, 21 Sep 2018 16:50:43 +0200 Subject: [PATCH 2/3] [Form] Allow to configure selectable countries --- .../Form/Extension/Core/Type/CountryType.php | 15 +++++++++++++-- .../Tests/Extension/Core/Type/CountryTypeTest.php | 14 ++++++++++++++ .../Tests/Extension/Core/Type/LocaleTypeTest.php | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index e7c41e0cec46f..fc84dbb454910 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; +use Symfony\Component\Form\Extension\Core\ArrayInclusionFilter; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -42,16 +43,26 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setDefaults(array( 'choice_loader' => function (Options $options) { $choiceTranslationLocale = $options['choice_translation_locale']; + $supportedCountries = $options['supported_countries']; - return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getRegionBundle()->getCountryNames($choiceTranslationLocale)); + return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $supportedCountries) { + $countries = Intl::getRegionBundle()->getCountryNames($choiceTranslationLocale); + + if (null !== $supportedCountries) { + $supportedCountries = array_map('strtoupper', $supportedCountries); + $countries = array_filter($countries, new ArrayInclusionFilter($supportedCountries), ARRAY_FILTER_USE_KEY); + } + + return array_flip($countries); }); }, 'choice_translation_domain' => false, 'choice_translation_locale' => null, + 'supported_countries' => null, )); $resolver->setAllowedTypes('choice_translation_locale', array('null', 'string')); + $resolver->setAllowedTypes('supported_countries', array('null', 'string[]')); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php index a8e9ddc7d34d9..775d5fd37d30c 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php @@ -57,6 +57,20 @@ public function testChoiceTranslationLocaleOption() $this->assertContains(new ChoiceView('MY', 'MY', 'Малайзія'), $choices, '', false, false); } + public function testAcceptedCountriesIsConfigurable() + { + $choices = $this->factory + ->create(static::TESTED_TYPE, null, array( + 'supported_countries' => array('GB', 'DE'), + )) + ->createView()->vars['choices']; + + $this->assertContains(new ChoiceView('DE', 'DE', 'Germany'), $choices, '', false, false); + $this->assertContains(new ChoiceView('GB', 'GB', 'United Kingdom'), $choices, '', false, false); + $this->assertNotContains(new ChoiceView('US', 'US', 'United States'), $choices, '', false, false); + $this->assertNotContains(new ChoiceView('FR', 'FR', 'France'), $choices, '', false, false); + } + public function testUnknownCountryIsNotIncluded() { $choices = $this->factory->create(static::TESTED_TYPE, 'country') diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php index 06fec590834f6..a46270002d0e1 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php @@ -37,7 +37,7 @@ public function testLocalesAreSelectable() public function testSupportedLocalesAreConfigurable() { - $choices = $this->factory->create(static::TESTED_TYPE, null, ['supported_locales' => ['en', 'zh_Hant_MO']]) + $choices = $this->factory->create(static::TESTED_TYPE, null, array('supported_locales' => array('en', 'zh_Hant_MO'))) ->createView()->vars['choices']; $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false); From 64e63f0a1b51505ce1b0e036167e014556ac188b Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Sun, 23 Sep 2018 20:16:34 +0200 Subject: [PATCH 3/3] Allow usage of closures for filtering --- .../Extension/Core/ArrayInclusionFilter.php | 18 +++++++++++++++--- .../Form/Extension/Core/Type/CountryType.php | 7 +++++-- .../Form/Extension/Core/Type/LocaleType.php | 4 ++-- .../Extension/Core/Type/LocaleTypeTest.php | 15 ++++++++++++++- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php b/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php index 7868e8cc0934f..f4072d6219cc8 100644 --- a/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php +++ b/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php @@ -18,14 +18,26 @@ */ final class ArrayInclusionFilter { + private $filterCallable; private $acceptedKeys; - public function __construct(array $acceptedKeys) + public function __construct($filter) { - $this->acceptedKeys = array_fill_keys($acceptedKeys, true); + if (\is_array($filter)) { + $this->acceptedKeys = array_fill_keys($filter, true); + $this->filterCallable = $this; + } else { + $this->acceptedKeys = []; + $this->filterCallable = $filter; + } } - public function __invoke(string $k) + public function filter(array $choices) + { + return array_filter($choices, $this->filterCallable, ARRAY_FILTER_USE_BOTH); + } + + public function __invoke($v, $k) { return isset($this->acceptedKeys[$k]); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index fc84dbb454910..3ac05b25c7340 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -49,8 +49,11 @@ public function configureOptions(OptionsResolver $resolver) $countries = Intl::getRegionBundle()->getCountryNames($choiceTranslationLocale); if (null !== $supportedCountries) { - $supportedCountries = array_map('strtoupper', $supportedCountries); - $countries = array_filter($countries, new ArrayInclusionFilter($supportedCountries), ARRAY_FILTER_USE_KEY); + if (is_array($supportedCountries)) { + $supportedCountries = array_map('strtoupper', $supportedCountries); + } + + $countries = (new ArrayInclusionFilter($supportedCountries))->filter($countries); } return array_flip($countries); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index 70f8b389db598..d07eaad761411 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -49,7 +49,7 @@ public function configureOptions(OptionsResolver $resolver) $locales = Intl::getLocaleBundle()->getLocaleNames($choiceTranslationLocale); if (null !== $supportedLocales) { - $locales = array_filter($locales, new ArrayInclusionFilter($supportedLocales), ARRAY_FILTER_USE_KEY); + $locales = (new ArrayInclusionFilter($supportedLocales))->filter($locales); } return array_flip($locales); @@ -61,7 +61,7 @@ public function configureOptions(OptionsResolver $resolver) )); $resolver->setAllowedTypes('choice_translation_locale', array('null', 'string')); - $resolver->setAllowedTypes('supported_locales', array('null', 'string[]')); + $resolver->setAllowedTypes('supported_locales', array('null', 'string[]', 'Closure')); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php index a46270002d0e1..e624705c8efb4 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php @@ -35,7 +35,7 @@ public function testLocalesAreSelectable() $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false); } - public function testSupportedLocalesAreConfigurable() + public function testSupportedLocalesAreConfigurableByArray() { $choices = $this->factory->create(static::TESTED_TYPE, null, array('supported_locales' => array('en', 'zh_Hant_MO'))) ->createView()->vars['choices']; @@ -43,6 +43,19 @@ public function testSupportedLocalesAreConfigurable() $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false); $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false); $this->assertNotContains(new ChoiceView('en_GB', 'en_GB', 'English (United Kingdom)'), $choices, '', false, false); + $this->assertNotContains(new ChoiceView('af_ZA', 'af_ZA', 'Afrikaans (South Africa)'), $choices, '', false, false); + } + + public function testSupportedLocalesAreConfigurableByClosure() + { + $choices = $this->factory->create(static::TESTED_TYPE, null, array('supported_locales' => function ($v, $k) { + return $k === 'zh_Hant_MO' || strpos($k, 'en') === 0; + }))->createView()->vars['choices']; + + $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false); + $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false); + $this->assertContains(new ChoiceView('en_GB', 'en_GB', 'English (United Kingdom)'), $choices, '', false, false); + $this->assertNotContains(new ChoiceView('af_ZA', 'af_ZA', 'Afrikaans (South Africa)'), $choices, '', false, false); } /**