How to Extend a Field Type with Symfony

How to create a form type extension to pass variables to the view by creating custom options.
Default field types in Symfony are not enough for certain features, such as adding a specific text help to an input field, in those cases you need to extend the field to pass extra features from the form to the view.

First of all, why should you extend a field Type?

Let's say you have a radio button list in a form and you want to show them inside a table which column names depend on certain conditions.

To accomplish this you need to have a special way to pass this variable from the form to the view because the default ChoyceType is not enough to satisfy this need.

In this case we are going to pass an array with custom options to the form with the desired data.

Extend the Type Choice

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class MyExtendedChoiceType extends AbstractType
    // Here is where you pass variables to the view    
public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace($view->vars, array( 'my_options' => $options['my_options'] )); } public function setDefaultOptions(OptionsResolverInterface $resolver) { // This default value will be overwritten with the form creation
$resolver->setDefaults(array( 'my_options' => array() )); } public function getName() { return 'my_extended_choice'; } public function getParent() { return 'choice'; } }

MyExtendedChoiceType has all the properties of the Choice Type. He recognizes, however, an additional option my_options . We can pass it as an array of attributes to add. The method takes a FormView buildView first argument. The FormView vars object has a property that encapsulates an array of variables that will be directly available in the template.

Create a template for custom Form Type

The template name file is fields.html.twig

Block name must be the same as the form with the _widget sufix appended

{# AppBundle/Resources/views/Forms/fields.html.twig #}
{% block my_extended_choice_widget %}             {{ my_options[0] }}            {{ my_options[1] }}            {{my_options[2] }} {# The rest will need some more development and logic #}        {% for child in form %}
        {{ form_row(child) }}
        {{ form_label(child) }}
        {% endfor %} {% endblock %}

Register your template

    debug:            %kernel.debug%
    strict_variables: %kernel.debug%
            - 'DemoBundle:Form:fields.html.twig'

Build the Form

If you don't specify any option, then it will take those by default declared in setDefaultOptions

$form = $this->buildForm(new MyExtendedChoiceType(), null, array(
'my_options' => array('Column name 1', 'Column Name 2', 'Column name 3' ))