Home » Php » php – Symfony2/Twig – iterate over select options

php – Symfony2/Twig – iterate over select options

Posted by: admin July 12, 2020 Leave a comment


Usual way of displaying select field is to call

{{ form_row(form.doctor_service_id, {'attr':{'class':'form-control'}}) }}

I would like to perform two things:

  1. Check if this field is actually a select field
  2. Iterate over every option (value, name). I know how twig iterator works, I just don’t know how to access select options and cast them to it.
How to&Answers:
<select name="country"data-width="100%">
    {% for key,val in form.country.vars.choices %}
        <option value="{{ val.value }}" {{  form.country.vars.value == '' and key == 0 ? ' selected ' :(val.value == form.country.vars.value ? ' selected ' : '') }}>{{ val.label | trans }}</option>
    {% endfor %}


  1. You can use a twig extension to add a twig ‘instanceof’ operator. If you are not familiar with creating twig extensions see How to Write a Custom Twig Extension in the Symfony docs. There is a gist which gives an example of a Twig extension that implements an instanceof operator. Then to check if a field is a select field use:

      {% if value is instanceof('ChoiceType') %}
  2. This is not as straightforward as you might think because choice fields have so many options. With Symfony it is the form theme that determines how the various field types are rendered into html. The default form theme is in form_div_layout.html.twig. It takes about 50 lines of code to render a choice field taking account of all the options, covered by the blocks choice_widget, choice_widget_expanded, choice_widget_collapsed and choice_widget_options. You could pick out the bits you need based on the options you have set for your choice field and paste them into your twig template but then setting choice options in the form class wouldn’t have any affect. The correct way to custom render your choice options (*assuming the select is not expanded) is to override the choice_widget_options block from the form theme. Form Customization is a topic in itself but the simplest approach is to override the block as a one-off within your twig template and then modify it to meet your needs e.g.

    {% extends '::base.html.twig' %}
    {% form_theme form _self %}
    {%- block choice_widget_options -%}
        {% for group_label, choice in options %}
            {%- if choice is iterable -%}
                <optgroup label="{{ choice_translation_domain is sameas(false) ? group_label : group_label|trans({}, choice_translation_domain) }}">
                    {% set options = choice %}
                    {{- block('choice_widget_options') -}}
            {%- else -%}
                {% set attr = choice.attr %}
                <option value="{{ choice.value }}" {{ block('attributes') }}{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is sameas(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}</option>
            {%- endif -%}
        {% endfor %}
    {%- endblock choice_widget_options -%}
    {% block content %}
        {# ... render the form #}
        {{ form_row(form.doctor_service_id, {'attr':{'class':'form-control'}}) }}
    {% endblock %}

If you don’t need to customise the rendering of your choice field but just want to get the data to do something else with it then the best thing to do is pass the data (that is mapped to the choice field) to the twig template along with the form and use it directly. If that is not an option it is possible to iterate over the choices as in the form theme although you may need to take account of preferred choices. The simplest case would be e.g.

{% for choice in form.doctor_service_id.vars.choices %}
    {{ choice.label }}
    {{ choice.value }}
{% endfor %}