[Form] Fixed results of the FieldType+FormType merge.

This commit is contained in:
Bernhard Schussek 2012-04-20 18:42:21 +02:00
parent a01dec00f4
commit eb75ab1b74
59 changed files with 401 additions and 278 deletions

View File

@ -102,7 +102,7 @@
``` ```
* The custom factories for the firewall configuration are now * The custom factories for the firewall configuration are now
registered during the build method of bundles instead of being registered registered during the build method of bundles instead of being registered
by the end-user. This means that you will you need to remove the 'factories' by the end-user. This means that you will you need to remove the 'factories'
keys in your security configuration. keys in your security configuration.
* The Firewall listener is now registered after the Router listener. This * The Firewall listener is now registered after the Router listener. This
@ -313,29 +313,29 @@
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice'; return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice';
} }
``` ```
* The methods `getDefaultOptions()` and `getAllowedOptionValues()` of form * The methods `getDefaultOptions()` and `getAllowedOptionValues()` of form
types no longer receive an option array. types no longer receive an option array.
You can specify options that depend on other options using closures instead. You can specify options that depend on other options using closures instead.
Before: Before:
``` ```
public function getDefaultOptions(array $options) public function getDefaultOptions(array $options)
{ {
$defaultOptions = array(); $defaultOptions = array();
if ($options['multiple']) { if ($options['multiple']) {
$defaultOptions['empty_data'] = array(); $defaultOptions['empty_data'] = array();
} }
return $defaultOptions; return $defaultOptions;
} }
``` ```
After: After:
``` ```
public function getDefaultOptions() public function getDefaultOptions()
{ {
@ -346,7 +346,7 @@
); );
} }
``` ```
The second argument `$previousValue` does not have to be specified if not The second argument `$previousValue` does not have to be specified if not
needed. needed.
@ -366,29 +366,92 @@
(or any other of the BIND events). In case you used the CallbackValidator (or any other of the BIND events). In case you used the CallbackValidator
class, you should now pass the callback directly to `addEventListener`. class, you should now pass the callback directly to `addEventListener`.
* simplified CSRF protection and removed the csrf type * Since FormType and FieldType were merged, you need to adapt your form
themes.
* deprecated FieldType and merged it into FormType The "field_widget" and all references to it should be renamed to
"form_widget_primitive":
Before:
```
{% block url_widget %}
{% spaceless %}
{% set type = type|default('url') %}
{{ block('field_widget') }}
{% endspaceless %}
{% endblock url_widget %}
```
After:
```
{% block url_widget %}
{% spaceless %}
{% set type = type|default('url') %}
{{ block('form_widget_primitive') }}
{% endspaceless %}
{% endblock url_widget %}
```
All other "field_*" blocks and references to them should be renamed to
"form_*". If you previously defined both a "field_*" and a "form_*"
block, you can merge them into a single "form_*" block and check the new
Boolean variable "primitive":
Before:
```
{% block form_errors %}
{% spaceless %}
... form code ...
{% endspaceless %}
{% endblock form_errors %}
{% block field_errors %}
{% spaceless %}
... field code ...
{% endspaceless %}
{% endblock field_errors %}
```
After:
```
{% block form_errors %}
{% spaceless %}
{% if primitive %}
... field code ...
{% else %}
... form code ...
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
```
Furthermore, the block "generic_label" was merged into "form_label". You
should now override "form_label" in order to customize labels.
Last but not least, the block "widget_choice_options" was renamed to
"choice_widget_options" to be consistent with the rest of the default
theme.
* [BC BREAK] renamed "field_*" theme blocks to "form_*" and "field_widget" to
"input"
* The method `guessMinLength()` of FormTypeGuesserInterface was deprecated * The method `guessMinLength()` of FormTypeGuesserInterface was deprecated
and will be removed in Symfony 2.3. You should use the new method and will be removed in Symfony 2.3. You should use the new method
`guessPattern()` instead which may return any regular expression that `guessPattern()` instead which may return any regular expression that
is inserted in the HTML5 attribute "pattern". is inserted in the HTML5 attribute "pattern".
Before: Before:
public function guessMinLength($class, $property) public function guessMinLength($class, $property)
{ {
if (/* condition */) { if (/* condition */) {
return new ValueGuess($minLength, Guess::LOW_CONFIDENCE); return new ValueGuess($minLength, Guess::LOW_CONFIDENCE);
} }
} }
After: After:
public function guessPattern($class, $property) public function guessPattern($class, $property)
{ {
if (/* condition */) { if (/* condition */) {
@ -470,7 +533,7 @@
`validate` and its return value was dropped. `validate` and its return value was dropped.
`ConstraintValidator` still contains the deprecated `isValid` method and `ConstraintValidator` still contains the deprecated `isValid` method and
forwards `validate` calls to `isValid` by default. This BC layer will be forwards `validate` calls to `isValid` by default. This BC layer will be
removed in Symfony 2.3. You are advised to rename your methods. You should removed in Symfony 2.3. You are advised to rename your methods. You should
also remove the return values, which have never been used by the framework. also remove the return values, which have never been used by the framework.
@ -500,7 +563,7 @@
$this->context->addViolation($constraint->message, array( $this->context->addViolation($constraint->message, array(
'{{ value }}' => $value, '{{ value }}' => $value,
)); ));
return; return;
} }
} }

View File

