8000 Merge remote branch 'vicb/form-rendering-fix' · renegare/symfony@97a745e · GitHub
[go: up one dir, main page]

Skip to content

Commit 97a745e

Browse files
committed
Merge remote branch 'vicb/form-rendering-fix'
* vicb/form-rendering-fix: [Form] Fix accessibility for file inputs [FrameworkBundle] Fix the FormHelper phpDoc [FrameworkBundle][Form] Add some phpDoc for the FormHelper class [FrameworkBundle][Form] Fix label rendering [FrameworkBundle][Form] Fix rendering search inputs in PHP [Form] FormType labels should never have a for attribute [Form] Never render a view again
2 parents 74fbdc2 + 8d2974c commit 97a745e

File tree

9 files changed

+189
-33
lines changed

9 files changed

+189
-33
lines changed

src/Symfony/Bridge/Twig/Extension/FormExtension.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ public function renderLabel(FormView $view, $label = null, array $variables = ar
197197
*/
198198
protected function render(FormView $view, $section, array $variables = array())
199199
{
200+
$mainTemplate = in_array($section, array('widget', 'row'));
201+
if ($mainTemplate && $view->isRendered()) {
202+
203+
return '';
204+
}
205+
200206
$templates = $this->getTemplates($view);
201207
$blocks = $view->get('types');
202208
array_unshift($blocks, '_'.$view->get('id'));
@@ -205,9 +211,6 @@ protected function render(FormView $view, $section, array $variables = array())
205211
$block = $block.'_'.$section;
206212

207213
if (isset($templates[$block])) {
208-
if ('widget' === $section || 'row' === $section) {
209-
$view->setRendered();
210-
}
211214

212215
$this->varStack[$view] = array_replace(
213216
$view->all(),
@@ -217,6 +220,10 @@ protected function render(FormView $view, $section, array $variables = array())
217220

218221
$html = $templates[$block]->renderBlock($block, $this->varStack[$view]);
219222

223+
if ($mainTemplate) {
224+
$view->setRendered();
225+
}
226+
220227
unset($this->varStack[$view]);
221228

222229
return $html;

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@
1010
{% endspaceless %}
1111
{% endblock field_label %}
1212

13-
{% block collection_label %}
13+
{% block form_label %}
1414
{% spaceless %}
1515
<label {% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans }}</label>
1616
{% endspaceless %}
17-
{% endblock collection_label %}
17+
{% endblock form_label %}
18+
19+
{% block file_label %}
20+
{% spaceless %}
21+
{{ form_label(form.file) }}
22+
{% endspaceless %}
23+
{% endblock file_label %}
1824

1925
{% block field_errors %}
2026
{% spaceless %}

src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/collection_label.html.php

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<label for="<?php echo $view->escape($id) ?>" <?php echo $view['form']->attributes() ?>><?php echo $view->escape($view['translator']->trans($label)) ?></label>
1+
<label for="<?php echo $view->escape($id) ?>" <?php echo $view['form']->attributes(false) ?>><?php echo $view->escape($view['translator']->trans($label)) ?></label>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php echo $view['form']->label($form['file']) ?>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<label <?php echo $view['form']->attributes(false) ?>><?php echo $view->escape($view['translator']->trans($label)) ?></label>

src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<input type="search"
22
<?php echo $view['form']->attributes() ?>
3-
name="<?php echo $view->escape($name) ?>"
3+
name="<?php echo $view->escape($full_name) ?>"
44
value="<?php echo $view->escape($value) ?>"
55
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
66
<?php if ($required): ?>required="required"<?php endif ?>

src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ public function __construct(EngineInterface $engine)
3838
$this->varStack = new \SplObjectStorage();
3939
}
4040

41-
public function attributes()
41+
/**
42+
* Renders the attributes for the current view.
43+
*
44+
* @param Boolean $includeId Whether to render the id attribute
45+
*
46+
* @return string The HTML markup
47+
*/
48+
public function attributes($includeId = true)
4249
{
4350
$html = '';
4451
$attr = array();
@@ -51,7 +58,7 @@ public function attributes()
5158
$attr = $vars['attr'];
5259
}
5360

54-
if (isset($vars['id'])) {
61+
if (true === $includeId && isset($vars['id'])) {
5562
$attr['id'] = $vars['id'];
5663
}
5764
}
@@ -63,11 +70,40 @@ public function attributes()
6370
return $html;
6471
}
6572

73+
/**
74+
* Renders the HTML enctype in the form tag, if necessary.
75+
*
76+
* Example usage templates:
77+
*
78+
* <form action="..." method="post" <?php echo $view['form']->enctype() ?>>
79+
*
80+
* @param FormView $view The view for which to render the encoding type
81+
*
82+
* @return string The html markup
83+
*/
6684
public function enctype(FormView $view)
6785
{
6886
return $this->renderSection($view, 'enctype');
6987
}
7088

89+
/**
90+
* Renders the HTML for a given view.
91+
*
92+
* Example usage:
93+
*
94+
* <?php echo view['form']->widget() ?>
95+
*
96+
* You can pass options during the call:
97+
*
98+
* <?php echo view['form']->widget(array('attr' => array('class' => 'foo'))) ?>
99+
*
100+
* <?php echo view['form']->widget(array('separator' => '+++++)) ?>
101+
*
102+
* @param FormView $view The view for which to render the widget
103+
* @param array $variables Additional variables passed to the template
104+
*
105+
* @return string The html markup
106+
*/
71107
public function widget(FormView $view, array $variables = array())
72108
{
73109
return trim($this->renderSection($view, 'widget', $variables));
@@ -76,16 +112,25 @@ public function widget(FormView $view, array $variables = array())
76112
/**
77113
* Renders the entire form field "row".
78114
*
79-
* @param FormView $view
80-
* @param array $variables
115+
* @param FormView $view The view for which to render the row
116+
* @param array $variables Additional variables passed to the template
81117
*
82-
* @return string
118+
* @return string The html markup
83119
*/
84120
public function row(FormView $view, array $variables = array())
85121
{
86122
return $this->renderSection($view, 'row', $variables);
87123
}
88124

125+
/**
126+
* Renders the label of the given view.
127+
*
128+
* @param FormView $view The view for which to render the label
129+
* @param string $label The label
130+
* @param array $variables Additional variables passed to the template
131+
*
132+
* @return string The html markup
133+
*/
89134
public function label(FormView $view, $label = null, array $variables = array())
90135
{
91136
if ($label !== null) {
@@ -95,18 +140,56 @@ public function label(FormView $view, $label = null, array $variables = array())
95140
return $this->renderSection($view, 'label', $variables);
96141
}
97142

143+
/**
144+
* Renders the errors of the given view.
145+
*
146+
* @param FormView $view The view to render the errors for
147+
*
148+
* @return string The html markup
149+
*/
98150
public function errors(FormView $view)
99151
{
100152
return $this->renderSection($view, 'errors');
101153
}
102154

155+
/**
156+
* Renders views which have not already been rendered.
157+
*
158+
* @param FormView $view The parent view
159+
* @param array $variables An array of variables
160+
*
161+
* @return string The html markup
162+
*/
103163
public function rest(FormView $view, array $variables = array())
104164
{
105165
return $this->renderSection($view, 'rest', $variables);
106166
}
107167

168+
/**
169+
* Renders a template.
170+
*
171+
* 1. This function first looks for a block named "_<view id>_<section>",
172+
* 2. if such a block is not found the function will look for a block named
173+
* "<type name>_<section>",
174+
* 3. the type name is recursively replaced by the parent type name until a
175+
* corresponding block is found
176+
*
177+
* @param FormView $view The form view
178+
* @param string $section The section to render (i.e. 'row', 'widget', 'label', ...)
179+
* @param array $variables Additional variables
180+
*
181+
* @return string The html markup
182+
*
183+
* @throws FormException if no template block exists to render the given section of the view
184+
*/
108185
protected function renderSection(FormView $view, $section, array $variables = array())
109186
{
187+
$mainTemplate = in_array($section, array('row', 'widget'));
188+
if ($mainTemplate && $view->isRendered()) {
189+
190+
return '';
191+
}
192+
110193
$template = null;
111194
$blocks = $view->get('types');
112195
array_unshift($blocks, '_'.$view->get('id'));
@@ -124,11 +207,13 @@ protected function renderSection(FormView $view, $section, array $variables = ar
124207
throw new FormException(sprintf('Unable to render form as none of the following blocks exist: "%s".', implode('", "', $blocks)));
125208
}
126209

127-
if ('widget' === $section || 'row' === $section) {
210+
$html = $this->render($view, $template, $variables);
211+
212+
if ($mainTemplate) {
128213
$view->setRendered();
129214
}
130215

131-
return $this->render($view, $template, $variables);
216+
return $html;
132217
}
133218

134219
public function render(FormView $view, $template, array $variables = array())
@@ -149,13 +234,20 @@ public function render(FormView $view, $template, array $variables = array())
149234
return $html;
150235
}
151236

152-
protected function lookupTemplate($templateName)
237+
/**
238+
* Returns the name of the template to use to render the block
239+
*
240+
* @param string $blockName The name of the block
241+
*
242+
* @return string|Boolean The template logical name or false when no template is found
243+
*/
244+
protected function lookupTemplate($blockName)
153245
{
154-
if (isset(self::$cache[$templateName])) {
155-
return self::$cache[$templateName];
246+
if (isset(self::$cache[$blockName])) {
247+
return self::$cache[$blockName];
156248
}
157249

158-
$template = $templateName.'.html.php';
250+
$template = $blockName.'.html.php';
159251
/*
160252
if ($this->templateDir) {
161253
$template = $this->templateDir.':'.$template;
@@ -166,7 +258,7 @@ protected function lookupTemplate($templateName)
166258
$template = false;
167259
}
168260

169-
self::$cache[$templateName] = $template;
261+
self::$cache[$blockName] = $template;
170262

171263
return $template;
172264
}

tests/Symfony/Tests/Component/Form/AbstractDivLayoutTest.php

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,11 @@ public function testRestWithChildrenForms()
144144
$html = $this->renderRest($view);
145145

146146
$this->assertMatchesXpath($html,
147-
'/input
148-
[@type="hidden"]
149-
[@id="parent__token"]
147+
'/input[@type="hidden"][@id="parent__token"]
150148
/following-sibling::div
151149
[
152-
./label[@for="parent_child1"]
153-
/following-sibling::div
154-
[@id="parent_child1"]
150+
./label[not(@for)]
151+
/following-sibling::div[@id="parent_child1"]
155152
[
156153
./div
157154
[
@@ -160,23 +157,21 @@ public function testRestWithChildrenForms()
160157
]
161158
]
162159
]
160+
163161
/following-sibling::div
164162
[
165-
./label[@for="parent_child2"]
166-
/following-sibling::div
167-
[@id="parent_child2"]
163+
./label[not(@for)]
164+
/following-sibling::div[@id="parent_child2"]
168165
[
169166
./div
170167
[
171168
./label[@for="parent_child2_field1"]
172169
/following-sibling::input[@id="parent_child2_field1"]
173170
]
174-
/following-sibling::div
175-
[
176-
./label[@for="parent_child2_field2"]
177-
]
178171
]
179172
]
173+
[count(//label)=4]
174+
[count(//input[@type="text"])=2]
180175
'
181176
);
182177
}
@@ -373,4 +368,59 @@ public function testRepeated()
373368
'
374369
);
375370
}
371+
372+
public function testSearchInputName()
373+
{
374+
$form = $this->factory->createNamedBuilder('form', 'full')
375+
->add('name', 'search')
376+
->getForm();
377+
378+
$this->assertWidgetMatchesXpath($form->createView(), array(),
379+
'/div
380+
[
381+
./input[@type="hidden"][@id="full__token"]
382+
/following-sibling::div
383+
[
384+
./label[@for="full_name"]
385+
/following-sibling::input[@type="search"][@id="full_name"][@name="full[name]"]
386+
]
387+
]
388+
[count(//input)=2]
389+
'
390+
);
391+
}
392+
393+
public function testLabelHasNoId()
394+
{
395+
$form = $this->factory->createNamed('text', 'name');
396+
$html = $this->renderRow($form->createView());
397+
398+
$this->assertMatchesXpath($html,
399+
'/div
400+
[
401+
./label[@for="name"][not(@id)]
402+
/following-sibling::input[@id="name"]
403+
]
404+
'
405+
);
406+
}
407+
408+
public function testFileLabelAccessibility()
409+
{
410+
$form = $this->factory->createNamed('file', 'name');
411+
$html = $this->renderRow($form->createView());
412+
413+
$this->assertMatchesXpath($html,
414+
'/div
415+
[
416+
./label[@for="name_file"]
417+
/following-sibling::div[@id="name"]
418+
[
419+
./input[@id="name_file"][@type="file"]
420+
]
421+
]
422+
'
423+
);
424+
}
425+
376426
}

0 commit comments

Comments
 (0)
0