fabtosz fabtosz - 5 months ago 36
PHP Question

Symfony Custom Field or Dynamic Form?

I'm asking you for a litte advice in creating specific form in Symfony 3.

After reading Symfony Docs I have some solution in mind, but I'm asking you for sharing best aproach to achieve this.

I need to get output form like this: link for expected example form

As you see i need to make single field constiting of one checkbox and one input type. It should work like if user ticks the checkbox, the input will be active.

Should it be custom field with getParent() method from FormType as parent? Maybe this form should be created dynamically with event listener and some Javascript? Or it should be CollectionType field (but how it can store two different form field types?) or maybe you know different solution?

Basically one field should consist of two different field type depending from each other.

Any help, sharing knowledge or some code examples will be very welcome.

Answer Source

First, you have to build a custom FormType that composes a CheckboxType and a TextType. This is the server-side form part.

But, in order to enable/disable the text field on the fly, you'll have to use Javascript.

Finally, if you want to store the result information a single nullable text field (like a nullable varchar), you need a DataTransformer to convert data from persistece layer to view.

Let's see a kind of FormType :


namespace Form\Type;

use Form\DataTransformer\NullableTextTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class NullableTextType extends AbstractType
    public function buildForm(FormBuilderInterface $builder, array $options)
            ->add('isNotNull', CheckboxType::class)
            ->add('text', TextType::class, array('required' => false))

        $builder->addModelTransformer(new NullableTextTransformer());

And now the transformer :


namespace Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

class NullableTextTransformer implements DataTransformerInterface
    public function transform($value)
        $nullableText = ['isNotNull' => false, 'text' => null];

        if (null !== $value) {
            $nullableText['isNotNull'] = true;
            $nullableText['text'] = (string) $value;

        return $nullableText;

    public function reverseTransform($array)
        if (!is_array($array) || empty($array) || !isset($array['isNotNull']) || !isset($array['text'])) {

        if ($array['isNotNull']) {
            return (string) $array['text'];
        } else {

Some twig for the form theming of the custom field :

{% block nullable_text_widget %}
{% spaceless %}
  <div class="input-group nullable-text-widget">
    <div class="input-group-addon">
      {{ form_widget(form.isNotNull, {attr: {class: 'is-not-null-widget'}}) }}
    {{ form_widget(form.text, {attr: {class: 'text-widget'}}) }}
{% endspaceless %}
{% endblock nullable_text_widget %}

And finally, a bunch of JS lines to handle the front interactions :

$(document).ready(function() {
    $.each($('body').find('.nullable-text-widget'), function () {

$(document).on('click', '.nullable-text-widget .is-not-null-widget', function (e) {
    var $nullableTextWidget = $(e.currentTarget).parents('.nullable-text-widget');

function syncNullableTextWidget($widget)
    if ($widget.find('.is-not-null-widget').prop('checked')) {
        $widget.find('.text-widget').prop('disabled', false);
    } else {
        $widget.find('.text-widget').prop('disabled', true);