@ -2,17 +2,30 @@
{% block form_widget %} {% block form_widget %}
{% spaceless %} {% spaceless %}
{% if form.children|length > 0 %} {% if primitive %}
<div {{ block('widget_container_attributes') }}> {{ block('form_widget_primitive') }}
{{ block('form_rows') }}
{{ form_rest(form) }}
</div>
{% else %} {% else %}
{{ block('input') }} {{ block('form_widget_complex') }}
{% endif %} {% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock form_widget %} {% endblock form_widget %}
{% block form_widget_primitive %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_primitive %}
{% block form_widget_complex %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{{ block('form_rows') }}
{{ form_rest(form) }}
</div>
{% endspaceless %}
{% endblock form_widget_complex %}
{% block collection_widget %} {% block collection_widget %}
{% spaceless %} {% spaceless %}
{% if prototype is defined %} {% if prototype is defined %}
@ -28,7 +41,47 @@
{% endspaceless %} {% endspaceless %}
{% endblock textarea_widget %} {% endblock textarea_widget %}
{% block widget_choice_options %} {% block choice_widget %}
{% spaceless %}
{% if expanded %}
{{ block('choice_widget_expanded') }}
{% else %}
{{ block('choice_widget_collapsed') }}
{% endif %}
{% endspaceless %}
{% endblock choice_widget %}
{% block choice_widget_expanded %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }}
{% endfor %}
</div>
{% endspaceless %}
{% endblock choice_widget_expanded %}
{% block choice_widget_collapsed %}
{% spaceless %}
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{% if empty_value is not none %}
<option value="">{{ empty_value|trans({}, translation_domain) }}</option>
{% endif %}
{% if preferred_choices|length > 0 %}
{% set options = preferred_choices %}
{{ block('choice_widget_options') }}
{% if choices|length > 0 and separator is not none %}
<option disabled="disabled">{{ separator }}</option>
{% endif %}
{% endif %}
{% set options = choices %}
{{ block('choice_widget_options') }}
</select>
{% endspaceless %}
{% endblock choice_widget_collapsed %}
{% block choice_widget_options %}
{% spaceless %} {% spaceless %}
{% for index, choice in options %} {% for index, choice in options %}
{% if _form_is_choice_group(choice) %} {% if _form_is_choice_group(choice) %}
@ -42,35 +95,7 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endspaceless %} {% endspaceless %}
{% endblock widget_choice_options %} {% endblock choice_widget_options %}
{% block choice_widget %}
{% spaceless %}
{% if expanded %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }}
{% endfor %}
</div>
{% else %}
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{% if empty_value is not none %}
<option value="">{{ empty_value|trans({}, translation_domain) }}</option>
{% endif %}
{% if preferred_choices|length > 0 %}
{% set options = preferred_choices %}
{{ block('widget_choice_options') }}
{% if choices|length > 0 and separator is not none %}
<option disabled="disabled">{{ separator }}</option>
{% endif %}
{% endif %}
{% set options = choices %}
{{ block('widget_choice_options') }}
</select>
{% endif %}
{% endspaceless %}
{% endblock choice_widget %}
{% block checkbox_widget %} {% block checkbox_widget %}
{% spaceless %} {% spaceless %}
@ -87,7 +112,7 @@
{% block datetime_widget %} {% block datetime_widget %}
{% spaceless %} {% spaceless %}
{% if widget == 'single_text' %} {% if widget == 'single_text' %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% else %} {% else %}
<div {{ block('widget_container_attributes') }}> <div {{ block('widget_container_attributes') }}>
{{ form_errors(form.date) }} {{ form_errors(form.date) }}
@ -102,7 +127,7 @@
{% block date_widget %} {% block date_widget %}
{% spaceless %} {% spaceless %}
{% if widget == 'single_text' %} {% if widget == 'single_text' %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% else %} {% else %}
<div {{ block('widget_container_attributes') }}> <div {{ block('widget_container_attributes') }}>
{{ date_pattern|replace({ {{ date_pattern|replace({
@ -118,7 +143,7 @@
{% block time_widget %} {% block time_widget %}
{% spaceless %} {% spaceless %}
{% if widget == 'single_text' %} {% if widget == 'single_text' %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% else %} {% else %}
<div {{ block('widget_container_attributes') }}> <div {{ block('widget_container_attributes') }}>
{{ form_widget(form.hour, { 'attr': { 'size': '1' } }) }}:{{ form_widget(form.minute, { 'attr': { 'size': '1' } }) }}{% if with_seconds %}:{{ form_widget(form.second, { 'attr': { 'size': '1' } }) }}{% endif %} {{ form_widget(form.hour, { 'attr': { 'size': '1' } }) }}:{{ form_widget(form.minute, { 'attr': { 'size': '1' } }) }}{% if with_seconds %}:{{ form_widget(form.second, { 'attr': { 'size': '1' } }) }}{% endif %}
@ -131,81 +156,77 @@
{% spaceless %} {% spaceless %}
{# type="number" doesn't work with floats #} {# type="number" doesn't work with floats #}
{% set type = type|default('text') %} {% set type = type|default('text') %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% endspaceless %} {% endspaceless %}
{% endblock number_widget %} {% endblock number_widget %}
{% block integer_widget %} {% block integer_widget %}
{% spaceless %} {% spaceless %}
{% set type = type|default('number') %} {% set type = type|default('number') %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% endspaceless %} {% endspaceless %}
{% endblock integer_widget %} {% endblock integer_widget %}
{% block money_widget %} {% block money_widget %}
{% spaceless %} {% spaceless %}
{{ money_pattern|replace({ '{{ widget }}': block('input') })|raw }} {{ money_pattern|replace({ '{{ widget }}': block('form_widget_primitive') })|raw }}
{% endspaceless %} {% endspaceless %}
{% endblock money_widget %} {% endblock money_widget %}
{% block url_widget %} {% block url_widget %}
{% spaceless %} {% spaceless %}
{% set type = type|default('url') %} {% set type = type|default('url') %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% endspaceless %} {% endspaceless %}
{% endblock url_widget %} {% endblock url_widget %}
{% block search_widget %} {% block search_widget %}
{% spaceless %} {% spaceless %}
{% set type = type|default('search') %} {% set type = type|default('search') %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% endspaceless %} {% endspaceless %}
{% endblock search_widget %} {% endblock search_widget %}
{% block percent_widget %} {% block percent_widget %}
{% spaceless %} {% spaceless %}
{% set type = type|default('text') %} {% set type = type|default('text') %}
{{ block('input') }} % {{ block('form_widget_primitive') }} %
{% endspaceless %} {% endspaceless %}
{% endblock percent_widget %} {% endblock percent_widget %}
{% block password_widget %} {% block password_widget %}
{% spaceless %} {% spaceless %}
{% set type = type|default('password') %} {% set type = type|default('password') %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% endspaceless %} {% endspaceless %}
{% endblock password_widget %} {% endblock password_widget %}
{% block hidden_widget %} {% block hidden_widget %}
{% spaceless %}
{% set type = type|default('hidden') %} {% set type = type|default('hidden') %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% endspaceless %}
{% endblock hidden_widget %} {% endblock hidden_widget %}
{% block email_widget %} {% block email_widget %}
{% spaceless %} {% spaceless %}
{% set type = type|default('email') %} {% set type = type|default('email') %}
{{ block('input') }} {{ block('form_widget_primitive') }}
{% endspaceless %} {% endspaceless %}
{% endblock email_widget %} {% endblock email_widget %}
{# Labels #} {# Labels #}
{% block generic_label %} {% block form_label %}
{% spaceless %} {% spaceless %}
{% if primitive %}
{% set attr = attr|merge({'for': id}) %}
{% endif %}
{% if required %} {% if required %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %} {% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %}
{% endif %} {% endif %}
<label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label> <label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>
{% endspaceless %} {% endspaceless %}
{% endblock %}
{% block form_label %}
{% spaceless %}
{% if form.children|length == 0 %}
{% set attr = attr|merge({'for': id}) %}
{% endif %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock form_label %} {% endblock form_label %}
{# Rows #} {# Rows #}
@ -220,7 +241,9 @@
{% spaceless %} {% spaceless %}
<div> <div>
{{ form_label(form, label|default(null)) }} {{ form_label(form, label|default(null)) }}
{% if form.children|length == 0 %} {# If the child is a form, the errors are rendered inside the container #}
{# see block form_rows #}
{% if primitive %}
{{ form_errors(form) }} {{ form_errors(form) }}
{% endif %} {% endif %}
{{ form_widget(form) }} {{ form_widget(form) }}
@ -247,10 +270,8 @@
{% for error in errors %} {% for error in errors %}
<li>{{ <li>{{
error.messagePluralization is null error.messagePluralization is null
? ? error.messageTemplate|trans(error.messageParameters, 'validators')
error.messageTemplate|trans(error.messageParameters, 'validators') : error.messageTemplate|transchoice(error.messagePluralization, error.messageParameters, 'validators')
:
error.messageTemplate|transchoice(error.messagePluralization, error.messageParameters, 'validators')
}}</li> }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
@ -279,13 +300,6 @@
{% endspaceless %} {% endspaceless %}
{% endblock form_rows %} {% endblock form_rows %}
{% block input %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock input %}
{% block widget_attributes %} {% block widget_attributes %}
{% spaceless %} {% spaceless %}
id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %} id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
@ -302,44 +316,12 @@
{# Deprecated in Symfony 2.1, to be removed in 2.3 #} {# Deprecated in Symfony 2.1, to be removed in 2.3 #}
{% block field_widget %} {% block generic_label %}{{ block('form_label') }}{% endblock %}
{% spaceless %} {% block widget_choice_options %}{{ block('choice_widget_options') }}{% endblock %}
{{ block('input') }} {% block field_widget %}{{ block('form_widget_primitive') }}{% endblock %}
{% endspaceless %} {% block field_label %}{{ block('form_label') }}{% endblock %}
{% endblock field_widget %} {% block field_row %}{{ block('form_row') }}{% endblock %}
{% block field_enctype %}{{ block('form_enctype') }}{% endblock %}
{% block field_label %} {% block field_errors %}{{ block('form_errors') }}{% endblock %}
{% spaceless %} {% block field_rest %}{{ block('form_rest') }}{% endblock %}
{{ block('form_label') }} {% block field_rows %}{{ block('form_rows') }}{% endblock %}
{% endspaceless %}
{% endblock field_label %}
{% block field_row %}
{% spaceless %}
{{ block('form_row') }}
{% endspaceless %}
{% endblock field_row %}
{% block field_enctype %}
{% spaceless %}
{{ block('form_enctype') }}
{% endspaceless %}
{% endblock field_enctype %}
{% block field_errors %}
{% spaceless %}
{{ block('form_errors') }}
{% endspaceless %}
{% endblock field_errors %}
{% block field_rest %}
{% spaceless %}
{{ block('form_rest') }}
{% endspaceless %}
{% endblock field_rest %}
{% block field_rows %}
{% spaceless %}
{{ block('form_rows') }}
{% endspaceless %}
{% endblock field_rows %}

View File

@ -7,7 +7,7 @@
{{ form_label(form, label|default(null)) }} {{ form_label(form, label|default(null)) }}
</td> </td>
<td> <td>
{% if form.children|length == 0 %} {% if primitive %}
{{ form_errors(form) }} {{ form_errors(form) }}
{% endif %} {% endif %}
{{ form_widget(form) }} {{ form_widget(form) }}
@ -18,7 +18,9 @@
{% block form_errors %} {% block form_errors %}
{% spaceless %} {% spaceless %}
{% if form.children|length > 0 %} {% if primitive %}
{{ parent() }}
{% else %}
{% if errors|length > 0 %} {% if errors|length > 0 %}
<tr> <tr>
<td colspan="2"> <td colspan="2">
@ -26,8 +28,6 @@
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% else %}
{{ parent() }}
{% endif %} {% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock form_errors %} {% endblock form_errors %}
@ -42,15 +42,11 @@
{% endspaceless %} {% endspaceless %}
{% endblock hidden_row %} {% endblock hidden_row %}
{% block form_widget %} {% block form_widget_complex %}
{% spaceless %} {% spaceless %}
{% if form.children|length > 0 %} <table {{ block('widget_container_attributes') }}>
<table {{ block('widget_container_attributes') }}> {{ block('form_rows') }}
{{ block('form_rows') }} {{ form_rest(form) }}
{{ form_rest(form) }} </table>
</table>
{% else %}
{{ parent() }}
{% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock form_widget %} {% endblock form_widget_complex %}

View File

@ -1,6 +1,6 @@
{% block input %} {% block form_widget_primitive %}
{% spaceless %} {% spaceless %}
{% set type = type|default('text') %} {% set type = type|default('text') %}
<input type="{{ type }}" {{ block('attributes') }} value="{{ value }}" rel="theme" /> <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %} {% endspaceless %}
{% endblock input %} {% endblock form_widget_primitive %}

View File

@ -1,8 +1,8 @@
{% extends 'form_div_layout.html.twig' %} {% extends 'form_div_layout.html.twig' %}
{% block input %} {% block form_widget_primitive %}
{% spaceless %} {% spaceless %}
{% set type = type|default('text') %} {% set type = type|default('text') %}
<input type="{{ type }}" {{ block('attributes') }} value="{{ value }}" rel="theme" /> <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %} {% endspaceless %}
{% endblock input %} {% endblock form_widget_primitive %}

View File

@ -1,8 +1,8 @@
{% use 'form_div_layout.html.twig' %} {% use 'form_div_layout.html.twig' %}
{% block input %} {% block form_widget_primitive %}
{% spaceless %} {% spaceless %}
{% set type = type|default('text') %} {% set type = type|default('text') %}
<input type="{{ type }}" {{ block('attributes') }} value="{{ value }}" rel="theme" /> <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %} {% endspaceless %}
{% endblock input %} {% endblock form_widget_primitive %}

View File

@ -1,9 +1 @@
id="<?php echo $view->escape($id) ?>" <?php echo $view['form']->renderBlock('widget_attributes') ?>
name="<?php echo $view->escape($full_name) ?>"
<?php if ($read_only): ?>readonly="readonly" <?php endif ?>
<?php if ($disabled): ?>disabled="disabled" <?php endif ?>
<?php if ($required): ?>required="required" <?php endif ?>
<?php if ($max_length): ?>maxlength="<?php echo $view->escape($max_length) ?>" <?php endif ?>
<?php if ($pattern): ?>pattern="<?php echo $view->escape($pattern) ?>" <?php endif ?>
<?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>

View File

@ -1,5 +1,5 @@
<input type="checkbox" <input type="checkbox"
<?php echo $view['form']->renderBlock('attributes') ?> <?php echo $view['form']->renderBlock('widget_attributes') ?>
<?php if ($value): ?> value="<?php echo $view->escape($value) ?>"<?php endif ?> <?php if ($value): ?> value="<?php echo $view->escape($value) ?>"<?php endif ?>
<?php if ($checked): ?> checked="checked"<?php endif ?> <?php if ($checked): ?> checked="checked"<?php endif ?>
/> />

View File

@ -1,11 +1 @@
<?php foreach ($options as $index => $choice): ?> <?php echo $view['form']->renderBlock('choice_widget_options') ?>
<?php if ($view['form']->isChoiceGroup($choice)): ?>
<optgroup label="<?php echo $view->escape($view['translator']->trans($index, array(), $translation_domain)) ?>">
<?php foreach ($choice as $nested_choice): ?>
<option value="<?php echo $view->escape($nested_choice->getValue()) ?>"<?php if ($view['form']->isChoiceSelected($form, $nested_choice)): ?> selected="selected"<?php endif?>><?php echo $view->escape($view['translator']->trans($nested_choice->getLabel(), array(), $translation_domain)) ?></option>
<?php endforeach ?>
</optgroup>
<?php else: ?>
<option value="<?php echo $view->escape($choice->getValue()) ?>"<?php if ($view['form']->isChoiceSelected($form, $choice)): ?> selected="selected"<?php endif?>><?php echo $view->escape($view['translator']->trans($choice->getLabel(), array(), $translation_domain)) ?></option>
<?php endif ?>
<?php endforeach ?>

View File

@ -1,22 +1,5 @@
<?php if ($expanded): ?> <?php if ($expanded): ?>
<div <?php echo $view['form']->renderBlock('container_attributes') ?>> <?php echo $view['form']->renderBlock('choice_widget_expanded') ?>
<?php foreach ($form as $child): ?>
<?php echo $view['form']->widget($child) ?>
<?php echo $view['form']->label($child) ?>
<?php endforeach ?>
</div>
<?php else: ?> <?php else: ?>
<select <?php echo $view['form']->renderBlock('choice_widget_collapsed') ?>
<?php echo $view['form']->renderBlock('attributes') ?>
<?php if ($multiple): ?> multiple="multiple"<?php endif ?>
>
<?php if (null !== $empty_value): ?><option value=""><?php echo $view->escape($view['translator']->trans($empty_value, array(), $translation_domain)) ?></option><?php endif; ?>
<?php if (count($preferred_choices) > 0): ?>
<?php echo $view['form']->renderBlock('choice_options', array('options' => $preferred_choices)) ?>
<?php if (count($choices) > 0 && null !== $separator): ?>
<option disabled="disabled"><?php echo $separator ?></option>
<?php endif ?>
<?php endif ?>
<?php echo $view['form']->renderBlock('choice_options', array('options' => $choices)) ?>
</select>
<?php endif ?> <?php endif ?>

View File

@ -0,0 +1,13 @@
<select
<?php echo $view['form']->renderBlock('widget_attributes') ?>
<?php if ($multiple): ?> multiple="multiple"<?php endif ?>
>
<?php if (null !== $empty_value): ?><option value=""><?php echo $view->escape($view['translator']->trans($empty_value, array(), $translation_domain)) ?></option><?php endif; ?>
<?php if (count($preferred_choices) > 0): ?>
<?php echo $view['form']->renderBlock('choice_widget_options', array('options' => $preferred_choices)) ?>
<?php if (count($choices) > 0 && null !== $separator): ?>
<option disabled="disabled"><?php echo $separator ?></option>
<?php endif ?>
<?php endif ?>
<?php echo $view['form']->renderBlock('choice_widget_options', array('options' => $choices)) ?>
</select>

View File

@ -0,0 +1,6 @@
<div <?php echo $view['form']->renderBlock('widget_container_attributes') ?>>
<?php foreach ($form as $child): ?>
<?php echo $view['form']->widget($child) ?>
<?php echo $view['form']->label($child) ?>
<?php endforeach ?>
</div>

View File

@ -0,0 +1,11 @@
<?php foreach ($options as $index => $choice): ?>
<?php if ($view['form']->isChoiceGroup($choice)): ?>
<optgroup label="<?php echo $view->escape($view['translator']->trans($index, array(), $translation_domain)) ?>">
<?php foreach ($choice as $nested_choice): ?>
<option value="<?php echo $view->escape($nested_choice->getValue()) ?>"<?php if ($view['form']->isChoiceSelected($form, $nested_choice)): ?> selected="selected"<?php endif?>><?php echo $view->escape($view['translator']->trans($nested_choice->getLabel(), array(), $translation_domain)) ?></option>
<?php endforeach ?>
</optgroup>
<?php else: ?>
<option value="<?php echo $view->escape($choice->getValue()) ?>"<?php if ($view['form']->isChoiceSelected($form, $choice)): ?> selected="selected"<?php endif?>><?php echo $view->escape($view['translator']->trans($choice->getLabel(), array(), $translation_domain)) ?></option>
<?php endif ?>
<?php endforeach ?>

View File

@ -1,2 +1 @@
<?php if (!empty($id)): ?>id="<?php echo $view->escape($id) ?>" <?php endif; ?> <?php echo $view['form']->renderBlock('widget_container_attributes') ?>
<?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>

View File

@ -1,7 +1,7 @@
<?php if ($widget == 'single_text'): ?> <?php if ($widget == 'single_text'): ?>
<?php echo $view['form']->renderBlock('input'); ?> <?php echo $view['form']->renderBlock('form_widget_primitive'); ?>
<?php else: ?> <?php else: ?>
<div <?php echo $view['form']->renderBlock('container_attributes') ?>> <div <?php echo $view['form']->renderBlock('widget_container_attributes') ?>>
<?php echo str_replace(array('{{ year }}', '{{ month }}', '{{ day }}'), array( <?php echo str_replace(array('{{ year }}', '{{ month }}', '{{ day }}'), array(
$view['form']->widget($form['year']), $view['form']->widget($form['year']),
$view['form']->widget($form['month']), $view['form']->widget($form['month']),

View File

@ -1,7 +1,7 @@
<?php if ($widget == 'single_text'): ?> <?php if ($widget == 'single_text'): ?>
<?php echo $view['form']->renderBlock('input'); ?> <?php echo $view['form']->renderBlock('form_widget_primitive'); ?>
<?php else: ?> <?php else: ?>
<div <?php echo $view['form']->renderBlock('container_attributes') ?>> <div <?php echo $view['form']->renderBlock('widget_container_attributes') ?>>
<?php echo $view['form']->widget($form['date']).' '.$view['form']->widget($form['time']) ?> <?php echo $view['form']->widget($form['date']).' '.$view['form']->widget($form['time']) ?>
</div> </div>
<?php endif ?> <?php endif ?>

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : 'email')) ?> <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : 'email')) ?>

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input') ?> <?php echo $view['form']->renderBlock('form_widget_primitive') ?>

View File

@ -1,3 +1,3 @@
<?php if ($required) { $attr['class'] = (isset($attr['class']) ? $attr['class'] : '').' required'; } ?> <?php if ($required) { $attr['class'] = (isset($attr['class']) ? $attr['class'] : '').' required'; } ?>
<?php if (!$form->hasChildren()) { $attr['for'] = $id; } ?> <?php if ($primitive) { $attr['for'] = $id; } ?>
<label <?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape($view['translator']->trans($label, array(), $translation_domain)) ?></label> <label <?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape($view['translator']->trans($label, array(), $translation_domain)) ?></label>

View File

@ -1,6 +1,6 @@
<div> <div>
<?php echo $view['form']->label($form, isset($label) ? $label : null) ?> <?php echo $view['form']->label($form, isset($label) ? $label : null) ?>
<?php if (!$form->hasChildren()): ?> <?php if ($primitive): ?>
<?php echo $view['form']->errors($form) ?> <?php echo $view['form']->errors($form) ?>
<?php endif ?> <?php endif ?>
<?php echo $view['form']->widget($form) ?> <?php echo $view['form']->widget($form) ?>

View File

@ -1,8 +1,5 @@
<?php if ($form->hasChildren()): ?> <?php if ($primitive): ?>
<div <?php echo $view['form']->renderBlock('container_attributes') ?>> <?php echo $view['form']->renderBlock('form_widget_primitive')?>
<?php echo $view['form']->renderBlock('form_rows') ?>
<?php echo $view['form']->rest($form) ?>
</div>
<?php else: ?> <?php else: ?>
<?php echo $view['form']->renderBlock('input')?> <?php echo $view['form']->renderBlock('form_widget_complex')?>
<?php endif ?> <?php endif ?>

View File

@ -0,0 +1,4 @@
<div <?php echo $view['form']->renderBlock('widget_container_attributes') ?>>
<?php echo $view['form']->renderBlock('form_rows') ?>
<?php echo $view['form']->rest($form) ?>
</div>

View File

@ -0,0 +1,5 @@
<input
type="<?php echo isset($type) ? $view->escape($type) : 'text' ?>"
<?php if (!empty($value)): ?>value="<?php echo $view->escape($value) ?>"<?php endif ?>
<?php echo $view['form']->renderBlock('widget_attributes') ?>
/>

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : "hidden")) ?> <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : "hidden")) ?>

View File

@ -1,5 +0,0 @@
<input
type="<?php echo isset($type) ? $view->escape($type) : "text" ?>"
<?php if (!empty($value)): ?>value="<?php echo $view->escape($value) ?>"<?php endif ?>
<?php echo $view['form']->renderBlock('attributes') ?>
/>

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : "number")) ?> <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : "number")) ?>

View File

@ -1 +1 @@
<?php echo str_replace('{{ widget }}', $view['form']->renderBlock('input'), $money_pattern) ?> <?php echo str_replace('{{ widget }}', $view['form']->renderBlock('form_widget_primitive'), $money_pattern) ?>

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : "text")) ?> <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : "text")) ?>

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : "password")) ?> <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : "password")) ?>

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : "text")) ?> % <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : "text")) ?> %

