Symfony2 - FormBuilder - add a class to the field

2019-03-09 10:47发布

I want to add a class to certain input or label fields from within symfony2.

I can do something like this in my form within Twig:

<div class="row">
    {{ form_label(form.subject) }}
    {{ form_widget(form.subject, { 'attr': {'class': 'c4'} }) }}
</div>

Which works fine. But I have to setup the template for every form. And I have to break it down to the smallest possible output level. I actually want to use:

 {{ form_widget(form) }}

So, I was thinking, how could I add a css class for the l somewhere in:

class SystemNotificationType extends AbstractType {
    public function buildForm(FormBuilder $builder, array $options) {
        $builder    ->add('subject', 'text', array( 'label'  => 'Subject' ) )
–

I thought this might be more useful, as I only have to make changes on one place.

So how could this be done, or maybe I'm thinking the wrong way.

Any help would be great,

Many thanks, Philipp

3条回答
Juvenile、少年°
2楼-- · 2019-03-09 10:57

Form Theming


Every part of how a form is rendered can be customized. You're free to change how each form "row" renders, change the markup used to render errors, or even customize how a textarea tag should be rendered. Nothing is off-limits, and different customizations can be used in different places.

Symfony uses templates to render each and every part of a form, such as label tags, input tags, error messages and everything else.

In Twig, each form "fragment" is represented by a Twig block. To customize any part of how a form renders, you just need to override the appropriate block.

In PHP, each form "fragment" is rendered via an individual template file. To customize any part of how a form renders, you just need to override the existing template by creating a new one.

To understand how this works, customize the form_row fragment and add a class attribute to the div element that surrounds each row. To do this, create a new template file that will store the new markup:

{# src/Acme/TaskBundle/Resources/views/Form/fields.html.twig #}
{% block form_row %}
{% spaceless %}
<div class="form_row">
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}

The form_row form fragment is used when rendering most fields via the form_row function. To tell the form component to use your new form_row fragment defined above, add the following to the top of the template that renders the form:

{# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #}
{% form_theme form 'AcmeTaskBundle:Form:fields.html.twig' %}
{% form_theme form 'AcmeTaskBundle:Form:fields.html.twig'
'AcmeTaskBundle:Form:fields2.html.twig' %}
{{ form(form) }}

The form_theme tag (in Twig) "imports" the fragments defined in the given template and uses them when rendering the form. In other words, when the form_row function is called later in this template, it will use the form_row block from your custom theme (instead of the default form_row block that ships with Symfony).

Your custom theme does not have to override all the blocks. When rendering a block which is not overridden in your custom theme, the theming engine will fall back to the global theme (defined at the bundle level).

If several custom themes are provided they will be searched in the listed order before falling back to the global theme.

To customize any portion of a form, you just need to override the appropriate fragment. Knowing exactly which block or file to override is the subject of the next section.

{# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #}

{% form_theme form with 'AcmeTaskBundle:Form:fields.html.twig' %}

{% form_theme form with ['AcmeTaskBundle:Form:fields.html.twig',
'AcmeTaskBundle:Form:fields2.html.twig'] %}

For more information see the How to customize rendering in Symfony cookbook

Global Form Theming


In the above example, you used the form_theme helper (in Twig) to "import" the custom form fragments into just that form. You can also tell Symfony to import form customizations across your entire project.

Twig

To automatically include the customized blocks from the fields.html.twig template created earlier in all templates, modify your application configuration file:

# app/config/config.yml
  twig:
    form:
      resources:
        - 'AcmeTaskBundle:Form:fields.html.twig'

Any blocks inside the fields.html.twig template are now used globally to define form output.

查看更多
贼婆χ
3楼-- · 2019-03-09 11:08

The class of a field is part of the presentation layer of your application, so it is best to create a twig theme for your forms:

Create a file fields.html.twig in Resources/views/Form of your Bundle and define how your form row will be formated, for example:

{% block field_row %}
<div class="row">
    {{ form_errors(form) }}
    {{ form_label(form) }}
    {{ form_widget(form, { 'attr': {'class': 'c4'} }) }}
</div>
{% endblock field_row %}

If you want to customize only certain field, for example the field fieldName of the form formName, customize the row:

{% block _formName_fieldName_row %}
<div class="row">
    {{ form_label(form) }}
    {{ form_errors(form) }}
    {{ form_widget(form, { 'attr': {'class': 'c4'} }) }}
</div>
{% endblock %}

EDIT: customize only the field:

{% block _formName_fieldName_widget %}
    {% set type = type|default('text') %}
    <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" class="c4" />
{% endblock %}

Then in all the form templates you want it use this theme add:

{% form_theme form 'MyBundle:Form:fields.html.twig' %}

This is explained in depth in the cookbook

查看更多
姐就是有狂的资本
4楼-- · 2019-03-09 11:09

You can do it like this:

class SystemNotificationType extends AbstractType {
    public function buildForm(FormBuilder $builder, array $options) {
        $builder->add('subject', 'text', array( 
            'label'  => 'Subject',
            'attr'   =>  array(
                'class'   => 'c4')
            )
        );
    }
}
查看更多
登录 后发表回答