Discuss your project
PHP symfony Sonata

Symfony 4 / Sonata: create a custom form field type

We are going to see how we can create a custom field type. In our example, we want a field that has the same rendering as a MoneyType field but in which we can add any suffix, as the money field only accepts currencies. However, in our project we want to us...

Symfony 4 / Sonata: create a custom form field type

We are going to see how we can create a custom field type.

In our example, we want a field that has the same rendering as a MoneyType field but in which we can add any suffix, as the money field only accepts currencies.

However, in our project we want to use kilograms, months or even kilometers. In short, a whole range of possible data types.

We start by creating our Type class:

<?php 
// src/Form/Type/NumberSuffixType.php
namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\Form\FormView;

class NumberSuffixType extends AbstractType
{
    public function getParent()
    {
        return NumberType::class;
        //return TextType::class;
    }
    
    public function configureOptions(OptionsResolver $resolver)
    {
    
        $resolver->setDefaults([
            'suffix' => 'suffix',
            'field_options' => [],
        ]);
    
    }
    
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['field_name']=$form->getName();
        $view->vars['data']=$form->getData();
        $view->vars['suffix']=$options['suffix'];
        $view->vars['type'] = 'number';
        $view->vars['attr']['class'] = 'number_suffix';
    
    }
    
    public function getBlockPrefix()
    {
        return 'number_suffix';
    }
    
    
}

?>

Then we add our template

{# templates/Adminform/number_suffix_type.html.twig #}
{% block number_suffix_widget %}
    {% spaceless %}
       <div class="input-group">
                {{- block('form_widget_simple') -}}
                {% if suffix is not empty %}
                	<span class="input-group-addon"> {{ suffix }}</span>
                {% endif %}
                
            </div>
    {% endspaceless %}
{% endblock %}

We have to register our template

# config/packages/twig.yaml
twig:
    form_themes:
        - 'Admin/form/number_suffix_type.html.twig'

Additionally, we add a CSS rule to remove the arrows from the HTML5 numeric field.
To do this, we must reference a CSS file in the admin

sonata_admin:
    assets:
        extra_stylesheets:
            - css/admin.css

And we add our directive in our CSS file

input[class*="number_suffix"] {
    -moz-appearance: textfield;
}
input[class*="number_suffix"]:hover,
input[class*="number_suffix"]:focus {
    -moz-appearance: number-input;
}

Then it's just a matter of using it like this:

            ->add('dureePossible1', NumberSuffixType::class, ['label'=>'Durée possible 1','suffix'=>'Mois','required'   => false])
            ->add('dureePossible2', NumberSuffixType::class, ['label'=>'Durée possible 2','suffix'=>'Mois','required'   => false])
            ->add('dureePossible3', NumberSuffixType::class, ['label'=>'Durée possible 3','suffix'=>'Mois','required'   => false])
            ->add('dureePossible4', NumberSuffixType::class, ['label'=>'Durée possible 4','suffix'=>'Mois','required'   => false])

Afterwards, it gives us a field like this

image-1

Adapt the example to the installed version

The Symfony and Sonata examples remain tied to the versions indicated in the article. Symfony 4.x and Symfony 6.2 are no longer maintained: for a current project, use a maintained branch and the documentation that exactly matches your dependencies.

php bin/console about
composer show symfony/framework-bundle sonata-project/admin-bundle

Before resuming the code, check the signatures, services, routes, and templates concerned. Then add a functional test covering permissions, HTTP code, and the visible result.

Reference: maintained Symfony versions.

Share this article