How to extend form fields in Symfony2 using extensions
Toni UebernickelUpdate: For Symfony2.1 update please take a look at the updated post.
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 FormType
s.
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 FormType
s 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
tag
is required so the service gets injected at the correct points. To add aFormTypeExtension
, the tagform.type_extension
is defined. - As mentioned there are several types of extensions, so another specification is required.
To have the extension being applied on fields, the
alias
will 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.