Styling and Customising Using Form Fragments


In this video we are going to look at form fragments, which in itself doesn't sound very exciting at all.

The good news is - pretty much no one actually calls these things form fragments. You are very unlikely to be having a conversation about Symfony where the term 'form fragment' comes up, at all.

But if you are using Symfony's form and Twig, then you are going to be using form fragments even if you don't realise it, or call them by their Sunday name.

So far we have been able to render out a fully Bootstrap 3 styled form using an incredibly small amount of code:

<!-- app/Resources/views/form-example/index.html.twig -->

    {{ form_start(form) }}
    {{ form_widget(form) }}
    {{ form_end(form) }}

And it's even possible to shorten this down further to just:

    {{ form(form) }}

This is an amazing time saver, particularly on smaller / simpler forms where extra customisation is not required.

But, if you are at all inquisitive about how the heck this transforms from a single helpful little template element into a full blown form, you are likely to be left with the same questions I had when I first started using Symfony's form - how is {{ form(form) }} producing a fully featured, well styled form for me?

Now, with a decent IDE like PHPStorm, you can ctrl+click (or cmd+click) on the vast majority of 'things' in your code, and be taken to underlying definition. This is an incredibly useful feature, and something I use on a daily basis. However, when it comes to Twig templates, you can't ctrl+click on pretty much anything. This makes it harder to understand how things are working, and where this code lives.

If you have been following along, you will recall that back in the first video in this series we set up our project to use the Bootstrap 3 horizontal layout form theme:

# app/config/config.yml

# Twig Configuration
twig:
    form_themes:
        - 'bootstrap_3_horizontal_layout.html.twig'

Again, we started using this theme without covering where this template / theme / code is actually coming from.

When we installed Symfony, we gained many new files and directories in our vendors/ directory. One of those folders is:

vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form

Quite the mouthful. I have no idea how you are supposed to know this without quite a bit of searching.

Inside this directory are - at the time of writing - 5 twig templates:

  • bootstrap_3_horizontal_layout.html.twig
  • bootstrap_3_layout.html.twig
  • form_div_layout.html.twig
  • form_table_layout.html.twig
  • foundation_5_layout.html.twig

The most important of the five would be the form_div_layout.html.twig, which is the default layout - the one in use unless we specifically tell Symfony otherwise.

We changed our template to be bootstrap_3_horizontal_layout.html.twig, which if you open up the file will find use's bootstrap_3_layout.html.twig, which in turn use's form_div_layout.html.twig.

So, we have this inheritence / override structure going on. Very similar to how we use extend in our own Twig templates.

This is cool, and the basis of what we need to know.

This can then answer our question - why does using {{ form(yourFormNameHere) }} render out a full form for us?

{%- block form -%}
    {{ form_start(form) }}
        {{- form_widget(form) -}}
    {{ form_end(form) }}
{%- endblock form -%}

Direct link to the code.

Behind the scenes, Symfony will look for the form fragment named form, which lives inside our form_div_layout.html.twig. This contains the other form helper methods that we were previously calling explicitly in our template (from the very first example in this write up).

But what is less intuitive is that form_end actually does a little more than the other tags:

{%- block form_end -%}
    {%- if not render_rest is defined or render_rest -%}
        {{ form_rest(form) }}
    {%- endif -%}
    </form>
{%- endblock form_end -%}

We can see here that our form_end fragment is going to render anything that hasn't yet been rendered. This is a really nice catch all statement - and is amongst other things, how we end up with a nice CSRF token added to our form without us having to explicitly add it in our template.

There are obviously quite a few twig helper methods, and associated styling form fragments that you could use in any particular project. There's no way I could feasibly cover them all. Instead, I hope this helps you understand where to start looking when customising your form rendering. This was a big question I had when working with Symfony and Twig, so hopefully this has saved you just that little bit of time.

Further Reading

The following links may be helpful to you in furthering your understanding of this topic:

Code For This Course

Get the code for this course.

Episodes