A panoramic, light blue background with abstract shapes and the Symfony logo, depicting a sleek and modern environment for Symfony web development.

Symfony Associative Array Form Type

12/12/2022

Among the advantages of Symfony, flexibility, and ease of customization are often mentioned. And when it turns out that something can't be done easily, another advantage of this framework comes to the rescue – community support. From time to time I get help from other developers working with Symfony so today is my turn to provide you with a ready-made solution. After all, karma comes back, right? Here's a simple tutorial to create an associative array form type in Symfony.

Some time ago, I was given a task that required creating a form field for editing a property, which was an associative array. To my surprise, Symfony does not present a ready solution for such a case! Since you are reading this article, you may have also encountered this problem. Wanting to save you time, I have prepared a short step-by-step tutorial, which you can find below. I hope you will find it helpful.

1. Create a new FormType for a single array row

In this step, you should add a collection form field in order to keep the array index and value in the respective child forms of the collection form. Let’s first create the new form type, which represents a single key ➡ value row of the array:

class AssociativeArrayItemType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options): void
   {
       $builder
           ->add('key', TextType::class)
           ->add('value', TextType::class)
      ;
   }
}

2. Use the newly created FormType

Now, let's create a form type representing our associative array and use the newly created type as a single entry:

class AssociativeArrayType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options)
   {
       $builder->add('items', CollectionType::class, [
           'entry_type' => AssociativeArrayItemType::class,
           'label' => false,
       ]);
   }
}

3. Add Model transformers

The visual representation is ready. Now you need to implement transforming the associative array into displayable rows and back into the associative array after submit:

class AssociativeArrayType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options)
   {
       ...
       $builder->addModelTransformer(new CallbackTransformer(
           function ($associativeArrayData) {
               $associativeArrayData = $associativeArrayData ?? [];
               $newData = [];
               foreach ($associativeArrayData as $key => $value) {
                   $newData['items'][] = [
                      'key' => $key,
                      'value' => $value
                   ];
              }
              return $newData;
           },
           function ($dtoData) {
               $newData = [];
               foreach ($dtoData['items'] as $item) {
                   $newData[$item['key']] = $item['value'];
               }
               return $newData;
           }
       ));
   }
}

4. Use your new associative array FormType

Now you’re ready to use the new FormType, and you will be easily able to edit associative array data!

class PlanInstallForm extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options)
   {
       ...
      
       $builder
           ->add('handler', ChoiceType::class, [
               'choices' => $handlerChoices,
               'placeholder' => '--- choose handler ---'
           ])
           ->add('params', AssociativeArrayType::class)
       ;
   }
}

5. Customize your AssociativeArrayType

Now, what if you wanted to be able to customize the types of fields that your key and value are? For example, you want the keys to be a ChoiceType with values specified by yourself. Just make it possible to pass it as an option. Do the same with the options of the corresponding field. Let’s configure the array row form, so it is able to receive the mentioned options:

class AssociativeArrayItemType extends AbstractType

{
   public function buildForm(FormBuilderInterface $builder, array $options): void
   {
       $builder
           ->add('key', $options['key_field_type'], $options['key_field_options'])
           ->add(
               'value',
               $options['value_field_type'],
               $options['value_field_options']
           )
       ;
   }
   public function configureOptions(OptionsResolver $resolver): void
   {
       $resolver->setDefaults([
           'key_field_type' => TextType::class,
           'value_field_type' => TextType::class,
           'key_field_options' => [],
           'value_field_options' => [],
       ]);
   }
}

Now let’s make sure, that your main FormType also receives and passes these options down to the children forms:

class AssociativeArrayType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options)
   {
       $builder->add('items', CollectionType::class, [
           'entry_type' => AssociativeArrayItemType::class,
           'entry_options' => $options['item_options'],
           'label' => false,
       ]);
      ...
   }
   public function configureOptions(OptionsResolver $resolver): void
   {
       $resolver->setDefaults([
           'item_options' => [
               'key_field_type' => TextType::class,
               'value_field_type' => TextType::class,
               'key_field_options' => [],
               'value_field_options' => [],
           ],
       ]);
   }
}