View File

@ -1,5 +1,5 @@
<input type="radio" <input type="radio"
<?php echo $view['form']->renderBlock('attributes') ?> <?php echo $view['form']->renderBlock('widget_attributes') ?>
value="<?php echo $view->escape($value) ?>" value="<?php echo $view->escape($value) ?>"
<?php if ($checked): ?> checked="checked"<?php endif ?> <?php if ($checked): ?> checked="checked"<?php endif ?>
/> />

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : "search")) ?> <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : "search")) ?>

View File

@ -1 +1 @@
<textarea <?php echo $view['form']->renderBlock('attributes') ?>><?php echo $view->escape($value) ?></textarea> <textarea <?php echo $view['form']->renderBlock('widget_attributes') ?>><?php echo $view->escape($value) ?></textarea>

View File

@ -1,7 +1,7 @@
<?php if ($widget == 'single_text'): ?> <?php if ($widget == 'single_text'): ?>
<?php echo $view['form']->renderBlock('input'); ?> <?php echo $view['form']->renderBlock('form_widget_primitive'); ?>
<?php else: ?> <?php else: ?>
<div <?php echo $view['form']->renderBlock('container_attributes') ?>> <div <?php echo $view['form']->renderBlock('widget_container_attributes') ?>>
<?php <?php
// There should be no spaces between the colons and the widgets, that's why // There should be no spaces between the colons and the widgets, that's why
// this block is written in a single PHP tag // this block is written in a single PHP tag

