How to extend form fields in Symfony2 using extensions
published on
In case you have read the form documentation, you will have noticed, that the example won’t work out of the box.
{% block field_widget %}
{{ block('base_field_widget') }}
{% if help is defined %}
<span class="help">{{ help }}</span>
{% endif %}
{% endblock %}
What are form extensions?
Put simple form extensions are classes providing additional options, services, behaviors or in general: extensions on the form component of Symfony2. There are several extension types available, such as validators, data transformers and types. The FormTypeExtensionInterface specifies an interface to extend FormTypes. A FormType is a class representation of a form input, being it a simple text field or a more complex date input containing several inputs.
So, in order to be able to apply a help message to existing FormType a FormTypeExtension is required. The following code illustrates a possible implementation of a HelpMessageTypeExtension. It’s very basic, it allows to set a help option, which was not found. The option - or attribute on the builders side - gets defined and defaults to null. The getExtendedType method defines on which FormTypes this extension may be applied. To allow every FormType be extended by this extensions, it return field the base FormType.
<?php
namespace Acme\Bundle\DemoBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormBuilder;
class HelpMessageTypeExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->setAttribute('help', $options['help']);
}
public function buildView(FormView $view, FormInterface $form)
{
$view->set('help', $form->getAttribute('help'));
}
public function getDefaultOptions(array $options)
{
return array(
'help' => null,
);
}
public function getExtendedType()
{
return 'field';
}
}
?>
Dependency Injection
Now that the extension is defined, and will be found by the autoloader, it’s required to register it with the framework. To achieve this task, it’s only one service definition that’s missing.
Important for this definition are two things.
- A
tagis required so the service gets injected at the correct points. To add aFormTypeExtension, the tagform.type_extensionis defined. - As mentioned there are several types of extensions, so another specification is required. To have the extension being applied on fields, the
aliaswill befield.
services:
form.type_extension.help_message:
class: Acme\Bundle\DemoBundle\Form\Extension\HelpMessageTypeExtension
tags:
- { name: "form.type_extension", alias: "field" }
Example Form
Now that the extension is written and made available to the Form component of Symfony2, the help option is available - see the example form built below.
<?php
$form = $this->createFormBuilder()
->add('name', 'text', array(
'help' => $this->trans('form.demo.name.help'),
))
->add('birthday', 'birthday', array(
'help' => $this->trans('form.demo.birthday.help'),
'attr' => array('class' => 'small'),
))
->add('email', 'email')
->getForm();
?>
Note: $this->trans() is a shortcut method calling trans() on the translator service.
Using Twitter Bootstrap this is how it would look like.
