Skip to content

Commit 16d3589

Browse files
committed
[TwigBridge] Set Form ID on form element, prevent duplicate form element attributes
1 parent ccbdc1a commit 16d3589

15 files changed

+45
-41
lines changed

src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% use "bootstrap_3_layout.html.twig" %}
22

33
{% block form_start -%}
4-
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-horizontal')|trim}) %}
4+
{% set row_attr = row_attr|merge({class: (row_attr.class|default('') ~ ' form-horizontal')|trim}) %}
55
{{- parent() -}}
66
{%- endblock form_start %}
77

src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@
400400
{%- else -%}
401401
{% set form_method = "POST" %}
402402
{%- endif -%}
403-
<form{% if name != '' %} name="{{ name }}"{% endif %} method="{{ form_method|lower }}"{% if action != '' %} action="{{ action }}"{% endif %}{{ block('attributes') }}{% if multipart %} enctype="multipart/form-data"{% endif %}>
403+
<form{% if name != '' %} name="{{ name }}"{% endif %} method="{{ form_method|lower }}"{% if action != '' %} action="{{ action }}"{% endif %}{% with { attr: row_attr} %}{{ block('attributes') }}{% endwith %}{% if multipart %} enctype="multipart/form-data"{% endif %}>
404404
{%- if form_method != method -%}
405405
<input type="hidden" name="_method" value="{{ method }}">
406406
{%- endif -%}

src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTestCase.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public function testStartTag()
142142

143143
$html = $this->renderStart($form->createView());
144144

145-
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" class="form-horizontal">', $html);
145+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" id="form_form" class="form-horizontal">', $html);
146146
}
147147

148148
public function testStartTagWithOverriddenVars()
@@ -157,7 +157,7 @@ public function testStartTagWithOverriddenVars()
157157
'action' => 'http://foo.com/directory',
158158
]);
159159

160-
$this->assertSame('<form name="form" method="post" action="http://foo.com/directory" class="form-horizontal">', $html);
160+
$this->assertSame('<form name="form" method="post" action="http://foo.com/directory" id="form_form" class="form-horizontal">', $html);
161161
}
162162

163163
public function testStartTagForMultipartForm()
@@ -171,7 +171,7 @@ public function testStartTagForMultipartForm()
171171

172172
$html = $this->renderStart($form->createView());
173173

174-
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" class="form-horizontal" enctype="multipart/form-data">', $html);
174+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" id="form_form" class="form-horizontal" enctype="multipart/form-data">', $html);
175175
}
176176

177177
public function testStartTagWithExtraAttributes()
@@ -182,7 +182,7 @@ public function testStartTagWithExtraAttributes()
182182
]);
183183

184184
$html = $this->renderStart($form->createView(), [
185-
'attr' => ['class' => 'foobar'],
185+
'row_attr' => ['class' => 'foobar'],
186186
]);
187187

188188
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" class="foobar form-horizontal">', $html);

src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTestCase.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public function testStartTag()
193193

194194
$html = $this->renderStart($form->createView());
195195

196-
$this->assertSame('<form name="form" method="get" action="http://example.com/directory">', $html);
196+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" id="form_form">', $html);
197197
}
198198

199199
public function testStartTagWithOverriddenVars()
@@ -208,7 +208,7 @@ public function testStartTagWithOverriddenVars()
208208
'action' => 'http://foo.com/directory',
209209
]);
210210

211-
$this->assertSame('<form name="form" method="post" action="http://foo.com/directory">', $html);
211+
$this->assertSame('<form name="form" method="post" action="http://foo.com/directory" id="form_form">', $html);
212212
}
213213

214214
public function testStartTagForMultipartForm()
@@ -222,7 +222,7 @@ public function testStartTagForMultipartForm()
222222

223223
$html = $this->renderStart($form->createView());
224224

225-
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
225+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" id="form_form" enctype="multipart/form-data">', $html);
226226
}
227227

228228
public function testStartTagWithExtraAttributes()
@@ -233,7 +233,7 @@ public function testStartTagWithExtraAttributes()
233233
]);
234234

235235
$html = $this->renderStart($form->createView(), [
236-
'attr' => ['class' => 'foobar'],
236+
'row_attr' => ['class' => 'foobar'],
237237
]);
238238

239239
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" class="foobar">', $html);