View File

@ -1 +1 @@
<?php echo $view['form']->renderBlock('input', array('type' => isset($type) ? $type : "url")) ?> <?php echo $view['form']->renderBlock('form_widget_primitive', array('type' => isset($type) ? $type : "url")) ?>

View File

@ -0,0 +1,9 @@
id="<?php echo $view->escape($id) ?>"
name="<?php echo $view->escape($full_name) ?>"
<?php if ($read_only): ?>readonly="readonly" <?php endif ?>
<?php if ($disabled): ?>disabled="disabled" <?php endif ?>
<?php if ($required): ?>required="required" <?php endif ?>
<?php if ($max_length): ?>maxlength="<?php echo $view->escape($max_length) ?>" <?php endif ?>
<?php if ($pattern): ?>pattern="<?php echo $view->escape($pattern) ?>" <?php endif ?>
<?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>

View File

@ -0,0 +1,2 @@
<?php if (!empty($id)): ?>id="<?php echo $view->escape($id) ?>" <?php endif; ?>
<?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>

View File

@ -1,4 +1,26 @@
<?php if ($form->hasChildren()): ?> <?php if ($primitive): ?>
<?php if ($errors): ?>
<ul>
<?php foreach ($errors as $error): ?>
<li><?php
if (null === $error->getMessagePluralization()) {
echo $view['translator']->trans(
$error->getMessageTemplate(),
$error->getMessageParameters(),
'validators'
);
} else {
echo $view['translator']->transChoice(
$error->getMessageTemplate(),
$error->getMessagePluralization(),
$error->getMessageParameters(),
'validators'
);
}?></li>
<?php endforeach; ?>
</ul>
<?php endif ?>
<?php else: ?>
<?php if (count($errors) > 0): ?> <?php if (count($errors) > 0): ?>
<tr> <tr>
<td colspan="2"> <td colspan="2">
@ -26,26 +48,4 @@
</td> </td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
<?php else: ?>
<?php if ($errors): ?>
<ul>
<?php foreach ($errors as $error): ?>
<li><?php
if (null === $error->getMessagePluralization()) {
echo $view['translator']->trans(
$error->getMessageTemplate(),
$error->getMessageParameters(),
'validators'
);
} else {
echo $view['translator']->transChoice(
$error->getMessageTemplate(),
$error->getMessagePluralization(),
$error->getMessageParameters(),
'validators'
);
}?></li>
<?php endforeach; ?>
</ul>
<?php endif ?>
<?php endif; ?> <?php endif; ?>

View File

@ -3,7 +3,7 @@
<?php echo $view['form']->label($form, isset($label) ? $label : null) ?> <?php echo $view['form']->label($form, isset($label) ? $label : null) ?>
</td> </td>
<td> <td>
<?php if (!$form->hasChildren()): ?> <?php if ($primitive): ?>
<?php echo $view['form']->errors($form) ?> <?php echo $view['form']->errors($form) ?>
<?php endif ?> <?php endif ?>
<?php echo $view['form']->widget($form) ?> <?php echo $view['form']->widget($form) ?>

View File

@ -1,8 +0,0 @@
<?php if ($form->hasChildren()): ?>
<table <?php echo $view['form']->renderBlock('container_attributes') ?>>
<?php echo $view['form']->renderBlock('form_rows') ?>
<?php echo $view['form']->rest($form) ?>
</table>
<?php else: ?>
<?php echo $view['form']->renderBlock('input')?>
<?php endif ?>

View File

@ -0,0 +1,4 @@
<table <?php echo $view['form']->renderBlock('widget_container_attributes') ?>>
<?php echo $view['form']->renderBlock('form_rows') ?>
<?php echo $view['form']->rest($form) ?>
</table>

View File

@ -1,2 +1,2 @@
<?php $type = isset($type) ? $type : 'text' ?> <?php $type = isset($type) ? $type : 'text' ?>
<input type="<?php echo $type ?>" <?php $view['form']->renderBlock('attributes') ?> value="<?php echo $value ?>" rel="theme" /> <input type="<?php echo $type ?>" <?php $view['form']->renderBlock('widget_attributes') ?> value="<?php echo $value ?>" rel="theme" />

View File

@ -25,16 +25,12 @@ CHANGELOG
* [BC BREAK] removed EntitiesToArrayTransformer and EntityToIdTransformer. * [BC BREAK] removed EntitiesToArrayTransformer and EntityToIdTransformer.
The former has been replaced by CollectionToArrayTransformer in combination The former has been replaced by CollectionToArrayTransformer in combination
with EntityChoiceList, the latter is not required in the core anymore. with EntityChoiceList, the latter is not required in the core anymore.
* [BC BREAK] renamed * [BC BREAK] renamed
* ArrayToBooleanChoicesTransformer to ChoicesToBooleanArrayTransformer * ArrayToBooleanChoicesTransformer to ChoicesToBooleanArrayTransformer
* ScalarToBooleanChoicesTransformer to ChoiceToBooleanArrayTransformer * ScalarToBooleanChoicesTransformer to ChoiceToBooleanArrayTransformer
* ArrayToChoicesTransformer to ChoicesToValuesTransformer * ArrayToChoicesTransformer to ChoicesToValuesTransformer
* ScalarToChoiceTransformer to ChoiceToValueTransformer * ScalarToChoiceTransformer to ChoiceToValueTransformer
to be consistent with the naming in ChoiceListInterface.
to be consistent with the naming in ChoiceListInterface.
* [BC BREAK] removed FormUtil::toArrayKey() and FormUtil::toArrayKeys(). * [BC BREAK] removed FormUtil::toArrayKey() and FormUtil::toArrayKeys().
They were merged into ChoiceList and have no public equivalent anymore. They were merged into ChoiceList and have no public equivalent anymore.
* choice fields now throw a FormException if neither the "choices" nor the * choice fields now throw a FormException if neither the "choices" nor the
@ -62,8 +58,13 @@ CHANGELOG
by event subscribers by event subscribers
* simplified CSRF protection and removed the csrf type * simplified CSRF protection and removed the csrf type
* deprecated FieldType and merged it into FormType * deprecated FieldType and merged it into FormType
* [BC BREAK] renamed "field_*" theme blocks to "form_*" and "field_widget" to * [BC BREAK] renamed theme blocks
"input" * "field_*" to "form_*"
* "field_widget" to "form_widget_primitive"
* "widget_choice_options" to "choice_widget_options"
* "generic_label" to "form_label"
* added theme blocks "form_widget_complex", "choice_widget_expanded" and
"choice_widget_collapsed" to make theming more modular
* ValidatorTypeGuesser now guesses "collection" for array type constraint * ValidatorTypeGuesser now guesses "collection" for array type constraint
* added method `guessPattern` to FormTypeGuesserInterface to guess which pattern to use in the HTML5 attribute "pattern" * added method `guessPattern` to FormTypeGuesserInterface to guess which pattern to use in the HTML5 attribute "pattern"
* deprecated method `guessMinLength` in favor of `guessPattern` * deprecated method `guessMinLength` in favor of `guessPattern`

