Created
May 5, 2023 07:58
-
-
Save ker0x/e050e7d1c5b7c1d1f88e3dd825f75f52 to your computer and use it in GitHub Desktop.
A Symfony Form extension to display emoji country flag for CountryType
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App\Form\Extension; | |
use Symfony\Component\Form\AbstractTypeExtension; | |
use Symfony\Component\Form\ChoiceList\ChoiceList; | |
use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; | |
use Symfony\Component\Form\Exception\LogicException; | |
use Symfony\Component\Form\Extension\Core\Type\CountryType; | |
use Symfony\Component\Intl\Countries; | |
use Symfony\Component\Intl\Intl; | |
use Symfony\Component\OptionsResolver\Options; | |
use Symfony\Component\OptionsResolver\OptionsResolver; | |
final class CountryTypeExtension extends AbstractTypeExtension | |
{ | |
public const FORMAT_WITH_NAME = '{name}'; | |
public const FORMAT_WITH_FLAG = '{flag}'; | |
public const FORMAT_WITH_FLAG_AND_NAME = '{flag} {name}'; | |
public const FLAG_POSITION_BEFORE = 'before'; | |
public const FLAG_POSITION_AFTER = 'after'; | |
public static function getExtendedTypes(): iterable | |
{ | |
return [CountryType::class]; | |
} | |
public static function getFlag(string $countryCode): string | |
{ | |
$offset = 0x1F1A5; | |
return | |
mb_chr($offset + mb_ord($countryCode[0], 'UTF-8'), 'UTF-8'). | |
mb_chr($offset + mb_ord($countryCode[1], 'UTF-8'), 'UTF-8'); | |
} | |
public function configureOptions(OptionsResolver $resolver): void | |
{ | |
$resolver->setDefaults([ | |
'choice_loader' => function (Options $options) { | |
if (!class_exists(Intl::class)) { | |
throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', CountryType::class)); | |
} | |
$choiceTranslationLocale = $options['choice_translation_locale']; | |
$alpha3 = $options['alpha3']; | |
$format = $options['format']; | |
$flagPosition = $options['flag_position']; | |
return ChoiceList::loader($this, new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $alpha3, $format, $flagPosition) { | |
$countries = $alpha3 ? Countries::getAlpha3Names($choiceTranslationLocale) : Countries::getNames($choiceTranslationLocale); | |
$choices = $countries; | |
if (self::FORMAT_WITH_FLAG === $format) { | |
foreach ($countries as $countryCode => $countryName) { | |
$choices[$countryCode] = self::getFlag($countryCode); | |
} | |
} elseif (self::FORMAT_WITH_FLAG_AND_NAME === $format) { | |
$choices = []; | |
foreach ($countries as $countryCode => $countryName) { | |
$values = [self::getFlag($countryCode), $countryName]; | |
if (self::FLAG_POSITION_AFTER === $flagPosition) { | |
$values = array_reverse($values); | |
} | |
$choices[$countryCode] = sprintf('%s %s', ...$values); | |
} | |
} | |
return array_flip($choices); | |
}), [$choiceTranslationLocale, $alpha3]); | |
}, | |
'format' => self::FORMAT_WITH_NAME, | |
'flag_position' => self::FLAG_POSITION_BEFORE, | |
]); | |
$resolver->setAllowedTypes('format', ['string']); | |
$resolver->setAllowedTypes('flag_position', ['string']); | |
$resolver->setAllowedValues('format', [self::FORMAT_WITH_NAME, self::FORMAT_WITH_FLAG, self::FORMAT_WITH_FLAG_AND_NAME]); | |
$resolver->setAllowedValues('flag_position', [self::FLAG_POSITION_BEFORE, self::FLAG_POSITION_AFTER]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment