Skip to content

Commit 7368b3b

Browse files
committed
[Form][ChoiceType] Add placeholder_attr field option
1 parent 2877c2c commit 7368b3b

File tree

5 files changed

+64
-38
lines changed

5 files changed

+64
-38
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.3
5+
---
6+
7+
* Add a `placeholder_attr` option to `ChoiceType`
8+
49
6.2
510
---
611

Extension/Core/Type/ChoiceType.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8484
// Check if the choices already contain the empty value
8585
// Only add the placeholder option if this is not the case
8686
if (null !== $options['placeholder'] && 0 === \count($choiceList->getChoicesForValues(['']))) {
87-
$placeholderView = new ChoiceView(null, '', $options['placeholder']);
87+
$placeholderView = new ChoiceView(null, '', $options['placeholder'], $options['placeholder_attr']);
8888

8989
// "placeholder" is a reserved name
9090
$this->addSubForm($builder, 'placeholder', $placeholderView, $options);
@@ -237,6 +237,7 @@ public function buildView(FormView $view, FormInterface $form, array $options)
237237
'choices' => $choiceListView->choices,
238238
'separator' => '-------------------',
239239
'placeholder' => null,
240+
'placeholder_attr' => [],
240241
'choice_translation_domain' => $choiceTranslationDomain,
241242
'choice_translation_parameters' => $options['choice_translation_parameters'],
242243
]);
@@ -261,6 +262,7 @@ public function buildView(FormView $view, FormInterface $form, array $options)
261262
// Only add the empty value option if this is not the case
262263
if (null !== $options['placeholder'] && !$view->vars['placeholder_in_choices']) {
263264
$view->vars['placeholder'] = $options['placeholder'];
265+
$view->vars['placeholder_attr'] = $options['placeholder_attr'];
264266
}
265267

266268
if ($options['multiple'] && !$options['expanded']) {
@@ -352,6 +354,7 @@ public function configureOptions(OptionsResolver $resolver)
352354
'group_by' => null,
353355
'empty_data' => $emptyData,
354356
'placeholder' => $placeholderDefault,
357+
'placeholder_attr' => [],
355358
'error_bubbling' => false,
356359
'compound' => $compound,
357360
// The view data is always a string or an array of strings,
@@ -375,6 +378,7 @@ public function configureOptions(OptionsResolver $resolver)
375378
$resolver->setAllowedTypes('choice_value', ['null', 'callable', 'string', PropertyPath::class, ChoiceValue::class]);
376379
$resolver->setAllowedTypes('choice_attr', ['null', 'array', 'callable', 'string', PropertyPath::class, ChoiceAttr::class]);
377380
$resolver->setAllowedTypes('choice_translation_parameters', ['null', 'array', 'callable', ChoiceTranslationParameters::class]);
381+
$resolver->setAllowedTypes('placeholder_attr', ['array']);
378382
$resolver->setAllowedTypes('preferred_choices', ['array', \Traversable::class, 'callable', 'string', PropertyPath::class, PreferredChoice::class]);
379383
$resolver->setAllowedTypes('group_by', ['null', 'callable', 'string', PropertyPath::class, GroupBy::class]);
380384
}

Tests/Extension/Core/Type/ChoiceTypeTest.php

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ public function testChoiceLoaderOptionExpectsChoiceLoaderInterface()
100100
]);
101101
}
102102

