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..f4072d6219cc8 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/ArrayInclusionFilter.php @@ -0,0 +1,44 @@ + + * + * 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 $filterCallable; + private $acceptedKeys; + + public function __construct($filter) + { + if (\is_array($filter)) { + $this->acceptedKeys = array_fill_keys($filter, true); + $this->filterCallable = $this; + } else { + $this->acceptedKeys = []; + $this->filterCallable = $filter; + } + } + + 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 e7c41e0cec46f..3ac05b25c7340 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,29 @@ 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) { + if (is_array($supportedCountries)) { + $supportedCountries = array_map('strtoupper', $supportedCountries); + } + + $countries = (new ArrayInclusionFilter($supportedCountries))->filter($countries); + } + + 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/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index c0de1c933bd17..d07eaad761411 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 = (new ArrayInclusionFilter($supportedLocales))->filter($locales); + } + + 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[]', 'Closure')); } /** 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 ab0dfa4bf17d3..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,6 +35,29 @@ public function testLocalesAreSelectable() $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false); } + public function testSupportedLocalesAreConfigurableByArray() + { + $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); + $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); + } + /** * @requires extension intl */