Create a custom form theme block with Twig

Share Button

Lire la version française

Yesterday, I wondered how to create a custom form theme block with Twig. My problem was to display two radio inputs with a specific rendering.

I didn’t find the solution in the Symfony2 documentation, but the process is easy. Let me explain :

The custom form theme block

I wanted to use the following block. As you see, in addition to the specific p element, the div and their specific classes, the big difference with the native Twig form_row method is that the radio labels are not in a label tag (but there is a label tag for the parent form field).

{# Obtao/AcmeBundle/Resources/Form/obtao_form_layout.html.twig #}
{% extends "form_div_layout.html.twig" %} {# we extends the Twig base layout as you usually do #}

{% block form_radio %}
{% spaceless %}
    <p class="checkbox-field">
        {{ form_label(form) }}
        {% for child in form %}
            <div class="radio-item">
                {{ form_widget(child) }}
                {{ child.vars.label|trans }}
            </div>
        {% endfor %}
    </p>
{% endspaceless %}
{% endblock form_radio %}

But if I use in a template like this :

{# somewhere in Obtao/AcmeBundle/Resources/views/Acme/template.html.twig #}
{{ form_radio(form.myRadioField) }}

I have the following error :
The function “form_radio” does not exist in /my/path/src/Obtao/AcmeBundle/Resources/views/Acme/template.html.twig at line XX

The solution is to tell to Twig that you want to use this new block.

Create the Twig extension

Simply create a new class that will list all your new blocks :

<?php

namespace Obtao\AcmeBundle\Twig\Extension;

class FormExtension extends \Twig_Extension
{

    public function getFunctions()
    {
        return array(
            'form_radio'   => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
        );
    }

    public function getName()
    {
        return 'obtao_form_extension';
    }
}

And do not forget to register this new extension by tagging it with twig.extension :

<!-- Obtao\AcmeBundle\Resources\config\services.xml -->
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    <services>
        <service id="obtao.form.extension" class="Obtao\AcmeBundle\Twig\Extension\FormExtension">
            <tag name="twig.extension" />
        </service>
    </services>
</container>

Now you can use your new block to render any part of a form field.
Do not forget to use your custom form theme with one of the following methods :

1) Define your theme for all the templates in config.yml :

twig:
    # ...
    form:
        resources:
            - "ObtaoAcmeBundle:Form:obtao_form_layout.html.twig"

2) Define your theme for the current template only :
{# in your template, above the form #}
{% form_theme form 'ObtaoAcmeBundle:Form:obtao_form_layout.html.twig' %}

Share Button

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Protected by WP Anti Spam