Nouveau dans Symfony 8.2 (en développement). Un intervalle — deux dates, deux prix, deux tailles — se déclarait jusqu'ici en deux champs, et la règle qui les lie n'avait nulle part où vivre : elle finissait dans un écouteur POST_SUBMIT recopié d'un formulaire à l'autre. BoundsType rend les deux bornes d'un même type et porte la comparaison.
Avant
$builder ->add('du', DateType::class, ['widget' => 'single_text', 'label' => 'Du']) ->add('au', DateType::class, ['widget' => 'single_text', 'label' => 'Au']) ->addEventListener(FormEvents::POST_SUBMIT, static function (FormEvent $event): void { // comparer les deux dates, poser l'erreur sur la bonne… });
Depuis Symfony 8.2
$builder->add('periode', BoundsType::class, [ 'type' => DateType::class, 'options' => ['widget' => 'single_text'], 'from_options' => ['label' => 'Du'], 'to_options' => ['label' => 'Au'], 'compare' => true, 'compare_message' => 'La date de début doit précéder la date de fin.', ]);
Le champ a deux enfants, from et to, rendus par le type passé en type. options vaut pour les deux, from_options et to_options se fusionnent par-dessus pour ce qui les distingue. Comme tout champ composé, il a son propre libellé, deviné de son nom : label: false le retire. compare: true vérifie l'ordre des bornes et signale l'erreur sur la borne basse, celle qui doit bouger ; dates, scalaires et énumérations s'ordonnent d'eux-mêmes, un autre type de borne demande un callable.
Une borne vide reste permise : compare ne s'occupe que des périodes fermées, et le champ rend null — et non ['from' => null, 'to' => null] — quand les deux bornes sont vides.
À faire
Dans RechercheType, remplacez les deux champs de date par un seul champ periode, et laissez BoundsType comparer les bornes : l'écouteur n'a plus lieu d'être. Adaptez EmpruntsController, qui lit maintenant les deux bornes dans la donnée du champ. La page /emprunts doit se comporter comme avant, libellés et message d'erreur compris.