View File

@ -46,11 +46,14 @@ class CheckboxType extends AbstractType
*/ */
public function getDefaultOptions() public function getDefaultOptions()
{ {
$emptyData = function (FormInterface $form, $clientData) {
return $clientData;
};
return array( return array(
'value' => '1', 'value' => '1',
'empty_data' => function (FormInterface $form, $clientData) { 'empty_data' => $emptyData,
return $clientData; 'primitive' => true,
},
); );
} }

View File

@ -165,6 +165,10 @@ class ChoiceType extends AbstractType
return $options['required'] ? null : ''; return $options['required'] ? null : '';
}; };
$primitive = function (Options $options) {
return !$options['expanded'];
};
return array( return array(
'multiple' => false, 'multiple' => false,
'expanded' => false, 'expanded' => false,
@ -174,6 +178,7 @@ class ChoiceType extends AbstractType
'empty_data' => $emptyData, 'empty_data' => $emptyData,
'empty_value' => $emptyValue, 'empty_value' => $emptyValue,
'error_bubbling' => false, 'error_bubbling' => false,
'primitive' => $primitive,
); );
} }

View File

@ -21,6 +21,7 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransfo
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
use Symfony\Component\Form\Options;
class DateTimeType extends AbstractType class DateTimeType extends AbstractType
{ {
@ -130,6 +131,10 @@ class DateTimeType extends AbstractType
*/ */
public function getDefaultOptions() public function getDefaultOptions()
{ {
$primitive = function (Options $options) {
return $options['widget'] === 'single_text';
};
return array( return array(
'input' => 'datetime', 'input' => 'datetime',
'data_timezone' => null, 'data_timezone' => null,
@ -158,6 +163,7 @@ class DateTimeType extends AbstractType
// representation is not \DateTime, but an array, we need to unset // representation is not \DateTime, but an array, we need to unset
// this option. // this option.
'data_class' => null, 'data_class' => null,
'primitive' => $primitive,
); );
} }

View File

@ -11,18 +11,18 @@
namespace Symfony\Component\Form\Extension\Core\Type; namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\Exception\CreationException; use Symfony\Component\Form\Exception\CreationException;
use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\ReversedTransformer; use Symfony\Component\Form\ReversedTransformer;
use Symfony\Component\Form\Options;
class DateType extends AbstractType class DateType extends AbstractType
{ {
@ -163,6 +163,10 @@ class DateType extends AbstractType
*/ */
public function getDefaultOptions() public function getDefaultOptions()
{ {
$primitive = function (Options $options) {
return $options['widget'] === 'single_text';
};
return array( return array(
'years' => range(date('Y') - 5, date('Y') + 5), 'years' => range(date('Y') - 5, date('Y') + 5),
'months' => range(1, 12), 'months' => range(1, 12),
@ -182,6 +186,7 @@ class DateType extends AbstractType
// representation is not \DateTime, but an array, we need to unset // representation is not \DateTime, but an array, we need to unset
// this option. // this option.
'data_class' => null, 'data_class' => null,
'primitive' => $primitive,
); );
} }

View File

@ -38,6 +38,16 @@ class FileType extends AbstractType
; ;
} }
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
{
return array(
'primitive' => true,
);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -61,6 +61,7 @@ class FormType extends AbstractType
->setAttribute('invalid_message_parameters', $options['invalid_message_parameters']) ->setAttribute('invalid_message_parameters', $options['invalid_message_parameters'])
->setAttribute('translation_domain', $options['translation_domain']) ->setAttribute('translation_domain', $options['translation_domain'])
->setAttribute('virtual', $options['virtual']) ->setAttribute('virtual', $options['virtual'])
->setAttribute('primitive', $options['primitive'])
->setData($options['data']) ->setData($options['data'])
->setDataMapper(new PropertyPathMapper($options['data_class'])) ->setDataMapper(new PropertyPathMapper($options['data_class']))
->addEventSubscriber(new ValidationListener()) ->addEventSubscriber(new ValidationListener())
@ -125,6 +126,7 @@ class FormType extends AbstractType
->set('label', $form->getAttribute('label')) ->set('label', $form->getAttribute('label'))
->set('multipart', false) ->set('multipart', false)
->set('attr', $form->getAttribute('attr')) ->set('attr', $form->getAttribute('attr'))
->set('primitive', $form->getAttribute('primitive'))
->set('types', $types) ->set('types', $types)
->set('translation_domain', $form->getAttribute('translation_domain')) ->set('translation_domain', $form->getAttribute('translation_domain'))
; ;
@ -201,6 +203,7 @@ class FormType extends AbstractType
'label' => null, 'label' => null,
'attr' => array(), 'attr' => array(),
'virtual' => false, 'virtual' => false,
'primitive' => false,
'invalid_message' => 'This value is not valid.', 'invalid_message' => 'This value is not valid.',
'invalid_message_parameters' => array(), 'invalid_message_parameters' => array(),
'translation_domain' => 'messages', 'translation_domain' => 'messages',

View File

@ -25,6 +25,7 @@ class HiddenType extends AbstractType
'required' => false, 'required' => false,
// Pass errors to the parent // Pass errors to the parent
'error_bubbling' => true, 'error_bubbling' => true,
'primitive' => true,
); );
} }

