Finally Through Symfony2 Forms and Collectiontype Make It Dynamic

It’s been quite a road to understand the symfony2 CollectionType, and to make it work the way I wanted!

This article will be brief (I’ll try at least) and will not explain a lot because this reflexion started 3 articles ago so all the information on why things are made like this, why is my code like that etc… can be understood through those articles:

  1. Form composition in symfony2
  2. First shot at the collection field
  3. Something is broken?

Part of the solutions are in the comments too.

Why make a collection?

First things first: When do you want to use the collection field? Any time you need to add an unknown number of fields to a form. This means anytime you need to add an unknown number of related entities to your “core” entity in my case. Good examples are:

  • Holes on a golf course (9? or 18?)
  • Tags on a blog article or on a product
  • Actors on a movie
  • Toppings on a pizza

The use for collection field is when you want to set all those things and the “core” entity at the same time. You don’t want your user to first chose a pepperoni pizza, then validate, go to the next screen add toppings. You want him to create a pepperoni pizza with toppings right away.

Here I made a small ProductBundle where I save products that have tags (like ‘shoes’, ‘blue’, ‘winter’, ‘fashionable’, ‘ugly’, …) The complete bundle code is here.

How to make a collection

In the backend

Read the previous article: Something is broken?

In the frontend

If we’re adding this many fields without knowing how many there will be, we need a dynamic frontend. We need to use some javascript to add and remove some fields as we see fit when filling that form.

Remember we used the prototype = true option here because this will allow us to have a prototype version for the tag fields that we can add to our html and then submit. Also remember that until now we did add 3 empty tags in the controller in order to have a non-empty collection. The controller now becomes this as we don’t need to have any tags at first.

Adding fields

In my case, the name for TagType was: khepin_productbundle_producttype_tags (auto generated and I didn’t change it, probably not the best). This means that when I output my form, I have a div with this as an id. And it’s this div that has a ‘data-prototype’ attribute containing the html of the tag fields with a generic ‘$$name$$’ in them that needs to be replaced before inserting into the final html.

We add an ‘Add Tag’ link which when clicked will add a tag field to our html page. In twig new.html.twig:

I am using jQuery for the javascript that will add the fields. The script is pretty simple:

The add function:

  • Finds the div holding our fields for the collection
  • Gets the data prototype
  • Replaces all instances of $$name$$ in the prototype with a number (current number of elements in the collection. Since they start numbering at 0, we always have one more).
  • Adds the resulting html to the div holding the collection

The rest of the script only subscribes the link’s click to activate the “add” function, and prevents the link from actually doing anything.

Now you can add an infinite number of tags to your Product and save all of them at the same time!