src/Symfony/Bridge/Twig/Tests/Extension/AbstractDivLayoutTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ public function testForm()
414414
]
415415
[@method="post"]
416416
[@action="http://example.com"]
417-
[@class="my&class"]
417+
[@id="form_name"]
418418
'
419419
);
420420
}

src/Symfony/Bridge/Twig/Tests/Extension/AbstractLayoutTestCase.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,7 +2374,7 @@ public function testStartTag()
23742374

23752375
$html = $this->renderStart($form->createView());
23762376

2377-
$this->assertSame('<form name="form" method="get" action="http://example.com/directory">', $html);
2377+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" id="form_form">', $html);
23782378
}
23792379

23802380
public function testStartTagForPutRequest()
@@ -2406,7 +2406,7 @@ public function testStartTagWithOverriddenVars()
24062406
'action' => 'http://foo.com/directory',
24072407
]);
24082408

2409-
$this->assertSame('<form name="form" method="post" action="http://foo.com/directory">', $html);
2409+
$this->assertSame('<form name="form" method="post" action="http://foo.com/directory" id="form_form">', $html);
24102410
}
24112411

24122412
public function testStartTagForMultipartForm()
@@ -2420,7 +2420,7 @@ public function testStartTagForMultipartForm()
24202420

24212421
$html = $this->renderStart($form->createView());
24222422

2423-
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
2423+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" id="form_form" enctype="multipart/form-data">', $html);
24242424
}
24252425

24262426
public function testStartTagWithExtraAttributes()
@@ -2431,7 +2431,7 @@ public function testStartTagWithExtraAttributes()
24312431
]);
24322432

24332433
$html = $this->renderStart($form->createView(), [
2434-
'attr' => ['class' => 'foobar'],
2434+
'row_attr' => ['class' => 'foobar'],
24352435
]);
24362436

24372437
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" class="foobar">', $html);

src/Symfony/Bridge/Twig/Tests/Extension/AbstractTableLayoutTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ public function testForm()
271271
]
272272
[@method="post"]
273273
[@action="http://example.com"]
274-
[@class="my&class"]
274+
[@id="form_name"]
275275
'
276276
);
277277
}

src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
3131

3232
$html = $this->renderStart($form->createView());
3333

34-
$this->assertSame('<form name="form" method="get">', $html);
34+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
3535
}
3636

3737
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -43,7 +43,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
4343

4444
$html = $this->renderStart($form->createView());
4545

46-
$this->assertSame('<form name="form" method="get" action="0">', $html);
46+
$this->assertSame('<form name="form" method="get" action="0" id="form_form">', $html);
4747
}
4848

4949
public function testMoneyWidgetInIso()

src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
3636

3737
$html = $this->renderStart($form->createView());
3838

39-
$this->assertSame('<form name="form" method="get">', $html);
39+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
4040
}
4141

4242
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -48,7 +48,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
4848

4949
$html = $this->renderStart($form->createView());
5050

51-
$this->assertSame('<form name="form" method="get" action="0">', $html);
51+
$this->assertSame('<form name="form" method="get" action="0" id="form_form">', $html);
5252
}
5353

5454
public function testMoneyWidgetInIso()

src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
3838

3939
$html = $this->renderStart($form->createView());
4040

41-
self::assertSame('<form name="form" method="get">', $html);
41+
self::assertSame('<form name="form" method="get" id="form_form">', $html);
4242
}
4343

4444
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -50,7 +50,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
5050

5151
$html = $this->renderStart($form->createView());
5252

53-
self::assertSame('<form name="form" method="get" action="0">', $html);
53+
self::assertSame('<form name="form" method="get" action="0" id="form_form">', $html);
5454
}
5555

5656
public function testMoneyWidgetInIso()

src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
103103

104104
$html = $this->renderStart($form->createView());
105105

106-
$this->assertSame('<form name="form" method="get">', $html);
106+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
107107
}
108108

109109
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -115,7 +115,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
115115

116116
$html = $this->renderStart($form->createView());
117117

118-
$this->assertSame('<form name="form" method="get" action="0">', $html);
118+
$this->assertSame('<form name="form" method="get" action="0" id="form_form">', $html);
119119
}
120120

121121
public static function isRootFormProvider(): array

src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
2626

2727
$html = $this->renderStart($form->createView());
2828

29-
$this->assertSame('<form name="form" method="get">', $html);
29+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
3030
}
3131