Now in order to make the key field a choiceType, you need to pass the desired type and choices in options when using our new FormType:

class PlanInstallForm extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options)
   {
       ...
       $builder
           ->add('handler', ChoiceType::class, [
               'choices' => $handlerChoices,
               'placeholder' => '--- choose handler ---'
           ])
           ->add('params', AssociativeArrayType::class, [
               'item_options' => [
                   'key_field_type' => ChoiceType::class,
                   'key_field_options' => [
                       'choices' => $paramsChoices,
                   ],
               ],
           ])
       ;
   }
}

6. Allow adding and removing items to the form

I have described how to create a FormType, that automatically handles adding and removing items to a CollectionType in another article:

All you need to do is create the CustomCollectionType and use it instead of the regular CollectionType in your form! Otherwise, you can handle this use case with regular javascript according to the Symfony docs:

Łu
Portret Łukasza Traczyka, back-end developera w Primotly, profesjonalisty o swobodnym i przystępnym usposobieniu, ubranego w jasnoniebieską koszulę.
Łukasz Traczyk
Back-end Developer

Najnowsze artykuły

Obraz koncepcyjny ukazujący kontrast między technologią AI a emisjami środowiskowymi, z symbolem mikroprocesora dla AI i chmurami symbolizującymi emisję CO2 nad budynkami przemysłowymi.

Innovations | 22/11/2024

Jak sztuczna inteligencja pomaga firmom śledzić emisje CO2?

Bernhard Huber

Rozliczanie emisji dwutlenku węgla, praktyka śledzenia, pomiaru i raportowania emisji gazów cieplarnianych (GHG) to tematy, które coraz częściej pojawiają się nie tylko w kontekście dbania o środowisko, ale też odpowiedzialności biznesu. Ponieważ 90% firm z listy Fortune 500 zobowiązało się do realizacji celów zrównoważonego rozwoju, zapotrzebowanie na skuteczne rozwiązania w zakresie rozliczania emisji dwutlenku węgla rośnie. Jednak firmy często zmagają się ze złożonymi łańcuchami dostaw i brakiem danych w czasie rzeczywistym, co sprawia, że dokładne rozliczanie emisji dwutlenku węgla jest trudnym zadaniem. Wygodne rozwiązanie podsuwa sztuczna inteligencja. Oferuje ona potężny zestaw narzędzi do automatyzacji i optymalizacji śledzenia emisji oraz identyfikowania nieefektywności.

Szczegóły
Grafika symbolizująca ład korporacyjny w kontekście ESG

Business | 15/11/2024

Czym jest ład korporacyjny w kontekście ESG?

Łukasz Kopaczewski

Podczas gdy wszystkie trzy filary - środowiskowy, społeczny i ład korporacyjny - są niezbędne, ład korporacyjny często odgrywa najbardziej fundamentalną rolę. Zarządzanie, które obejmuje etyczne przywództwo, przejrzystość i odpowiedzialność, zapewnia, że wysiłki ESG nie są tylko deklaracjami na papierze, ale są zintegrowane z codziennymi decyzjami firmy. Warto zauważyć, że niedawne badanie wykazało, że 39% firm uważa, że osiąga odpowiednie wyniki w zakresie zarządzania, co wskazuje na znaczne możliwości poprawy.

Szczegóły
Ilustracja do artykułu o wykorzystaniu sztucznej inteligencji (AI) w biznesowych procesach decyzyjnych w przedsiębiorstwie

Business | 08/11/2024

Wykorzystanie sztucznej inteligencji (AI) w biznesowych procesach decyzyjnych w przedsiębiorstwie

Agata Pater

Poleganie wyłącznie na intuicji w biznesie może często oznaczać utratę dużych możliwości. Najlepszym przykładem jest Netflix. Analizując ponad 30 milionów dziennych „odtworzeń” oraz niezliczone oceny i wyszukiwania subskrybentów, Netflix dokładnie określił, czego chcą widzowie, co doprowadziło do stworzenia hitowych seriali, takich jak House of Cards. To podejście nie tylko zwiększyło zaangażowanie widzów; zrewolucjonizowało podejście branży rozrywkowej do tworzenia treści.

Szczegóły