Symfony 4 / Sonata : créer un type de champs de formulaire personnalisé

Nous allons voir comment nous pouvons créer un type de champ personnalisé.

Dans notre exemple, nous voulons un champ qui a le même rendu qu’un type de champ MoneyType mais dans lequel nous pourrons ajouter n’importe quel suffixe, car le champ money n’accepte que les devises.

Or dans notre projet nous voulons utiliser des kilogrammes, des mois ou encore des kilomètres. Bref, tout un tas de type de données possibles.

On commence par créer notre classe Type :

<?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';
    }
    
    
}

?>

Ensuite on rajoute notre 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 %}

Nous devons enregistrer notre template

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

Accessoirement, on ajoute une directive css pour supprimer les flèches du champ numérique HTML5.
Pour cela, nous devons référencer un fichier css dans l’admin

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

Et on ajoute notre directive dans notre fichier css

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

Ensuite il suffit de l’utiliser ainsi :

            ->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])

Cela donne ensuite un champ comme ceci

image-1