Question

Politics aside, I need to provide Kosovo as a form choice when selecting a country.

What's the most elegant way of doing this with Symfony's built-in form choice type country, while also providing translations for the Kosovo name?

Here's what I've done so far and it works but I'm concerned this might be a bit hack-ish.

<?php

namespace Acme\Bundle\DemoBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Intl\Intl;

class LocationType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Kosovo is not listed as a choice provided by the method call
        // `Symfony\Component\Intl\Intl::getRegionBundle()->getCountryNames()`
        // although it is mostly recognized as in independent state, including by Google Maps.
        // This is because no ISO 3166-1 alpha-2 code as been assigned to that country.
        // However, a temporary code 'XK' is available.

        $countries = Intl::getRegionBundle()->getCountryNames();
        $countries['XK'] = "Kosovo";

        $builder
            ->add('country', 'country', array(
                'choices' => $countries,
                'preferred_choices' => array(
                    'XK', // Kosovo
                    'AL', // Albania
                    'MK', // Macedonia
                    'ME', // Montenegro
                    'GB', // United Kingdom
                    'US', // United States
                ),
            ))
            ->add('district', 'text', array('required' => false))
            ->add('town', 'text', array('required' => false))
        ;
    }
}
Was it helpful?

Solution

You should create your service, in wich you use Intl's static method (like above) and add your custom countries. Then, inject that service into your form type. Or (even better), define your custom type (something like "MyCountry") and use it instead of standard country one.

OTHER TIPS

I also needed to add Kosovo to a list of countries for my project, and no answers in this thread were useful. I came up with a working solution for Symfony 5:

In your twig, you should have a form, and the country form field should be rendered as follows:

{{ form_row(form.field_country, {'attr': {'novalidate': 'novalidate', 'class' : 'novalidate' }}) }}

In the Controller, this field is created as follows:

->add('field_country', CountryType::class, ['label' => '*Country', 'required' => false  ])

If the above is not clear, please consult Symfony documentation for form creation/processing.

Now you have to find a file called "CountryType.php". Finding it might be tricky because it is buried pretty deep, and in my case it is the following location:

vendor -> symfony -> form -> Extension -> Core -> Type -> CountryType.php

Find the following line:

return array_flip($alpha3 ? Countries::getAlpha3Names($choiceTranslationLocale) : Countries::getNames($choiceTranslationLocale) );

This line is what generates the full array of countries that CountryType::class uses.

This return statement needs to be modified so that it gives you a new expanded list of countries that also includes Kosovo. To do that, you need to get the associative array of countries, slice it at location 188 (letter K), insert Kosovo, and the merge the array again.

To achieve the above, replace the whole code for IntlCallbackChoiceLoader function with this:

  return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $alpha3) {

//Get list of courtries from the API with array keys given with 3 letters
$countriesByAlpha3 = Countries::getAlpha3Names($choiceTranslationLocale);
//Splice the original array, insert Kosovo in correct alphabetical order with a 3 letter key, and merge the array again
$countriesByAlpha3 = array_merge(array_slice($countriesByAlpha3, 0, 118), array('XKX' => 'Kosovo'), array_slice($countriesByAlpha3, 118));

//Get list of courtries from the API with array keys given with 2 letters
$countriesByName = Countries::getNames($choiceTranslationLocale);   
//Splice the original array, insert Kosovo in correct alphabetical order with a 2 letter key, and merge the array again     
$countriesByName = array_merge(array_slice($countriesByName, 0, 118), array('KX' => 'Kosovo'), array_slice($countriesByName, 118));
          
               // return array_flip($alpha3 ? Countries::getAlpha3Names($choiceTranslationLocale) : Countries::getNames($choiceTranslationLocale) );
return array_flip( $alpha3 ?  $countriesByAlpha3 :  $countriesByName   );


            });
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top