From eaced1f587ad44f5d15f0c46d285a33ffc9a9cd0 Mon Sep 17 00:00:00 2001 From: Guillaume VDP Date: Tue, 10 Mar 2026 14:28:22 +0100 Subject: [PATCH] [Form] Add `labels` option to DateType to customize year/month/day sub-field labels --- CHANGELOG.md | 1 + Extension/Core/Type/DateType.php | 12 ++++++++ Tests/Extension/Core/Type/DateTypeTest.php | 33 ++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e64b9fa..1e11bf83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ CHANGELOG * Deprecate passing boolean as the second argument of `ValidatorExtension` and `FormTypeValidatorExtension`'s constructors; pass a `ViolationMapperInterface` instead * Add argument `$violationMapper` to `ValidatorExtensionTrait` and `TypeTestCase`'s `getExtensions()` methods * Add default `min`/`max` attributes to `BirthdayType` when `widget` is `single_text` + * Add `labels` option to `DateType` to customize the year, month and day sub-field labels 8.0 --- diff --git a/Extension/Core/Type/DateType.php b/Extension/Core/Type/DateType.php index 5c8dfaa3..2eb4f099 100644 --- a/Extension/Core/Type/DateType.php +++ b/Extension/Core/Type/DateType.php @@ -147,6 +147,10 @@ class DateType extends AbstractType $yearOptions[$passOpt] = $monthOptions[$passOpt] = $dayOptions[$passOpt] = $options[$passOpt]; } + $yearOptions['label'] = $options['labels']['year']; + $monthOptions['label'] = $options['labels']['month']; + $dayOptions['label'] = $options['labels']['day']; + $builder ->add('year', self::WIDGETS[$options['widget']], $yearOptions) ->add('month', self::WIDGETS[$options['widget']], $monthOptions) @@ -269,6 +273,11 @@ class DateType extends AbstractType ]; }; + $labelsNormalizer = static fn (Options $options, array $labels) => array_replace( + ['year' => null, 'month' => null, 'day' => null], + array_filter($labels, static fn ($label) => null !== $label) + ); + $format = static fn (Options $options) => 'single_text' === $options['widget'] ? self::HTML5_FORMAT : self::DEFAULT_FORMAT; $resolver->setDefaults([ @@ -282,6 +291,7 @@ class DateType extends AbstractType 'view_timezone' => null, 'calendar' => null, 'placeholder' => $placeholderDefault, + 'labels' => [], 'html5' => true, // Don't modify \DateTime classes by reference, we treat // them like immutable value objects @@ -301,6 +311,8 @@ class DateType extends AbstractType $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); + $resolver->setNormalizer('labels', $labelsNormalizer); + $resolver->setAllowedTypes('labels', 'array'); $resolver->setAllowedValues('input', [ 'datetime', diff --git a/Tests/Extension/Core/Type/DateTypeTest.php b/Tests/Extension/Core/Type/DateTypeTest.php index 562c4ed1..43c420c4 100644 --- a/Tests/Extension/Core/Type/DateTypeTest.php +++ b/Tests/Extension/Core/Type/DateTypeTest.php @@ -1204,6 +1204,39 @@ class DateTypeTest extends BaseTypeTestCase $this->assertSame('113-03-31', $form->getViewData()); } + public function testPassLabelsAsArray() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'choice', + 'labels' => [ + 'year' => 'Year label', + 'month' => 'Month label', + 'day' => 'Day label', + ], + ]) + ->createView(); + + $this->assertSame('Year label', $view['year']->vars['label']); + $this->assertSame('Month label', $view['month']->vars['label']); + $this->assertSame('Day label', $view['day']->vars['label']); + } + + public function testPassLabelsAsPartialArray() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'choice', + 'labels' => [ + 'year' => 'Year label', + 'day' => 'Day label', + ], + ]) + ->createView(); + + $this->assertSame('Year label', $view['year']->vars['label']); + $this->assertNull($view['month']->vars['label']); + $this->assertSame('Day label', $view['day']->vars['label']); + } + protected function getTestOptions(): array { return ['widget' => 'choice'];