0
votes

I came across to a problem regarding Twig's escaping in Symfony2.

The problem

I'm currently using Symfony's form builder to create a form for managing the categories of my project. My current code for creating the form is the following:

$Form
    ->add('title', 'text', array('label' => 'Title', 'attr' => array('class' => 'span8')))
    ->add('parent', 'entity', array(
        'label' => 'Category',
        'attr' => array('class' => 'selectPicker span8'),
                'property' => 'indentedTitle',
                'empty_value' => ' -- New Category --',
                'required' => false,
                'class' => 'News\Entity\Category',
                'query_builder' => function(EntityRepository $Repository) {
                    return $Repository->createQueryBuilder('c')
                            ->orderBy('c.root, c.left');
                    }
                ))
    ->add('commit', 'submit', array('label' => 'Save', 'attr' => array('class' => 'btn btn-info')));

The callback that I added in my Entity "indentedTitle" simply adds two lines before the title, depending on the category level in the tree set.

public function getIndentedTitle() {
    return str_repeat("--", $this->level) . $this->title;
}

So far everything works fine, except that when I try to add some HTML code to modify a bit the category name that I output in my select list, it get automatically escaped. For example you can see that I added a simple &nbsp tag next to the "empty_value" key in my Form Builder. So as a result I get "&nbsp -- New Category --" as first option in my select list.

What I tried

  1. Twig autoescape

    {% autoescape false %}
        {{ form_row(form.parent) }}
    {% endautoescape %}
    
  2. Twig extension

I tried writing custom Twig extension, with the single purpose of escaping(html_decode) the whole Set of Object I passed to it - still no good. Unfortunately I did not save my code to paste it here, so I will provide a link where another user proposed the same method as I did(it's for JSON actually, but the concept is the same). link to SO answer

So, to put it simple as my final thought - What do I have to do, in order to use some HTML like "strong" or "&nbsp" in my select list without getting it escaped?

Thanks in advance.

1
you should do this {{ htmlvar|raw }} the raw will print the html correctacrobat
Yes, I forgot to mention that as well. I did set |raw - still the same output.Artamiel

1 Answers

1
votes

Maybe option groups are a better choice in this case?

You could try customizing that individual form field in twig. You essentially create a block in your template with a special name and custom the display in since of it.

The block naming convention is _{field_id}_row and _{field_id}_widget. So something like this:

{% block _parent_widget %}
    {# spit out the select field here with whatever you need #}
{% endblock %}

Look at the Twig bridge code to see how you might output a select:

{% block choice_widget_collapsed %}
{% spaceless %}
    {% if required and empty_value is none and not empty_value_in_choices %}
        {% set required = false %}
    {% endif %}
    <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
        {% if empty_value is not none %}
            <option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ empty_value|trans({}, translation_domain) }}</option>
        {% endif %}
        {% if preferred_choices|length > 0 %}
            {% set options = preferred_choices %}
            {{ block('choice_widget_options') }}
            {% if choices|length > 0 and separator is not none %}
                <option disabled="disabled">{{ separator }}</option>
            {% endif %}
        {% endif %}
        {% set options = choices %}
        {{ block('choice_widget_options') }}
    </select>
{% endspaceless %}
{% endblock choice_widget_collapsed %}

{% block choice_widget_options %}
{% spaceless %}
    {% for group_label, choice in options %}
        {% if choice is iterable %}
            <optgroup label="{{ group_label|trans({}, translation_domain) }}">
                {% set options = choice %}
                {{ block('choice_widget_options') }}
            </optgroup>
        {% else %}
            <option value="{{ choice.value }}"{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice.label|trans({}, translation_domain) }}</option>
        {% endif %}
    {% endfor %}
{% endspaceless %}
{% endblock choice_widget_options %}

Then you tell twig that the current template is also a form theme:

{% form_theme your_form_name _self %}