Skip to content

Commit d54e174

Browse files
committed
[TwigBridge] Set Form ID on form element, prevent duplicate form element attributes
1 parent 6f2e603 commit d54e174

16 files changed

+47
-43
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
@@ -392,7 +392,7 @@
392392
{%- else -%}
393393
{% set form_method = "POST" %}
394394
{%- endif -%}
395-
<form{% if name != '' %} name="{{ name }}"{% endif %} method="{{ form_method|lower }}"{% if action != '' %} action="{{ action }}"{% endif %}{{ block('attributes') }}{% if multipart %} enctype="multipart/form-data"{% endif %}>
395+
<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 %}>
396396
{%- if form_method != method -%}
397397
<input type="hidden" name="_method" value="{{ method }}" />
398398
{%- 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/FormExtensionBootstrap3LayoutTest.php

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

6161
$html = $this->renderStart($form->createView());
6262

63-
$this->assertSame('<form name="form" method="get">', $html);
63+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
6464
}
6565

6666
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -72,7 +72,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
7272

7373
$html = $this->renderStart($form->createView());
7474

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

7878
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
@@ -64,7 +64,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
6464

6565
$html = $this->renderStart($form->createView());
6666

67-
$this->assertSame('<form name="form" method="get">', $html);
67+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
6868
}
6969

7070
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -76,7 +76,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
7676

7777
$html = $this->renderStart($form->createView());
7878

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

8282
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
@@ -67,7 +67,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
6767

6868
$html = $this->renderStart($form->createView());
6969

70-
self::assertSame('<form name="form" method="get">', $html);
70+
self::assertSame('<form name="form" method="get" id="form_form">', $html);
7171
}
7272

7373
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -79,7 +79,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
7979

8080
$html = $this->renderStart($form->createView());
8181

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

8585
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
@@ -135,7 +135,7 @@ public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
135135

136136
$html = $this->renderStart($form->createView());
137137

138-
$this->assertSame('<form name="form" method="get">', $html);
138+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
139139
}
140140

141141
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -147,7 +147,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
147147

148148
$html = $this->renderStart($form->createView());
149149

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

153153
public static function isRootFormProvider()

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

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

6363
$html = $this->renderStart($form->createView());
6464

65-
$this->assertSame('<form name="form" method="get">', $html);
65+
$this->assertSame('<form name="form" method="get" id="form_form">', $html);
6666
}
6767

6868
public function testStartTagHasActionAttributeWhenActionIsZero()
@@ -74,7 +74,7 @@ public function testStartTagHasActionAttributeWhenActionIsZero()
7474

7575
$html = $this->renderStart($form->createView());
7676

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

8080
public function testHelpAttr()

src/Symfony/Bridge/Twig/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"symfony/asset": "^4.4|^5.0|^6.0",
2929
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
3030
"symfony/finder": "^4.4|^5.0|^6.0",
31-
"symfony/form": "^5.4.21|^6.2.7",
31+
"symfony/form": "^5.4.26|~6.2.13|^6.3.2",
3232
"symfony/http-foundation": "^5.3|^6.0",
3333
"symfony/http-kernel": "^4.4|^5.0|^6.0",
3434
"symfony/intl": "^4.4|^5.0|^6.0",
@@ -56,7 +56,7 @@
5656
"phpdocumentor/reflection-docblock": "<3.2.2",
5757
"phpdocumentor/type-resolver": "<1.4.0",
5858
"symfony/console": "<5.3",
59-
"symfony/form": "<5.4.21|>=6,<6.2.7",
59+
"symfony/form": "<5.4.26|>=6,<6.2.13|>=6.3,<6.3.2",
6060
"symfony/http-foundation": "<5.3",
6161
"symfony/http-kernel": "<4.4",
6262
"symfony/translation": "<5.2",

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

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

7575
$rootFormAttrOption = $form->getRoot()->getConfig()->getOption('form_attr');
76+
$rootFormName = $form->getRoot()->getName();
7677
if ($options['form_attr'] || $rootFormAttrOption) {
77-
$options['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption : $form->getRoot()->getName();
78-
if (empty($options['attr']['form'])) {
78+
if (true === $rootFormAttrOption && empty($rootFormName)) {
7979
throw new LogicException('"form_attr" option must be a string identifier on root form when it has no id.');
8080
}
81+
82+
$options['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption : 'form_'.$rootFormName;
8183
}
8284
} else {
83-
$id = \is_string($options['form_attr']) ? $options['form_attr'] : $name;
85+
$id = $name;
8486
$fullName = $name;
8587
$uniqueBlockPrefix = '_'.$blockName;
8688

8789
// Strip leading underscores and digits. These are allowed in
8890
// form names, but not in HTML4 ID attributes.
8991
// https://www.w3.org/TR/html401/struct/global#adef-id
9092
$id = ltrim($id, '_0123456789');
93+
94+
$options['row_attr'] += ['id' => \is_string($options['form_attr']) ? $options['form_attr'] : 'form_'.$id];
9195
}
9296

9397
$blockPrefixes = [];

src/Symfony/Component/Form/Tests/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/Component/Form/Tests/AbstractLayoutTestCase.php

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

24252425
$html = $this->renderStart($form->createView());
24262426

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

24302430
public function testStartTagForPutRequest()
@@ -2456,7 +2456,7 @@ public function testStartTagWithOverriddenVars()
24562456
'action' => 'http://foo.com/directory',
24572457
]);
24582458

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

24622462
public function testStartTagForMultipartForm()
@@ -2470,7 +2470,7 @@ public function testStartTagForMultipartForm()
24702470

24712471
$html = $this->renderStart($form->createView());
24722472

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

24762476
public function testStartTagWithExtraAttributes()
@@ -2481,7 +2481,7 @@ public function testStartTagWithExtraAttributes()
24812481
]);
24822482

24832483
$html = $this->renderStart($form->createView(), [
2484-
'attr' => ['class' => 'foobar'],
2484+
'row_attr' => ['class' => 'foobar'],
24852485
]);
24862486

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

src/Symfony/Component/Form/Tests/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/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
@@ -787,8 +787,8 @@ public function testFormAttrOnRoot()
787787
->getForm()
788788
->createView();
789789
$this->assertArrayNotHasKey('form', $view->vars['attr']);
790-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
791-
$this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
790+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
791+
$this->assertSame($view->vars['row_attr']['id'], $view['child2']->vars['attr']['form']);
792792
}
793793

794794
public function testFormAttrOnChild()
@@ -802,7 +802,7 @@ public function testFormAttrOnChild()
802802
->getForm()
803803
->createView();
804804
$this->assertArrayNotHasKey('form', $view->vars['attr']);
805-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
805+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
806806
$this->assertArrayNotHasKey('form', $view['child2']->vars['attr']);
807807
}
808808

@@ -832,9 +832,9 @@ public function testFormAttrAsStringWithNoId()
832832
->getForm()
833833
->createView();
834834
$this->assertArrayNotHasKey('form', $view->vars['attr']);
835-
$this->assertSame($stringId, $view->vars['id']);
836-
$this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
837-
$this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
835+
$this->assertSame($stringId, $view->vars['row_attr']['id']);
836+
$this->assertSame($view->vars['row_attr']['id'], $view['child1']->vars['attr']['form']);
837+
$this->assertSame($view->vars['row_attr']['id'], $view['child2']->vars['attr']['form']);
838838
}
839839

840840
public function testSortingViewChildrenBasedOnPriorityOption()

0 commit comments

Comments
 (0)