103+
public function testPlaceholderAttrOptionExpectsArray()
104+
{
105+
$this->expectException(InvalidOptionsException::class);
106+
$this->factory->create(static::TESTED_TYPE, null, [
107+
'placeholder_attr' => new \stdClass(),
108+
]);
109+
}
110+
103111
public function testChoiceListAndChoicesCanBeEmpty()
104112
{
105113
$this->assertInstanceOf(FormInterface::class, $this->factory->create(static::TESTED_TYPE, null, []));
@@ -189,15 +197,19 @@ public function testExpandedChoiceListWithBooleanAndNullValuesAndFalseAsPreSetDa
189197

190198
public function testPlaceholderPresentOnNonRequiredExpandedSingleChoice()
191199
{
200+
$placeholderAttr = ['attr' => 'value'];
201+
192202
$form = $this->factory->create(static::TESTED_TYPE, null, [
193203
'multiple' => false,
194204
'expanded' => true,
195205
'required' => false,
196206
'choices' => $this->choices,
207+
'placeholder_attr' => $placeholderAttr,
197208
]);
198209

199210
$this->assertArrayHasKey('placeholder', $form);
200211
$this->assertCount(\count($this->choices) + 1, $form, 'Each choice should become a new field');
212+
$this->assertSame($placeholderAttr, $form->createView()->children['placeholder']->vars['attr']);
201213
}
202214

203215
public function testPlaceholderNotPresentIfRequired()
@@ -1669,80 +1681,84 @@ public function testPlaceholderIsEmptyStringByDefaultIfNotRequired()
16691681
/**
16701682
* @dataProvider getOptionsWithPlaceholder
16711683
*/
1672-
public function testPassPlaceholderToView($multiple, $expanded, $required, $placeholder, $viewValue)
1684+
public function testPassPlaceholderToView($multiple, $expanded, $required, $placeholder, $placeholderViewValue, $placeholderAttr, $placeholderAttrViewValue)
16731685
{
16741686
$view = $this->factory->create(static::TESTED_TYPE, null, [
16751687
'multiple' => $multiple,
16761688
'expanded' => $expanded,
16771689
'required' => $required,
16781690
'placeholder' => $placeholder,
1691+
'placeholder_attr' => $placeholderAttr,
16791692
'choices' => $this->choices,
16801693
])
16811694
->createView();
16821695

1683-
$this->assertSame($viewValue, $view->vars['placeholder']);
1696+
$this->assertSame($placeholderViewValue, $view->vars['placeholder']);
1697+
$this->assertSame($placeholderAttrViewValue, $view->vars['placeholder_attr']);
16841698
$this->assertFalse($view->vars['placeholder_in_choices']);
16851699
}
16861700

16871701
/**
16881702
* @dataProvider getOptionsWithPlaceholder
16891703
*/
1690-
public function testDontPassPlaceholderIfContainedInChoices($multiple, $expanded, $required, $placeholder, $viewValue)
1704+
public function testDontPassPlaceholderIfContainedInChoices($multiple, $expanded, $required, $placeholder, $placeholderViewValue, $placeholderAttr, $placeholderAttrViewValue)
16911705
{
16921706
$view = $this->factory->create(static::TESTED_TYPE, null, [
16931707
'multiple' => $multiple,
16941708
'expanded' => $expanded,
16951709
'required' => $required,
16961710
'placeholder' => $placeholder,
1711+
'placeholder_attr' => $placeholderAttr,
16971712
'choices' => ['Empty' => '', 'A' => 'a'],
16981713
])
16991714
->createView();
17001715

17011716
$this->assertNull($view->vars['placeholder']);
1717+
$this->assertSame([], $view->vars['placeholder_attr']);
17021718
$this->assertTrue($view->vars['placeholder_in_choices']);
17031719
}
17041720

17051721
public function getOptionsWithPlaceholder()
17061722
{
17071723
return [
17081724
// single non-expanded
1709-
[false, false, false, 'foobar', 'foobar'],
1710-
[false, false, false, '', ''],
1711-
[false, false, false, null, null],
1712-
[false, false, false, false, null],
1713-
[false, false, true, 'foobar', 'foobar'],
1714-
[false, false, true, '', ''],
1715-
[false, false, true, null, null],
1716-
[false, false, true, false, null],
1725+
[false, false, false, 'foobar', 'foobar', ['attr' => 'value'], ['attr' => 'value']],
1726+
[false, false, false, '', '', ['attr' => 'value'], ['attr' => 'value']],
1727+
[false, false, false, null, null, ['attr' => 'value'], []],
1728+
[false, false, false, false, null, ['attr' => 'value'], []],
1729+
[false, false, true, 'foobar', 'foobar', ['attr' => 'value'], ['attr' => 'value']],
1730+
[false, false, true, '', '', ['attr' => 'value'], ['attr' => 'value']],
1731+
[false, false, true, null, null, ['attr' => 'value'], []],
1732+
[false, false, true, false, null, ['attr' => 'value'], []],
17171733
// single expanded
1718-
[false, true, false, 'foobar', 'foobar'],
1734+
[false, true, false, 'foobar', 'foobar', ['attr' => 'value'], ['attr' => 'value']],
17191735
// radios should never have an empty label
1720-
[false, true, false, '', 'None'],
1721-
[false, true, false, null, null],
1722-
[false, true, false, false, null],
1736+
[false, true, false, '', 'None', ['attr' => 'value'], ['attr' => 'value']],
1737+
[false, true, false, null, null, ['attr' => 'value'], []],
1738+
[false, true, false, false, null, ['attr' => 'value'], []],
17231739
// required radios should never have a placeholder
1724-
[false, true, true, 'foobar', null],
1725-
[false, true, true, '', null],
1726-
[false, true, true, null, null],
1727-
[false, true, true, false, null],
1740+
[false, true, true, 'foobar', null, ['attr' => 'value'], []],
1741+
[false, true, true, '', null, ['attr' => 'value'], []],
1742+
[false, true, true, null, null, ['attr' => 'value'], []],
1743+
[false, true, true, false, null, ['attr' => 'value'], []],
17281744
// multiple non-expanded
1729-
[true, false, false, 'foobar', null],
1730-
[true, false, false, '', null],
1731-
[true, false, false, null, null],
1732-
[true, false, false, false, null],
1733-
[true, false, true, 'foobar', null],
1734-
[true, false, true, '', null],
1735-
[true, false, true, null, null],
1736-
[true, false, true, false, null],
1745+
[true, false, false, 'foobar', null, ['attr' => 'value'], []],
1746+
[true, false, false, '', null, ['attr' => 'value'], []],
1747+
[true, false, false, null, null, ['attr' => 'value'], []],
1748+
[true, false, false, false, null, ['attr' => 'value'], []],
1749+
[true, false, true, 'foobar', null, ['attr' => 'value'], []],
1750+
[true, false, true, '', null, ['attr' => 'value'], []],
1751+
[true, false, true, null, null, ['attr' => 'value'], []],
1752+
[true, false, true, false, null, ['attr' => 'value'], []],
17371753
// multiple expanded
1738-
[true, true, false, 'foobar', null],
1739-
[true, true, false, '', null],
1740-
[true, true, false, null, null],
1741-
[true, true, false, false, null],
1742-
[true, true, true, 'foobar', null],
1743-
[true, true, true, '', null],
1744-
[true, true, true, null, null],
1745-
[true, true, true, false, null],
1754+
[true, true, false, 'foobar', null, ['attr' => 'value'], []],
1755+
[true, true, false, '', null, ['attr' => 'value'], []],
1756+
[true, true, false, null, null, ['attr' => 'value'], []],
1757+
[true, true, false, false, null, ['attr' => 'value'], []],
1758+
[true, true, true, 'foobar', null, ['attr' => 'value'], []],
1759+
[true, true, true, '', null, ['attr' => 'value'], []],
1760+
[true, true, true, null, null, ['attr' => 'value'], []],
1761+
[true, true, true, false, null, ['attr' => 'value'], []],
17461762
];
17471763
}
17481764

Tests/Fixtures/Descriptor/resolved_form_type_1.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"group_by",
1717
"multiple",
1818
"placeholder",
19+
"placeholder_attr",
1920
"preferred_choices"
2021
],
2122
"overridden": {

Tests/Fixtures/Descriptor/resolved_form_type_1.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
1818
group_by data
1919
multiple disabled
2020
placeholder form_attr
21-
preferred_choices getter
22-
help
21+
placeholder_attr getter
22+
preferred_choices help
2323
help_attr
2424
help_html
2525
help_translation_parameters

0 commit comments

Comments
 (0)