8000 [Form] add option `empty_view` to `FormType` · symfony/symfony@f68e1e0 · GitHub
[go: up one dir, main page]

Skip to content

Commit f68e1e0

Browse files
committed
[Form] add option empty_view to FormType
1 parent adef8c4 commit f68e1e0

File tree

12 files changed

+151
-55
lines changed

12 files changed

+151
-55
lines changed

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

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,6 @@
114114
{%- endif %}
115115
{%- endblock choice_widget_expanded %}
116116

117-
{% block choice_widget_empty -%}
118-
{%- if empty_choices is empty %}
119-
{%- set empty_choices = 'No choice available' %}
120-
{%- set choice_translation_domain = 'sf_form' %}
121-
{%- endif -%}
122-
{%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) %}
123-
<div {{ block('widget_container_attributes') }}>
124-
<p>
125-
{{- choice_translation_domain is same as(false) ? empty_choices : empty_choices|trans({}, choice_translation_domain) -}}
126-
</p>
127-
</div>
128-
{%- endblock %}
129-
130117
{% block checkbox_widget -%}
131118
{%- set parent_label_class = parent_label_class|default(label_attr.class|default('')) -%}
132119
{% if 'checkbox-inline' in parent_label_class %}
@@ -245,6 +232,18 @@
245232
</div>
246233
{%- endblock radio_row %}
247234

