Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 Formbuilder auto escaping?

Tags:

php

twig

symfony

I have a hard space ( ) inside some of my choice options. Somehow, somewhere, they are being escaped. I have tried:

{% autoescape false %}
    {{ form_widget(foobar) }}
{% endautoescape %}    

As well as

{{ form_widget(foobar)|raw }}

And the following under Twig in config.yml

autoescape: false

Yet the choice fields are still rendered as  Choice Text Here instead of Choice Text Here, and in the source they are being encoded as  Choice Text Here

In the controller I have:

$form   ->add('foo', 'choice', array(
            'label' => 'Foo Label',
            'choices'  => $fooChoices,
            'required' => true));
$form = $form->getForm();
$foobar = $form->createView();

If I print_r $fooChoices I get:

Array ( [1] =>  60# FooBar [5] =>  60# BatBar [11] =>  60# DooWop )

Which shows me the proper   (note the double space in front of the 60's). Somewhere between the FormBuilder and the rendering, it is getting escaped.

Is there built-in escaping inside the Form Builder?

What I have deduced is that through the point that the form view is rendered via $form->createView() the data is still unescaped. But, by the time it reaches Twig via form_widget, it has been escaped. Doing form_widget(foobar)|raw shows this.

Edit: I have added a workaround as an answer, but I'm still interested in accepting an answer that explains how to prevent the initial escaping from occurring altogether.

like image 874
Nick Avatar asked Jul 02 '12 22:07

Nick


3 Answers

I ran into the same problem with radio labels. This solves it.

{% for child in form %}

  {% autoescape false %}
    {{ child.vars.label }}
  {% endautoescape %}

  {{ form_widget(child) }}

{% endfor %}
like image 60
Ben Routson Avatar answered Nov 13 '22 00:11

Ben Routson


I've ended up creating a Twig extension that decodes encoded HTML and added it as a service:

The extension in Vendor/Bundle/Extensions/Twig

namespace Vendor\Bundle\Extensions\Twig;

class HTMLDecodeTwigExtension extends \Twig_Extension 
{

    public function getFilters()
    {
        return array(
            'htmldecode' => new \Twig_Filter_Method($this, 'htmldecode', array(
                'is_safe' => array('html'))
            ),
        );
    }

    // your custom function
    public function htmldecode($string)
    {
        return html_entity_decode($string);
    }

    // Name for Service
    public function getName()
    {
        return 'html_decode_twig_extension';
    }
}

Registering the service in Vendor/Bundle/Resources/config/services.yml

vendor_bundle.htmldecode:
    class:  Vendor\Bundle\Extensions\Twig\HTMLDecodeTwigExtension
    tags:
      - { name: twig.extension }

The usage:

{{ form_widget(foobar)|htmldecode }}

I still don't know where the escaping is being performed, as it is only performed on the data itself (and I tried creating a data event to modify the form's data), but this at least gives me the end result I'm looking for.

like image 4
Nick Avatar answered Nov 13 '22 00:11

Nick


What you really should be doing is over-riding the form_label template

{% block form_label %}
{% spaceless %}
    {% if label is not sameas(false) %}
        {% if not compound %}
            {% set label_attr = label_attr|merge({'for': id}) %}
        {% endif %}
        {% if required %}
            {% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
        {% endif %}
        {% if label is empty %}
            {% set label = name|humanize %}
        {% endif %}
        {% autoescape false %}<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>{% endautoescape %}
    {% endif %}
{% endspaceless %}
{% endblock form_label %}

Note the addition of the autoescape sections.

like image 3
juz Avatar answered Nov 12 '22 23:11

juz