3232
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -38,7 +38,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
3838

3939
$html = $this->renderStart($form->createView());
4040

41-
$this->assertSame('<form name="form" method="get" action="0">', $html);
41+
$this->assertSame('<form name="form" method="get" action="0" id="form_form">', $html);
4242
}
4343

4444
public function testHelpAttr()

src/Symfony/Component/Form/Extension/Core/Type/BaseType.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,25 @@ public function buildView(FormView $view, FormInterface $form, array $options):
6565
}
6666

6767
$rootFormAttrOption = $form->getRoot()->getConfig()->getOption('form_attr');
68+
$rootFormName = $form->getRoot()->getName();
6869
if ($options['form_attr'] || $rootFormAttrOption) {
69-
$options['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption : $form->getRoot()->getName();
70-
if (empty($options['attr']['form'])) {
70+
if (true === $rootFormAttrOption && empty($rootFormName)) {
7171
throw new LogicException('"form_attr" option must be a string identifier on root form when it has no id.');
7272
}
73+
74+
$options['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption : 'form_'.$rootFormName;
7375
}
7476
} else {
75-
$id = \is_string($options['form_attr']) ? $options['form_attr'] : $name;
77+
$id = $name;
7678
$fullName = $name;
7779
$uniqueBlockPrefix = '_'.$blockName;
7880

7981
// Strip leading underscores and digits. These are allowed in
8082
// form names, but not in HTML4 ID attributes.
8183
// https://www.w3.org/TR/html401/struct/global#adef-id
8284
$id = ltrim($id, '_0123456789');
85+
86+
$options['row_attr'] += ['id' => \is_string($options['form_attr']) ? $options['form_attr'] : 'form_'.$id];
8387
}
8488

8589
$blockPrefixes = [];

src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public function testFormAttrOnRoot()
5050
->getForm()
5151
->createView();
5252
$this->assertArrayNotHasKey('form', $view->vars['attr']);
53-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
54-
$this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
53+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
54+
$this->assertSame($view->vars['row_attr']['id'], $view['child2']->vars['attr']['form']);
5555
}
5656

5757
public function testFormAttrOnChild()
@@ -65,7 +65,7 @@ public function testFormAttrOnChild()
6565
->getForm()
6666
->createView();
6767
$this->assertArrayNotHasKey('form', $view->vars['attr']);
68-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
68+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
6969
$this->assertArrayNotHasKey('form', $view['child2']->vars['attr']);
7070
}
7171

@@ -95,8 +95,8 @@ public function testFormAttrAsStringWithNoId()
9595
->getForm()
9696
->createView();
9797
$this->assertArrayNotHasKey('form', $view->vars['attr']);
98-
$this->assertSame($stringId, $view->vars['id']);
99-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
100-
$this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
98+
$this->assertSame($stringId, $view->vars['row_attr']['id']);
99+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
100+
$this->assertSame($view->vars['row_attr']['id'], $view['child2']->vars['attr']['form']);
101101
}
102102
}

src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -785,8 +785,8 @@ public function testFormAttrOnRoot()
785785
->getForm()
786786
->createView();
787787
$this->assertArrayNotHasKey('form', $view->vars['attr']);
788-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
789-
$this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
788+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
789+
$this->assertSame($view->vars['row_attr']['id'], $view['child2']->vars['attr']['form']);
790790
}
791791

792792
public function testFormAttrOnChild()
@@ -800,7 +800,7 @@ public function testFormAttrOnChild()
800800
->getForm()
801801
->createView();
802802
$this->assertArrayNotHasKey('form', $view->vars['attr']);
803-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
803+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
804804
$this->assertArrayNotHasKey('form', $view['child2']->vars['attr']);
805805
}
806806

@@ -830,9 +830,9 @@ public function testFormAttrAsStringWithNoId()
830830
->getForm()
831831
->createView();
832832
$this->assertArrayNotHasKey('form', $view->vars['attr']);
833-
$this->assertSame($stringId, $view->vars['id']);
834-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
835-
$this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
833+
$this->assertSame($stringId, $view->vars['row_attr']['id']);
834+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
835+
$this->assertSame($view->vars['row_attr']['id'], $view['child2']->vars['attr']['form']);
836836
}
837837

838838
public function testSortingViewChildrenBasedOnPriorityOption()

0 commit comments

Comments
 (0)