235+
{# Support #}
236+
237+
{% block empty_row -%}
238+
{%- set translation_domain = translation_domain ?: 'sf_form' -%}
239+
{%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) %}
240+
<div {{ block('widget_container_attributes') }}>
241+
<p>
242+
{{- translation_domain is same as(false) ? empty_view : empty_view|trans({}, translation_domain) -}}
243+
</p>
244+
</div>
245+
{%- endblock empty_row %}
246+
248247
{# Errors #}
249248

250249
{% block form_errors -%}

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
{%- block form_widget -%}
44
{% if compound %}
5-
{{- block('form_widget_compound') -}}
5+
{%- if empty_view %}
6+
{{- block('empty_row') -}}
7+
{{ form_rest(form) }}
8+
{%- else -%}
9+
{{- block('form_widget_compound') -}}
10+
{%- endif -%}
611
{% else %}
712
{{- block('form_widget_simple') -}}
813
{% endif %}
@@ -35,15 +40,15 @@
3540
{%- endblock textarea_widget -%}
3641

3742
{%- block choice_widget -%}
38-
{% if choices is not empty or preferred_choices is not empty -%}
43+
{%- if empty_view is defined and empty_view -%}
44+
{{- block('empty_row') -}}
45+
{%- else -%}
3946
{%- if expanded -%}
4047
{{- block('choice_widget_expanded') -}}
4148
{%- else -%}
4249
{{- block('choice_widget_collapsed') -}}
4350
{%- endif -%}
44-
{%- elseif empty_choices is defined -%}
45-
{{- block('choice_widget_empty') -}}
46-
{% endif %}
51+
{%- endif -%}
4752
{%- endblock choice_widget -%}
4853

4954
{%- block choice_widget_expanded -%}
@@ -75,16 +80,6 @@
7580
</select>
7681
{%- endblock choice_widget_collapsed -%}
7782

78-
{%- block choice_widget_empty -%}
79-
{%- if empty_choices is empty -%}
80-
{%- set empty_choices = 'No choice available' -%}
81-
{%- set choice_translation_domain = 'sf_form' -%}
82-
{%- endif -%}
83-
<div {{ block('widget_container_attributes') }}>
84-
{{- choice_translation_domain is same as(false) ? empty_choices : empty_choices|trans({}, choice_translation_domain) -}}
85-
</div>
86-
{%- endblock choice_widget_empty -%}
87-
8883
{%- block choice_widget_options -%}
8984
{% for group_label, choice in options %}
9085
{%- if choice is iterable -%}
@@ -327,6 +322,13 @@
327322
{% endfor %}
328323
{%- endblock form_rows -%}
329324

325+
{%- block empty_row -%}
326+
{%- set translation_domain = translation_domain ?: 'sf_form' -%}
327+
<div {{ block('widget_container_attributes') }}>
328+
{{- translation_domain is same as(false) ? empty_view : empty_view|trans({}, translation_domain) -}}
329+
</div>
330+
{%- endblock empty_row -%}
331+
330332
{%- block widget_attributes -%}
331333
id="{{ id }}" name="{{ full_name }}"
332334
{%- if disabled %} disabled="disabled"{% endif -%}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,14 @@
4242
{{- form_rest(form) -}}
4343
</table>
4444
{%- endblock form_widget_compound -%}
45+
46+
{%- block empty_row -%}
47+
{%- set translation_domain = translation_domain ?: 'sf_form' -%}
48+
<table {{ block('widget_container_attributes') }}>
49+
<tr>
50+
<td colspan="2">
51+
{{ translation_domain is same as(false) ? empty_view : empty_view|trans({}, translation_domain) }}
52+
</td>
53+
</tr>
54+
</table>
55+
{%- endblock empty_row -%}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<?php if (0 < count($choices) || 0 < count($preferred_choices)): ?>
1+
<?php if (isset($empty_view) && $empty_view): ?>
2+
<?php echo $view['form']->block($form, 'empty_row')?>
3+
<?php else: ?>
24
<?php if ($expanded): ?>
35
<?php echo $view['form']->block($form, 'choice_widget_expanded') ?>
46
<?php else: ?>
57
<?php echo $view['form']->block($form, 'choice_widget_collapsed') ?>
68
<?php endif ?>
7-
<?php elseif (isset($empty_choices)): ?>
8-
<?php echo $view['form']->block($form, 'choice_widget_empty'); ?>
99
<?php endif ?>

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

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php $translation_domain = $translation_domain ?: 'sf_form'; ?>
2+
<div <?php echo $view['form']->block($form, 'widget_container_attributes') ?>>
3+
<?php echo $view->escape(false !== $translation_domain
4+
? $view['translator']->trans($empty_view, array(), $translation_domain)
5+
: $empty_view
6+
); ?>
7+
</div>
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<?php if ($compound): ?>
2-
<?php echo $view['form']->block($form, 'form_widget_compound')?>
2+
<?php if (isset($empty_view) && $empty_view): ?>
3+
<?php echo $view['form']->block($form, 'empty_row')?>
4+
<?php echo $view['form']->rest($form) ?>
5+
<?php else: ?>
6+
<?php echo $view['form']->block($form, 'form_widget_compound')?>
7+
<?php endif ?>
38
<?php else: ?>
49
<?php echo $view['form']->block($form, 'form_widget_simple')?>
510
<?php endif ?>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php $translation_domain = $translation_domain ?: 'sf_form'; ?>
2+
<table <?php echo $view['form']->block($form, 'widget_container_attributes') ?>>
3+
<tr>
4+
<td colspan="2">
5+
<?php echo $view->escape(false !== $translation_domain
6+
? $view['translator']->trans($empty_view, array(), $translation_domain)
7+
: $empty_view
8+
); ?>
9+
</td>
10+
</tr>
11+
</table>

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

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,6 @@ public function buildView(FormView $view, FormInterface $form, array $options)
224224
// POST request.
225225
$view->vars['full_name'] .= '[]';
226226
}
227-
228-
// If choices are empty set an alternative string which defaults to "null" casted to an empty string.
229-
// It should be handled in the layout and is translated with "choice_translation_domain" if any.
230-
// In default form themes it results with the string "<em>No choice available</em>".
231-
if (array() === $view->vars['choices'] && array() === $view->vars['preferred_choices']) {
232-
$view->vars['empty_choices'] = (string) $options['empty_choices'];
233-
}
234227
}
235228