View File

@ -41,6 +41,7 @@ class IntegerType extends AbstractType
'grouping' => false, 'grouping' => false,
// Integer cast rounds towards 0, so do the same when displaying fractions // Integer cast rounds towards 0, so do the same when displaying fractions
'rounding_mode' => \NumberFormatter::ROUND_DOWN, 'rounding_mode' => \NumberFormatter::ROUND_DOWN,
'primitive' => true,
); );
} }

View File

@ -55,6 +55,7 @@ class MoneyType extends AbstractType
'grouping' => false, 'grouping' => false,
'divisor' => 1, 'divisor' => 1,
'currency' => 'EUR', 'currency' => 'EUR',
'primitive' => true,
); );
} }

View File

@ -39,6 +39,7 @@ class NumberType extends AbstractType
'precision' => null, 'precision' => null,
'grouping' => false, 'grouping' => false,
'rounding_mode' => \NumberFormatter::ROUND_HALFUP, 'rounding_mode' => \NumberFormatter::ROUND_HALFUP,
'primitive' => true,
); );
} }

View File

@ -33,6 +33,7 @@ class PercentType extends AbstractType
return array( return array(
'precision' => 0, 'precision' => 0,
'type' => 'fractional', 'type' => 'fractional',
'primitive' => true,
); );
} }

View File

@ -27,6 +27,16 @@ class TextType extends AbstractType
; ;
} }
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
{
return array(
'primitive' => true,
);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -20,6 +20,7 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransf
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Options;
class TimeType extends AbstractType class TimeType extends AbstractType
{ {
@ -136,6 +137,10 @@ class TimeType extends AbstractType
*/ */
public function getDefaultOptions() public function getDefaultOptions()
{ {
$primitive = function (Options $options) {
return $options['widget'] === 'single_text';
};
return array( return array(
'hours' => range(0, 23), 'hours' => range(0, 23),
'minutes' => range(0, 59), 'minutes' => range(0, 59),
@ -155,6 +160,7 @@ class TimeType extends AbstractType
// representation is not \DateTime, but an array, we need to unset // representation is not \DateTime, but an array, we need to unset
// this option. // this option.
'data_class' => null, 'data_class' => null,
'primitive' => $primitive,
); );
} }

View File

@ -277,6 +277,19 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
); );
} }
public function testEmptyCollection()
{
$form = $this->factory->createNamed('collection', 'name', array(), array(
'type' => 'text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[count(./div)=0]
'
);
}
public function testCollectionRow() public function testCollectionRow()
{ {
$collection = $this->factory->createNamedBuilder( $collection = $this->factory->createNamedBuilder(

View File

@ -170,6 +170,19 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
); );
} }
public function testEmptyCollection()
{
$form = $this->factory->createNamed('collection', 'name', array(), array(
'type' => 'text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/table
[count(./tr[./td/input])=0]
'
);
}
public function testForm() public function testForm()
{ {
$view = $this->factory->createNamedBuilder('form', 'name') $view = $this->factory->createNamedBuilder('form', 'name')

View File

@ -619,8 +619,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
'"attr", "by_reference", "data", "data_class", "disabled", ' . '"attr", "by_reference", "data", "data_class", "disabled", ' .
'"empty_data", "error_bubbling", "error_mapping", "invalid_message", ' . '"empty_data", "error_bubbling", "error_mapping", "invalid_message", ' .
'"invalid_message_parameters", "label", "max_length", "pattern", ' . '"invalid_message_parameters", "label", "max_length", "pattern", ' .
'"property_path", "read_only", "required", "translation_domain", ' . '"primitive", "property_path", "read_only", "required", ' .
'"trim"' '"translation_domain", "trim"'
); );
$factory->createNamedBuilder($type, "text", "value", array("invalid" => "opt", "unknown" => "opt")); $factory->createNamedBuilder($type, "text", "value", array("invalid" => "opt", "unknown" => "opt"));
} }
@ -636,8 +636,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
'"by_reference", "data", "data_class", "disabled", "empty_data", ' . '"by_reference", "data", "data_class", "disabled", "empty_data", ' .
'"error_bubbling", "error_mapping", "invalid_message", ' . '"error_bubbling", "error_mapping", "invalid_message", ' .
'"invalid_message_parameters", "label", "max_length", "pattern", ' . '"invalid_message_parameters", "label", "max_length", "pattern", ' .
'"property_path", "read_only", "required", "translation_domain", ' . '"primitive", "property_path", "read_only", "required", ' .
'"trim"' '"translation_domain", "trim"'
); );
$factory->createNamedBuilder($type, "text", "value", array("unknown" => "opt")); $factory->createNamedBuilder($type, "text", "value", array("unknown" => "opt"));
} }