236229
/**
@@ -251,6 +244,18 @@ public function finishView(FormView $view, FormInterface $form, array $options)
251244
$childView->vars['full_name'] = $childName;
252245
}
253246
}
247+
248+
// We have to override parent {@link FormType} condition of the empty_view option here,
249+
// even if there is no choices the field view may not be empty because:
250+
//
251+
// - a select input is not "compound" but should be considered as any empty HTML tag,
252+
//
253+
// - when expanded it could hold a placeholder which has been counted as a children,
254+
// we should ignore it in any case since its role is to be a "null" alternative to
255+
// choices, not a choice itself. Think of "Choose something" with no choices.
256+
if (array() === $view->vars['choices'] && array() === $view->vars['preferred_choices']) {
257+
$view->vars['empty_view'] = $options['empty_view'];
258+
}
254259
}
255260

256261
/**
@@ -330,7 +335,7 @@ public function configureOptions(OptionsResolver $resolver)
330335
'preferred_choices' => array(),
331336
'group_by' => null,
332337
'empty_data' => $emptyData,
333-
'empty_choices' => null,
338+
'empty_view' => 'No choice available',
334339
'placeholder' => $placeholderDefault,
335340
'error_bubbling' => false,
336341
'compound' => $compound,
@@ -346,7 +351,6 @@ public function configureOptions(OptionsResolver $resolver)
346351
$resolver->setNormalizer('choices_as_values', $choicesAsValuesNormalizer);
347352

348353
$resolver->setAllowedTypes('choices', array('null', 'array', '\Traversable'));
349-
$resolver->setAllowedTypes('empty_choices', array('null', 'string'));
350354
$resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string'));
351355
$resolver->setAllowedTypes('choice_loader', array('null', 'Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface'));
352356
$resolver->setAllowedTypes('choice_label', array('null', 'bool', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath'));

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ public function finishView(FormView $view, FormInterface $form, array $options)
113113
}
114114

115115
$view->vars['multipart'] = $multipart;
116+
117+
if ($form->getConfig()->getCompound()) {
118+
$view->vars['empty_view'] = (bool) $view->count() ? false : $options['empty_view'];
119+
}
116120
}
117121

118122
/**
@@ -142,6 +146,12 @@ public function configureOptions(OptionsResolver $resolver)
142146
};
143147
};
144148

149+
// For any compound form which has no children, show some text
150+
// instead of an empty HTML tag by default
151+
$emptyView = function (Options $options) {
152+
return $options['compound'] ? 'No fields' : false;
153+
};
154+
145155
// For any form that is not represented by a single HTML control,
146156
// errors should bubble up by default
147157
$errorBubbling = function (Options $options) {
@@ -157,6 +167,7 @@ public function configureOptions(OptionsResolver $resolver)
157167
$resolver->setDefaults(array(
158168
'data_class' => $dataClass,
159169
'empty_data' => $emptyData,
170+
'empty_view' => $emptyView,
160171
'trim' => true,
161172
'required' => true,
162173
'property_path' => null,
@@ -175,6 +186,7 @@ public function configureOptions(OptionsResolver $resolver)
175186
));
176187

177188
$resolver->setAllowedTypes('label_attr', 'array');
189+
$resolver->setAllowedTypes('empty_view', array('null', 'string', 'bool'));
178190
}
179191

180192
/**

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,13 @@ public function testEmptyCollection()
327327
'entry_type' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
328328
));
329329

330-
$this->assertWidgetMatchesXpath($form->createView(), array(),
330+
$this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')),
331331
'/div
332-
[./input[@type="hidden"][@id="names__token"]]
332+
[.="[trans]No fields[/trans]"]
333+
[@id="my&id"]
334+
[@class="my&class"]
333335
[count(./div)=0]
336+
/following-sibling::input[@type="hidden"][@id="names__token"]
334337
'
335338
);
336339
}

src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,62 @@ public function testEmptyCollection()
216216
'entry_type' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
217217
));
218218

219+
$this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')),
220+
'/table
221+
[
222+
./tr
223+
[
224+
./td[@colspan="2"][.="[trans]No fields[/trans]"]
225+
]
226+
]
227+
[@id="my&id"]
228+
[@class="my&class"]
229+
/following-sibling::tr[@style="display: none"]
230+
[
231+
./td[@colspan="2"]/input[@type="hidden"][@id="names__token"]
232+
]
233+
'
234+
);
235+
}
236+
237+
public function testSingleChoiceWithoutChoices()
238+
{
239+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
240+
'choices' => array(),
241+
'multiple' => false,
242+
'expanded' => false,
243+
'required' => true,
244+
));
245+
246+
$this->assertWidgetMatchesXpath($form->createView(), array(),
247+
'/table
248+
[
249+
./tr
250+
[
251+
./td[@colspan="2"][.="[trans]No choice available[/trans]"]
252+
]
253+
]
254+
'
255+
);
256+
}
257+
258+
public function testSingleChoiceExpandedWithoutChoices()
259+
{
260+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
261+
'choices' => array(),
262+
'multiple' => false,
263+
'expanded' => true,
264+
'required' => true,
265+
));
266+
219267
$this->assertWidgetMatchesXpath($form->createView(), array(),
220268
'/table
221-
[./tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="names__token"]]]
222-
[count(./tr[./td/input])=1]
269+
[
270+
./tr
271+
[
272+
./td[@colspan="2"][.="[trans]No choice available[/trans]"]
273+
]
274+
]
223275
'
224276
);
225277
}

0 commit comments

Comments
 (0)
0