[Form] Deprecated FieldType, which has been merged into FormType

This commit is contained in:
Bernhard Schussek 2012-04-13 16:06:32 +02:00
parent bfa7ef2d9b
commit fcb2227ac9
72 changed files with 1016 additions and 826 deletions

View File

@ -267,9 +267,12 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
in their name anymore. Their names terminate with "[]" now. in their name anymore. Their names terminate with "[]" now.
* [BC BREAK] FormType::getDefaultOptions() and FormType::getAllowedOptionValues() * [BC BREAK] FormType::getDefaultOptions() and FormType::getAllowedOptionValues()
don't receive an options array anymore. don't receive an options array anymore.
* Deprecated FormValidatorInterface and substituted its implementations * deprecated FormValidatorInterface and substituted its implementations
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
* [BC BREAK] renamed "field_*" theme blocks to "form_*" and "field_widget" to
"input"
### HttpFoundation ### HttpFoundation

View File

@ -94,7 +94,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
@ -372,29 +372,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()
{ {
@ -405,7 +405,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.
@ -425,6 +425,100 @@
(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`.
* FieldType was merged into FormType. FieldType itself was deprecated and
will be removed in Symfony 2.3.
##### Update your field types
You are advised to update your custom types that extend FieldType to extend
FormType instead.
Before:
```
public function getParent(array $options)
{
return 'field';
}
```
After:
```
public function getParent(array $options)
{
return 'form';
}
```
You can also remove the getParent() method as this is the default
implementation in AbstractType.
##### Update your form themes
Previously, FieldType was the super type for all other types. Now, since
it is deprecated, FieldType is a subtype of FormType, which is now the base
type for all other types.
A consequence of this change is that any "form_*" blocks defined in your
themes are now also used for other types that extend "field", unless you
explicitely override the "field_*" or "mytype_*" blocks.
"field_*" blocks are deprecated and will be unsupported as of Symfony 2.3.
You should merge them into the corresponding "form_*" blocks instead.
Before:
```
{% block field_label %}
{% spaceless %}
{% set attr = attr|merge({'for': id}) %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock field_label %}
{% block form_label %}
{% spaceless %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock form_label %}
```
After:
```
{% block form_label %}
{% spaceless %}
{% if form.children|length == 0 %}
{% set attr = attr|merge({'for': id}) %}
{% endif %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock form_label %}
```
The block "field_widget" was renamed to "input" and is still supported.
Before:
```
{% block field_widget %}
{% spaceless %}
<!-- custom input tag -->
{% endspaceless %}
{% endblock field_widget %}
```
After:
```
{% block input %}
{% spaceless %}
<!-- custom input tag -->
{% endspaceless %}
{% endblock input %}
```
### Session ### Session
* Flash messages now return an array based on their type. The old method is * Flash messages now return an array based on their type. The old method is

View File

@ -2,10 +2,14 @@
{% block form_widget %} {% block form_widget %}
{% spaceless %} {% spaceless %}
<div {{ block('widget_container_attributes') }}> {% if form.children|length > 0 %}
{{ block('field_rows') }} <div {{ block('widget_container_attributes') }}>
{{ form_rest(form) }} {{ block('form_rows') }}
</div> {{ form_rest(form) }}
</div>
{% else %}
{{ block('input') }}
{% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock form_widget %} {% endblock form_widget %}
@ -83,7 +87,7 @@
{% block datetime_widget %} {% block datetime_widget %}
{% spaceless %} {% spaceless %}
{% if widget == 'single_text' %} {% if widget == 'single_text' %}
{{ block('field_widget') }} {{ block('input') }}
{% else %} {% else %}
<div {{ block('widget_container_attributes') }}> <div {{ block('widget_container_attributes') }}>
{{ form_errors(form.date) }} {{ form_errors(form.date) }}
@ -98,7 +102,7 @@
{% block date_widget %} {% block date_widget %}
{% spaceless %} {% spaceless %}
{% if widget == 'single_text' %} {% if widget == 'single_text' %}
{{ block('field_widget') }} {{ block('input') }}
{% else %} {% else %}
<div {{ block('widget_container_attributes') }}> <div {{ block('widget_container_attributes') }}>
{{ date_pattern|replace({ {{ date_pattern|replace({
@ -114,7 +118,7 @@
{% block time_widget %} {% block time_widget %}
{% spaceless %} {% spaceless %}
{% if widget == 'single_text' %} {% if widget == 'single_text' %}
{{ block('field_widget') }} {{ block('input') }}
{% 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 %}
@ -127,67 +131,60 @@
{% 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('field_widget') }} {{ block('input') }}
{% 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('field_widget') }} {{ block('input') }}
{% endspaceless %} {% endspaceless %}
{% endblock integer_widget %} {% endblock integer_widget %}
{% block money_widget %} {% block money_widget %}
{% spaceless %} {% spaceless %}
{{ money_pattern|replace({ '{{ widget }}': block('field_widget') })|raw }} {{ money_pattern|replace({ '{{ widget }}': block('input') })|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('field_widget') }} {{ block('input') }}
{% 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('field_widget') }} {{ block('input') }}
{% 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('field_widget') }} % {{ block('input') }} %
{% endspaceless %} {% endspaceless %}
{% endblock percent_widget %} {% endblock percent_widget %}
{% block field_widget %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock field_widget %}
{% block password_widget %} {% block password_widget %}
{% spaceless %} {% spaceless %}
{% set type = type|default('password') %} {% set type = type|default('password') %}
{{ block('field_widget') }} {{ block('input') }}
{% endspaceless %} {% endspaceless %}
{% endblock password_widget %} {% endblock password_widget %}
{% block hidden_widget %} {% block hidden_widget %}
{% set type = type|default('hidden') %} {% set type = type|default('hidden') %}
{{ block('field_widget') }} {{ block('input') }}
{% 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('field_widget') }} {{ block('input') }}
{% endspaceless %} {% endspaceless %}
{% endblock email_widget %} {% endblock email_widget %}
@ -202,15 +199,11 @@
{% endspaceless %} {% endspaceless %}
{% endblock %} {% endblock %}
{% block field_label %}
{% spaceless %}
{% set attr = attr|merge({'for': id}) %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock field_label %}
{% block form_label %} {% block form_label %}
{% spaceless %} {% spaceless %}
{% if form.children|length == 0 %}
{% set attr = attr|merge({'for': id}) %}
{% endif %}
{{ block('generic_label') }} {{ block('generic_label') }}
{% endspaceless %} {% endspaceless %}
{% endblock form_label %} {% endblock form_label %}
@ -219,24 +212,17 @@
{% block repeated_row %} {% block repeated_row %}
{% spaceless %} {% spaceless %}
{{ block('field_rows') }} {{ block('form_rows') }}
{% endspaceless %} {% endspaceless %}
{% endblock repeated_row %} {% endblock repeated_row %}
{% block field_row %}
{% spaceless %}
<div>
{{ form_label(form, label|default(null)) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock field_row %}
{% block form_row %} {% block form_row %}
{% spaceless %} {% spaceless %}
<div> <div>
{{ form_label(form, label|default(null)) }} {{ form_label(form, label|default(null)) }}
{% if form.children|length == 0 %}
{{ form_errors(form) }}
{% endif %}
{{ form_widget(form) }} {{ form_widget(form) }}
</div> </div>
{% endspaceless %} {% endspaceless %}
@ -248,13 +234,13 @@
{# Misc #} {# Misc #}
{% block field_enctype %} {% block form_enctype %}
{% spaceless %} {% spaceless %}
{% if multipart %}enctype="multipart/form-data"{% endif %} {% if multipart %}enctype="multipart/form-data"{% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock field_enctype %} {% endblock form_enctype %}
{% block field_errors %} {% block form_errors %}
{% spaceless %} {% spaceless %}
{% if errors|length > 0 %} {% if errors|length > 0 %}
<ul> <ul>
@ -270,9 +256,9 @@
</ul> </ul>
{% endif %} {% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock field_errors %} {% endblock form_errors %}
{% block field_rest %} {% block form_rest %}
{% spaceless %} {% spaceless %}
{% for child in form %} {% for child in form %}
{% if not child.rendered %} {% if not child.rendered %}
@ -280,18 +266,25 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endspaceless %} {% endspaceless %}
{% endblock field_rest %} {% endblock form_rest %}
{# Support #} {# Support #}
{% block field_rows %} {% block form_rows %}
{% spaceless %} {% spaceless %}
{{ form_errors(form) }} {{ form_errors(form) }}
{% for child in form %} {% for child in form %}
{{ form_row(child) }} {{ form_row(child) }}
{% endfor %} {% endfor %}
{% endspaceless %} {% endspaceless %}
{% endblock field_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 %}
@ -306,3 +299,47 @@
{% for attrname,attrvalue in attr %}{{attrname}}="{{attrvalue}}" {% endfor %} {% for attrname,attrvalue in attr %}{{attrname}}="{{attrvalue}}" {% endfor %}
{% endspaceless %} {% endspaceless %}
{% endblock widget_container_attributes %} {% endblock widget_container_attributes %}
{# Deprecated in Symfony 2.1, to be removed in 2.3 #}
{% block field_widget %}
{% spaceless %}
{{ block('input') }}
{% endspaceless %}
{% endblock field_widget %}
{% block field_label %}
{% spaceless %}
{{ block('form_label') }}
{% 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

@ -1,19 +1,5 @@
{% use "form_div_layout.html.twig" %} {% use "form_div_layout.html.twig" %}
{% block field_row %}
{% spaceless %}
<tr>
<td>
{{ form_label(form, label|default(null)) }}
</td>
<td>
{{ form_errors(form) }}
{{ form_widget(form) }}
</td>
</tr>
{% endspaceless %}
{% endblock field_row %}
{% block form_row %} {% block form_row %}
{% spaceless %} {% spaceless %}
<tr> <tr>
@ -21,6 +7,9 @@
{{ form_label(form, label|default(null)) }} {{ form_label(form, label|default(null)) }}
</td> </td>
<td> <td>
{% if form.children|length == 0 %}
{{ form_errors(form) }}
{% endif %}
{{ form_widget(form) }} {{ form_widget(form) }}
</td> </td>
</tr> </tr>
@ -29,12 +18,16 @@
{% block form_errors %} {% block form_errors %}
{% spaceless %} {% spaceless %}
{% if errors|length > 0 %} {% if form.children|length > 0 %}
<tr> {% if errors|length > 0 %}
<td colspan="2"> <tr>
{{ block('field_errors') }} <td colspan="2">
</td> {{ parent() }}
</tr> </td>
</tr>
{% endif %}
{% else %}
{{ parent() }}
{% endif %} {% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock form_errors %} {% endblock form_errors %}
@ -51,9 +44,13 @@
{% block form_widget %} {% block form_widget %}
{% spaceless %} {% spaceless %}
<table {{ block('widget_container_attributes') }}> {% if form.children|length > 0 %}
{{ block('field_rows') }} <table {{ block('widget_container_attributes') }}>
{{ form_rest(form) }} {{ block('form_rows') }}
</table> {{ form_rest(form) }}
</table>
{% else %}
{{ parent() }}
{% endif %}
{% endspaceless %} {% endspaceless %}
{% endblock form_widget %} {% endblock form_widget %}

View File

@ -1,3 +1,3 @@
{% block field_label %} {% block form_label %}
<label>child</label> <label>child</label>
{% endblock field_label %} {% endblock form_label %}

View File

@ -1,3 +1,3 @@
{% block field_label %} {% block form_label %}
<label>parent</label> <label>parent</label>
{% endblock field_label %} {% endblock form_label %}

View File

@ -1,6 +1,6 @@
{% block field_widget %} {% block input %}
{% 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('attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %} {% endspaceless %}
{% endblock field_widget %} {% endblock input %}

View File

@ -1,8 +1,8 @@
{% extends 'form_div_layout.html.twig' %} {% extends 'form_div_layout.html.twig' %}
{% block field_widget %} {% block input %}
{% 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('attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %} {% endspaceless %}
{% endblock field_widget %} {% endblock input %}

View File

@ -1,8 +1,8 @@
{% use 'form_div_layout.html.twig' %} {% use 'form_div_layout.html.twig' %}
{% block field_widget %} {% block input %}
{% 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('attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %} {% endspaceless %}
{% endblock field_widget %} {% endblock input %}

View File

@ -52,7 +52,6 @@
<!-- CoreExtension --> <!-- CoreExtension -->
<service id="form.type.field" class="Symfony\Component\Form\Extension\Core\Type\FieldType"> <service id="form.type.field" class="Symfony\Component\Form\Extension\Core\Type\FieldType">
<tag name="form.type" alias="field" /> <tag name="form.type" alias="field" />
<argument type="service" id="validator" />
</service> </service>
<service id="form.type.form" class="Symfony\Component\Form\Extension\Core\Type\FormType"> <service id="form.type.form" class="Symfony\Component\Form\Extension\Core\Type\FormType">
<tag name="form.type" alias="form" /> <tag name="form.type" alias="form" />
@ -133,8 +132,8 @@
<tag name="form.type" alias="url" /> <tag name="form.type" alias="url" />
</service> </service>
<!-- FieldTypeValidatorExtension --> <!-- FormTypeValidatorExtension -->
<service id="form.type_extension.field" class="Symfony\Component\Form\Extension\Validator\Type\FieldTypeValidatorExtension"> <service id="form.type_extension.field" class="Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension">
<tag name="form.type_extension" alias="field" /> <tag name="form.type_extension" alias="field" />
<argument type="service" id="validator" /> <argument type="service" id="validator" />
</service> </service>

View File

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

View File

@ -1,5 +1,5 @@
<?php if ($widget == 'single_text'): ?> <?php if ($widget == 'single_text'): ?>
<?php echo $view['form']->renderBlock('field_widget'); ?> <?php echo $view['form']->renderBlock('input'); ?>
<?php else: ?> <?php else: ?>
<div <?php echo $view['form']->renderBlock('container_attributes') ?>> <div <?php echo $view['form']->renderBlock('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']) ?>

View File

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

View File

@ -1 +1 @@
<?php if ($form->get('multipart')): ?>enctype="multipart/form-data"<?php endif ?> <?php echo $view['form']->renderBlock('form_enctype') ?>

View File

@ -1,21 +1 @@
<?php if ($errors): ?> <?php echo $view['form']->renderBlock('form_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 ?>

View File

@ -1,2 +1 @@
<?php if ($required) { $attr['class'] = (isset($attr['class']) ? $attr['class'] : '').' required'; } ?> <?php echo $view['form']->renderBlock('form_label') ?>
<label for="<?php echo $view->escape($id) ?>" <?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,5 +1 @@
<?php foreach ($form as $child): ?> <?php echo $view['form']->renderBlock('form_rest') ?>
<?php if (!$child->isRendered()): ?>
<?php echo $view['form']->row($child) ?>
<?php endif; ?>
<?php endforeach; ?>

View File

@ -1,5 +1 @@
<div> <?php echo $view['form']->renderBlock('form_row') ?>
<?php echo $view['form']->label($form, isset($label) ? $label : null) ?>
<?php echo $view['form']->errors($form) ?>
<?php echo $view['form']->widget($form) ?>
</div>

View File

@ -1,4 +1 @@
<?php echo $view['form']->errors($form) ?> <?php echo $view['form']->renderBlock('form_rows') ?>
<?php foreach ($form as $child) : ?>
<?php echo $view['form']->row($child) ?>
<?php endforeach; ?>

View File

@ -1,5 +1 @@
<input <?php echo $view['form']->renderBlock('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

@ -0,0 +1 @@
<?php if ($form->get('multipart')): ?>enctype="multipart/form-data"<?php endif ?>

View File

@ -0,0 +1,21 @@
<?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 ?>

View File

@ -1,2 +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; } ?>
<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

@ -0,0 +1,5 @@
<?php foreach ($form as $child): ?>
<?php if (!$child->isRendered()): ?>
<?php echo $view['form']->row($child) ?>
<?php endif; ?>
<?php endforeach; ?>

View File

@ -1,4 +1,7 @@
<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 echo $view['form']->errors($form) ?>
<?php endif ?>
<?php echo $view['form']->widget($form) ?> <?php echo $view['form']->widget($form) ?>
</div> </div>

View File

@ -0,0 +1,4 @@
<?php echo $view['form']->errors($form) ?>
<?php foreach ($form as $child) : ?>
<?php echo $view['form']->row($child) ?>
<?php endforeach; ?>

View File

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

View File

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

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('attributes') ?>
/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<?php if ($widget == 'single_text'): ?> <?php if ($widget == 'single_text'): ?>
<?php echo $view['form']->renderBlock('field_widget'); ?> <?php echo $view['form']->renderBlock('input'); ?>
<?php else: ?> <?php else: ?>
<div <?php echo $view['form']->renderBlock('container_attributes') ?>> <div <?php echo $view['form']->renderBlock('container_attributes') ?>>
<?php <?php

View File

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

View File

@ -1,9 +0,0 @@
<tr>
<td>
<?php echo $view['form']->label($form, isset($label) ? $label : null) ?>
</td>
<td>
<?php echo $view['form']->errors($form) ?>
<?php echo $view['form']->widget($form) ?>
</td>
</tr>

View File

@ -1,7 +1,51 @@
<?php if (0 < count($errors)) : ?> <?php if ($form->hasChildren()): ?>
<tr> <?php if (count($errors) > 0): ?>
<td colspan="2"> <tr>
<?php echo $view['form']->renderBlock('field_errors'); ?> <td colspan="2">
</td> <?php if ($errors): ?>
</tr> <ul>
<?php endif; ?> <?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 ?>
</td>
</tr>
<?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; ?>

View File

@ -3,6 +3,9 @@
<?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 echo $view['form']->errors($form) ?>
<?php endif ?>
<?php echo $view['form']->widget($form) ?> <?php echo $view['form']->widget($form) ?>
</td> </td>
</tr> </tr>

View File

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

View File

@ -119,7 +119,7 @@ class FormHelper extends Helper
*/ */
public function widget(FormView $view, array $variables = array()) public function widget(FormView $view, array $variables = array())
{ {
return trim($this->renderSection($view, 'widget', $variables)); return $this->renderSection($view, 'widget', $variables);
} }
/** /**
@ -276,7 +276,7 @@ class FormHelper extends Helper
$view->setRendered(); $view->setRendered();
} }
return $html; return trim($html);
} }
} while (--$typeIndex >= 0); } while (--$typeIndex >= 0);
@ -311,7 +311,7 @@ class FormHelper extends Helper
$variables = array_replace_recursive($context['variables'], $variables); $variables = array_replace_recursive($context['variables'], $variables);
return $this->engine->render($template, $variables); return trim($this->engine->render($template, $variables));
} }
public function getName() public function getName()

View File

@ -24,7 +24,7 @@ interface DataTransformerInterface
* This method is called on two occasions inside a form field: * This method is called on two occasions inside a form field:
* *
* 1. When the form field is initialized with the data attached from the datasource (object or array). * 1. When the form field is initialized with the data attached from the datasource (object or array).
* 2. When data from a request is bound using {@link Field::bind()} to transform the new input data * 2. When data from a request is bound using {@link Form::bind()} to transform the new input data
* back into the renderable format. For example if you have a date field and bind '2009-10-10' onto * back into the renderable format. For example if you have a date field and bind '2009-10-10' onto
* it you might accept this value because its easily parsed, but the transformer still writes back * it you might accept this value because its easily parsed, but the transformer still writes back
* "2009/10/10" onto the form field (for further displaying or other purposes). * "2009/10/10" onto the form field (for further displaying or other purposes).
@ -52,7 +52,7 @@ interface DataTransformerInterface
* Transforms a value from the transformed representation to its original * Transforms a value from the transformed representation to its original
* representation. * representation.
* *
* This method is called when {@link Field::bind()} is called to transform the requests tainted data * This method is called when {@link Form::bind()} is called to transform the requests tainted data
* into an acceptable format for your data processing/model layer. * into an acceptable format for your data processing/model layer.
* *
* This method must be able to deal with empty values. Usually this will * This method must be able to deal with empty values. Usually this will

View File

@ -44,8 +44,8 @@ class ChoiceType extends AbstractType
} }
if ($options['expanded']) { if ($options['expanded']) {
$this->addSubFields($builder, $options['choice_list']->getPreferredViews(), $options); $this->addSubForms($builder, $options['choice_list']->getPreferredViews(), $options);
$this->addSubFields($builder, $options['choice_list']->getRemainingViews(), $options); $this->addSubForms($builder, $options['choice_list']->getRemainingViews(), $options);
} }
// empty value // empty value
@ -182,7 +182,7 @@ class ChoiceType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return isset($options['expanded']) && $options['expanded'] ? 'form' : 'field'; return 'field';
} }
/** /**
@ -200,12 +200,12 @@ class ChoiceType extends AbstractType
* @param array $choiceViews The choice view objects. * @param array $choiceViews The choice view objects.
* @param array $options The build options. * @param array $options The build options.
*/ */
private function addSubFields(FormBuilder $builder, array $choiceViews, array $options) private function addSubForms(FormBuilder $builder, array $choiceViews, array $options)
{ {
foreach ($choiceViews as $i => $choiceView) { foreach ($choiceViews as $i => $choiceView) {
if (is_array($choiceView)) { if (is_array($choiceView)) {
// Flatten groups // Flatten groups
$this->addSubFields($builder, $choiceView, $options); $this->addSubForms($builder, $choiceView, $options);
} else { } else {
$choiceOpts = array( $choiceOpts = array(
'value' => $choiceView->getValue(), 'value' => $choiceView->getValue(),

View File

@ -153,7 +153,7 @@ class DateTimeType extends AbstractType
'widget' => null, 'widget' => null,
// This will overwrite "empty_value" child options // This will overwrite "empty_value" child options
'empty_value' => null, 'empty_value' => null,
// If initialized with a \DateTime object, FieldType initializes // If initialized with a \DateTime object, FormType initializes
// this option to "\DateTime". Since the internal, normalized // this option to "\DateTime". Since the internal, normalized
// 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.
@ -200,7 +200,7 @@ class DateTimeType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form'; return 'field';
} }
/** /**

View File

@ -177,7 +177,7 @@ class DateType extends AbstractType
// them like immutable value objects // them like immutable value objects
'by_reference' => false, 'by_reference' => false,
'error_bubbling' => false, 'error_bubbling' => false,
// If initialized with a \DateTime object, FieldType initializes // If initialized with a \DateTime object, FormType initializes
// this option to "\DateTime". Since the internal, normalized // this option to "\DateTime". Since the internal, normalized
// 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.
@ -210,7 +210,7 @@ class DateType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form'; return 'field';
} }
/** /**

View File

@ -23,179 +23,15 @@ use Symfony\Component\Form\Extension\Core\EventListener\ValidationListener;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Exception\FormException; use Symfony\Component\Form\Exception\FormException;
/**
* Deprecated. You should extend FormType instead.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
class FieldType extends AbstractType class FieldType extends AbstractType
{ {
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
{
if (null === $options['property_path']) {
$options['property_path'] = $builder->getName();
}
if (false === $options['property_path'] || '' === $options['property_path']) {
$options['property_path'] = null;
} else {
$options['property_path'] = new PropertyPath($options['property_path']);
}
if (!is_array($options['attr'])) {
throw new FormException('The "attr" option must be "array".');
}
$builder
->setRequired($options['required'])
->setDisabled($options['disabled'])
->setErrorBubbling($options['error_bubbling'])
->setEmptyData($options['empty_data'])
->setAttribute('read_only', $options['read_only'])
->setAttribute('by_reference', $options['by_reference'])
->setAttribute('property_path', $options['property_path'])
->setAttribute('error_mapping', $options['error_mapping'])
->setAttribute('max_length', $options['max_length'])
->setAttribute('pattern', $options['pattern'])
->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
->setAttribute('attr', $options['attr'] ?: array())
->setAttribute('invalid_message', $options['invalid_message'])
->setAttribute('invalid_message_parameters', $options['invalid_message_parameters'])
->setAttribute('translation_domain', $options['translation_domain'])
->setData($options['data'])
->addEventSubscriber(new ValidationListener())
;
if ($options['trim']) {
$builder->addEventSubscriber(new TrimListener());
}
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
{
$name = $form->getName();
$readOnly = $form->getAttribute('read_only');
if ($view->hasParent()) {
if ('' === $name) {
throw new FormException('Form node with empty name can be used only as root form node.');
}
if ('' !== ($parentFullName = $view->getParent()->get('full_name'))) {
$id = sprintf('%s_%s', $view->getParent()->get('id'), $name);
$fullName = sprintf('%s[%s]', $parentFullName, $name);
} else {
$id = $name;
$fullName = $name;
}
// Complex fields are read-only if themselves or their parent is.
$readOnly = $readOnly || $view->getParent()->get('read_only');
} else {
$id = $name;
$fullName = $name;
// Strip leading underscores and digits. These are allowed in
// form names, but not in HTML4 ID attributes.
// http://www.w3.org/TR/html401/struct/global.html#adef-id
$id = ltrim($id, '_0123456789');
}
$types = array();
foreach ($form->getTypes() as $type) {
$types[] = $type->getName();
}
$view
->set('form', $view)
->set('id', $id)
->set('name', $name)
->set('full_name', $fullName)
->set('read_only', $readOnly)
->set('errors', $form->getErrors())
->set('value', $form->getClientData())
->set('disabled', $form->isDisabled())
->set('required', $form->isRequired())
->set('max_length', $form->getAttribute('max_length'))
->set('pattern', $form->getAttribute('pattern'))
->set('size', null)
->set('label', $form->getAttribute('label'))
->set('multipart', false)
->set('attr', $form->getAttribute('attr'))
->set('types', $types)
->set('translation_domain', $form->getAttribute('translation_domain'))
;
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
{
// Derive "data_class" option from passed "data" object
$dataClass = function (Options $options) {
if (is_object($options['data'])) {
return get_class($options['data']);
}
return null;
};
// Derive "empty_data" closure from "data_class" option
$emptyData = function (Options $options) {
$class = $options['data_class'];
if (null !== $class) {
return function (FormInterface $form) use ($class) {
if ($form->isEmpty() && !$form->isRequired()) {
return null;
}
return new $class();
};
}
return '';
};
return array(
'data' => null,
'data_class' => $dataClass,
'empty_data' => $emptyData,
'trim' => true,
'required' => true,
'read_only' => false,
'disabled' => false,
'max_length' => null,
'pattern' => null,
'property_path' => null,
'by_reference' => true,
'error_bubbling' => false,
'error_mapping' => array(),
'label' => null,
'attr' => array(),
'invalid_message' => 'This value is not valid',
'invalid_message_parameters' => array(),
'translation_domain' => 'messages',
);
}
/**
* {@inheritdoc}
*/
public function createBuilder($name, FormFactoryInterface $factory, array $options)
{
return new FormBuilder($name, $factory, new EventDispatcher(), $options['data_class']);
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
{
return null;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -203,9 +39,4 @@ class FieldType extends AbstractType
{ {
return 'field'; return 'field';
} }
private function humanize($text)
{
return ucfirst(trim(strtolower(preg_replace('/[_\s]+/', ' ', $text))));
}
} }

View File

@ -23,12 +23,24 @@ class FileType extends AbstractType
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form)
{ {
$view $view
->set('multipart', true)
->set('type', 'file') ->set('type', 'file')
->set('value', '') ->set('value', '')
; ;
} }
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
{
$view
->set('multipart', true)
;
}
/**
* {@inheritdoc}
*/
public function getParent(array $options) public function getParent(array $options)
{ {
return 'field'; return 'field';

View File

@ -13,10 +13,16 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Options; use Symfony\Component\Form\Options;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
use Symfony\Component\Form\Extension\Core\EventListener\ValidationListener;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Exception\FormException;
class FormType extends AbstractType class FormType extends AbstractType
{ {
@ -25,9 +31,102 @@ class FormType extends AbstractType
*/ */
public function buildForm(FormBuilder $builder, array $options) public function buildForm(FormBuilder $builder, array $options)
{ {
if (null === $options['property_path']) {
$options['property_path'] = $builder->getName();
}
if (false === $options['property_path'] || '' === $options['property_path']) {
$options['property_path'] = null;
} else {
$options['property_path'] = new PropertyPath($options['property_path']);
}
if (!is_array($options['attr'])) {
throw new FormException('The "attr" option must be "array".');
}
$builder $builder
->setRequired($options['required'])
->setDisabled($options['disabled'])
->setErrorBubbling($options['error_bubbling'])
->setEmptyData($options['empty_data'])
->setAttribute('read_only', $options['read_only'])
->setAttribute('by_reference', $options['by_reference'])
->setAttribute('property_path', $options['property_path'])
->setAttribute('error_mapping', $options['error_mapping'])
->setAttribute('max_length', $options['max_length'])
->setAttribute('pattern', $options['pattern'])
->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
->setAttribute('attr', $options['attr'] ?: array())
->setAttribute('invalid_message', $options['invalid_message'])
->setAttribute('invalid_message_parameters', $options['invalid_message_parameters'])
->setAttribute('translation_domain', $options['translation_domain'])
->setAttribute('virtual', $options['virtual']) ->setAttribute('virtual', $options['virtual'])
->setData($options['data'])
->setDataMapper(new PropertyPathMapper($options['data_class'])) ->setDataMapper(new PropertyPathMapper($options['data_class']))
->addEventSubscriber(new ValidationListener())
;
if ($options['trim']) {
$builder->addEventSubscriber(new TrimListener());
}
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
{
$name = $form->getName();
$readOnly = $form->getAttribute('read_only');
if ($view->hasParent()) {
if ('' === $name) {
throw new FormException('Form node with empty name can be used only as root form node.');
}
if ('' !== ($parentFullName = $view->getParent()->get('full_name'))) {
$id = sprintf('%s_%s', $view->getParent()->get('id'), $name);
$fullName = sprintf('%s[%s]', $parentFullName, $name);
} else {
$id = $name;
$fullName = $name;
}
// Complex fields are read-only if themselves or their parent is.
$readOnly = $readOnly || $view->getParent()->get('read_only');
} else {
$id = $name;
$fullName = $name;
// Strip leading underscores and digits. These are allowed in
// form names, but not in HTML4 ID attributes.
// http://www.w3.org/TR/html401/struct/global.html#adef-id
$id = ltrim($id, '_0123456789');
}
$types = array();
foreach ($form->getTypes() as $type) {
$types[] = $type->getName();
}
$view
->set('form', $view)
->set('id', $id)
->set('name', $name)
->set('full_name', $fullName)
->set('read_only', $readOnly)
->set('errors', $form->getErrors())
->set('value', $form->getClientData())
->set('disabled', $form->isDisabled())
->set('required', $form->isRequired())
->set('max_length', $form->getAttribute('max_length'))
->set('pattern', $form->getAttribute('pattern'))
->set('size', null)
->set('label', $form->getAttribute('label'))
->set('multipart', false)
->set('attr', $form->getAttribute('attr'))
->set('types', $types)
->set('translation_domain', $form->getAttribute('translation_domain'))
; ;
} }
@ -53,29 +152,75 @@ class FormType extends AbstractType
*/ */
public function getDefaultOptions() public function getDefaultOptions()
{ {
$emptyData = function (Options $options, $currentValue) { // Derive "data_class" option from passed "data" object
if (empty($options['data_class'])) { $dataClass = function (Options $options) {
return array(); if (is_object($options['data'])) {
return get_class($options['data']);
} }
return $currentValue; return null;
}; };
// Derive "empty_data" closure from "data_class" option
$emptyData = function (Options $options) {
$class = $options['data_class'];
if (null !== $class) {
return function (FormInterface $form) use ($class) {
if ($form->isEmpty() && !$form->isRequired()) {
return null;
}
return new $class();
};
}
return function (FormInterface $form) {
if ($form->hasChildren()) {
return array();
}
};
return '';
};
return array( return array(
'data' => null,
'data_class' => $dataClass,
'empty_data' => $emptyData, 'empty_data' => $emptyData,
'trim' => true,
'required' => true,
'read_only' => false,
'disabled' => false,
'max_length' => null,
'pattern' => null,
'property_path' => null,
'by_reference' => true,
'error_bubbling' => false,
'error_mapping' => array(),
'label' => null,
'attr' => array(),
'virtual' => false, 'virtual' => false,
// Errors in forms bubble by default, so that form errors will 'invalid_message' => 'This value is not valid',
// end up as global errors in the root form 'invalid_message_parameters' => array(),
'error_bubbling' => true, 'translation_domain' => 'messages',
); );
} }
/**
* {@inheritdoc}
*/
public function createBuilder($name, FormFactoryInterface $factory, array $options)
{
return new FormBuilder($name, $factory, new EventDispatcher(), $options['data_class']);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return 'field'; return null;
} }
/** /**
@ -85,4 +230,9 @@ class FormType extends AbstractType
{ {
return 'form'; return 'form';
} }
private function humanize($text)
{
return ucfirst(trim(strtolower(preg_replace('/[_\s]+/', ' ', $text))));
}
} }

View File

@ -150,7 +150,7 @@ class TimeType extends AbstractType
// them like immutable value objects // them like immutable value objects
'by_reference' => false, 'by_reference' => false,
'error_bubbling' => false, 'error_bubbling' => false,
// If initialized with a \DateTime object, FieldType initializes // If initialized with a \DateTime object, FormType initializes
// this option to "\DateTime". Since the internal, normalized // this option to "\DateTime". Since the internal, normalized
// 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.
@ -183,7 +183,7 @@ class TimeType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form'; return 'field';
} }
/** /**

View File

@ -19,7 +19,7 @@ use Symfony\Component\Validator\ValidatorInterface;
/** /**
* @author Bernhard Schussek <bschussek@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com>
*/ */
class FieldTypeValidatorExtension extends AbstractTypeExtension class FormTypeValidatorExtension extends AbstractTypeExtension
{ {
private $validator; private $validator;
@ -57,6 +57,6 @@ class FieldTypeValidatorExtension extends AbstractTypeExtension
public function getExtendedType() public function getExtendedType()
{ {
return 'field'; return 'form';
} }
} }

View File

@ -38,7 +38,7 @@ class ValidatorExtension extends AbstractExtension
protected function loadTypeExtensions() protected function loadTypeExtensions()
{ {
return array( return array(
new Type\FieldTypeValidatorExtension($this->validator), new Type\FormTypeValidatorExtension($this->validator),
); );
} }
} }

View File

@ -191,7 +191,7 @@ class Form implements \IteratorAggregate, FormInterface
array $types = array(), array $clientTransformers = array(), array $types = array(), array $clientTransformers = array(),
array $normTransformers = array(), array $normTransformers = array(),
DataMapperInterface $dataMapper = null, array $validators = array(), DataMapperInterface $dataMapper = null, array $validators = array(),
$required = false, $disabled = false, $errorBubbling = false, $required = false, $disabled = false, $errorBubbling = null,
$emptyData = null, array $attributes = array()) $emptyData = null, array $attributes = array())
{ {
$name = (string) $name; $name = (string) $name;
@ -225,7 +225,10 @@ class Form implements \IteratorAggregate, FormInterface
$this->validators = $validators; $this->validators = $validators;
$this->required = (Boolean) $required; $this->required = (Boolean) $required;
$this->disabled = (Boolean) $disabled; $this->disabled = (Boolean) $disabled;
$this->errorBubbling = (Boolean) $errorBubbling; // NULL is the default meaning:
// bubble up if the form has children (complex forms)
// don't bubble up if the form has no children (primitive fields)
$this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
$this->emptyData = $emptyData; $this->emptyData = $emptyData;
$this->attributes = $attributes; $this->attributes = $attributes;
@ -312,9 +315,9 @@ class Form implements \IteratorAggregate, FormInterface
} }
/** /**
* Returns the parent field. * Returns the parent form.
* *
* @return FormInterface The parent field * @return FormInterface The parent form
*/ */
public function getParent() public function getParent()
{ {
@ -342,7 +345,7 @@ class Form implements \IteratorAggregate, FormInterface
} }
/** /**
* Returns whether the field is the root of the form tree. * Returns whether the form is the root of the form tree.
* *
* @return Boolean * @return Boolean
*/ */
@ -374,7 +377,7 @@ class Form implements \IteratorAggregate, FormInterface
} }
/** /**
* Updates the field with default data. * Updates the form with default data.
* *
* @param array $appData The data formatted as expected for the underlying object * @param array $appData The data formatted as expected for the underlying object
* *
@ -408,7 +411,7 @@ class Form implements \IteratorAggregate, FormInterface
$this->clientData = $clientData; $this->clientData = $clientData;
$this->synchronized = true; $this->synchronized = true;
if ($this->dataMapper) { if (count($this->children) > 0 && $this->dataMapper) {
// Update child forms from the data // Update child forms from the data
$this->dataMapper->mapDataToForms($clientData, $this->children); $this->dataMapper->mapDataToForms($clientData, $this->children);
} }
@ -450,7 +453,7 @@ class Form implements \IteratorAggregate, FormInterface
} }
/** /**
* Binds data to the field, transforms and validates it. * Binds data to the form, transforms and validates it.
* *
* @param string|array $clientData The data * @param string|array $clientData The data
* *
@ -626,11 +629,11 @@ class Form implements \IteratorAggregate, FormInterface
} }
/** /**
* Returns the normalized data of the field. * Returns the normalized data of the form.
* *
* @return mixed When the field is not bound, the default data is returned. * @return mixed When the form is not bound, the default data is returned.
* When the field is bound, the normalized bound data is * When the form is bound, the normalized bound data is
* returned if the field is valid, null otherwise. * returned if the form is valid, null otherwise.
*/ */
public function getNormData() public function getNormData()
{ {
@ -646,7 +649,7 @@ class Form implements \IteratorAggregate, FormInterface
*/ */
public function addError(FormError $error) public function addError(FormError $error)
{ {
if ($this->parent && $this->errorBubbling) { if ($this->parent && $this->getErrorBubbling()) {
$this->parent->addError($error); $this->parent->addError($error);
} else { } else {
$this->errors[] = $error; $this->errors[] = $error;
@ -662,11 +665,11 @@ class Form implements \IteratorAggregate, FormInterface
*/ */
public function getErrorBubbling() public function getErrorBubbling()
{ {
return $this->errorBubbling; return null === $this->errorBubbling ? $this->hasChildren() : $this->errorBubbling;
} }
/** /**
* Returns whether the field is bound. * Returns whether the form is bound.
* *
* @return Boolean true if the form is bound to input values, false otherwise * @return Boolean true if the form is bound to input values, false otherwise
*/ */
@ -702,7 +705,7 @@ class Form implements \IteratorAggregate, FormInterface
} }
/** /**
* Returns whether the field is valid. * Returns whether the form is valid.
* *
* @return Boolean * @return Boolean
*/ */
@ -735,9 +738,8 @@ class Form implements \IteratorAggregate, FormInterface
public function hasErrors() public function hasErrors()
{ {
// Don't call isValid() here, as its semantics are slightly different // Don't call isValid() here, as its semantics are slightly different
// Field groups are not valid if their children are invalid, but // Forms are not valid if their children are invalid, but
// hasErrors() returns only true if a field/field group itself has // hasErrors() returns only true if a form itself has errors
// errors
return count($this->errors) > 0; return count($this->errors) > 0;
} }
@ -894,7 +896,7 @@ class Form implements \IteratorAggregate, FormInterface
return $this->children[$name]; return $this->children[$name];
} }
throw new \InvalidArgumentException(sprintf('Field "%s" does not exist.', $name)); throw new \InvalidArgumentException(sprintf('Child "%s" does not exist.', $name));
} }
/** /**

View File

@ -106,7 +106,7 @@ class FormBuilder
* Whether added errors should bubble up to the parent * Whether added errors should bubble up to the parent
* @var Boolean * @var Boolean
*/ */
private $errorBubbling = false; private $errorBubbling;
/** /**
* Data used for the client data when no value is bound * Data used for the client data when no value is bound
@ -243,7 +243,7 @@ class FormBuilder
*/ */
public function setErrorBubbling($errorBubbling) public function setErrorBubbling($errorBubbling)
{ {
$this->errorBubbling = (Boolean) $errorBubbling; $this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
return $this; return $this;
} }

View File

@ -183,7 +183,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
* The content of a disabled form is displayed, but not allowed to be * The content of a disabled form is displayed, but not allowed to be
* modified. The validation of modified disabled forms should fail. * modified. The validation of modified disabled forms should fail.
* *
* Fields whose parents are disabled are considered disabled regardless of * Forms whose parents are disabled are considered disabled regardless of
* their own state. * their own state.
* *
* @return Boolean * @return Boolean

View File

@ -75,7 +75,7 @@ class FormTypeGuesserChain implements FormTypeGuesserInterface
* @param \Closure $closure The closure to execute. Accepts a guesser * @param \Closure $closure The closure to execute. Accepts a guesser
* as argument and should return a Guess instance * as argument and should return a Guess instance
* *
* @return FieldFactoryGuess The guess with the highest confidence * @return Guess The guess with the highest confidence
*/ */
private function guess(\Closure $closure) private function guess(\Closure $closure)
{ {

View File

@ -202,7 +202,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
); );
} }
public function testRestAndRepeatedWithRowPerField() public function testRestAndRepeatedWithRowPerChild()
{ {
$view = $this->factory->createNamedBuilder('form', 'name') $view = $this->factory->createNamedBuilder('form', 'name')
->add('first', 'text') ->add('first', 'text')
@ -230,7 +230,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
); );
} }
public function testRestAndRepeatedWithWidgetPerField() public function testRestAndRepeatedWithWidgetPerChild()
{ {
$view = $this->factory->createNamedBuilder('form', 'name') $view = $this->factory->createNamedBuilder('form', 'name')
->add('first', 'text') ->add('first', 'text')
@ -348,7 +348,10 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testNestedFormError() public function testNestedFormError()
{ {
$form = $this->factory->createNamedBuilder('form', 'name') $form = $this->factory->createNamedBuilder('form', 'name')
->add('child', 'form', array('error_bubbling' => false)) ->add($this->factory
->createNamedBuilder('form', 'child', null, array('error_bubbling' => false))
->add('grandChild', 'form')
)
->getForm(); ->getForm();
$form->get('child')->addError(new FormError('Error!')); $form->get('child')->addError(new FormError('Error!'));

View File

@ -210,7 +210,10 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testNestedFormError() public function testNestedFormError()
{ {
$form = $this->factory->createNamedBuilder('form', 'name') $form = $this->factory->createNamedBuilder('form', 'name')
->add('child', 'form', array('error_bubbling' => false)) ->add($this->factory
->createNamedBuilder('form', 'child', null, array('error_bubbling' => false))
->add('grandChild', 'form')
)
->getForm(); ->getForm();
$form->get('child')->addError(new FormError('Error!')); $form->get('child')->addError(new FormError('Error!'));

View File

@ -98,7 +98,7 @@ class ChoiceTypeTest extends TypeTestCase
)); ));
} }
public function testExpandedChoicesOptionsTurnIntoFields() public function testExpandedChoicesOptionsTurnIntoChildren()
{ {
$form = $this->factory->create('choice', null, array( $form = $this->factory->create('choice', null, array(
'expanded' => true, 'expanded' => true,
@ -141,7 +141,7 @@ class ChoiceTypeTest extends TypeTestCase
} }
} }
public function testExpandedRadiosAreRequiredIfChoiceFieldIsRequired() public function testExpandedRadiosAreRequiredIfChoiceChildIsRequired()
{ {
$form = $this->factory->create('choice', null, array( $form = $this->factory->create('choice', null, array(
'multiple' => false, 'multiple' => false,
@ -155,7 +155,7 @@ class ChoiceTypeTest extends TypeTestCase
} }
} }
public function testExpandedRadiosAreNotRequiredIfChoiceFieldIsNotRequired() public function testExpandedRadiosAreNotRequiredIfChoiceChildIsNotRequired()
{ {
$form = $this->factory->create('choice', null, array( $form = $this->factory->create('choice', null, array(
'multiple' => false, 'multiple' => false,
@ -288,7 +288,7 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertNull($form[4]->getClientData()); $this->assertNull($form[4]->getClientData());
} }
public function testBindSingleExpandedWithFalseDoesNotHaveExtraFields() public function testBindSingleExpandedWithFalseDoesNotHaveExtraChildren()
{ {
$form = $this->factory->create('choice', null, array( $form = $this->factory->create('choice', null, array(
'multiple' => false, 'multiple' => false,
@ -302,7 +302,7 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertNull($form->getData()); $this->assertNull($form->getData());
} }
public function testBindSingleExpandedWithEmptyField() public function testBindSingleExpandedWithEmptyChild()
{ {
$form = $this->factory->create('choice', null, array( $form = $this->factory->create('choice', null, array(
'multiple' => false, 'multiple' => false,
@ -422,7 +422,7 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertNull($form[4]->getClientData()); $this->assertNull($form[4]->getClientData());
} }
public function testBindMultipleExpandedWithEmptyField() public function testBindMultipleExpandedWithEmptyChild()
{ {
$form = $this->factory->create('choice', null, array( $form = $this->factory->create('choice', null, array(
'multiple' => true, 'multiple' => true,

View File

@ -15,10 +15,10 @@ use Symfony\Component\Form\Form;
class CollectionTypeTest extends TypeTestCase class CollectionTypeTest extends TypeTestCase
{ {
public function testContainsNoFieldByDefault() public function testContainsNoChildByDefault()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
)); ));
$this->assertCount(0, $form); $this->assertCount(0, $form);
@ -27,7 +27,7 @@ class CollectionTypeTest extends TypeTestCase
public function testSetDataAdjustsSize() public function testSetDataAdjustsSize()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
'options' => array( 'options' => array(
'max_length' => 20, 'max_length' => 20,
), ),
@ -53,7 +53,7 @@ class CollectionTypeTest extends TypeTestCase
public function testThrowsExceptionIfObjectIsNotTraversable() public function testThrowsExceptionIfObjectIsNotTraversable()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
)); ));
$this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException'); $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
$form->setData(new \stdClass()); $form->setData(new \stdClass());
@ -62,7 +62,7 @@ class CollectionTypeTest extends TypeTestCase
public function testNotResizedIfBoundWithMissingData() public function testNotResizedIfBoundWithMissingData()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
)); ));
$form->setData(array('foo@foo.com', 'bar@bar.com')); $form->setData(array('foo@foo.com', 'bar@bar.com'));
$form->bind(array('foo@bar.com')); $form->bind(array('foo@bar.com'));
@ -76,7 +76,7 @@ class CollectionTypeTest extends TypeTestCase
public function testResizedDownIfBoundWithMissingDataAndAllowDelete() public function testResizedDownIfBoundWithMissingDataAndAllowDelete()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
'allow_delete' => true, 'allow_delete' => true,
)); ));
$form->setData(array('foo@foo.com', 'bar@bar.com')); $form->setData(array('foo@foo.com', 'bar@bar.com'));
@ -91,7 +91,7 @@ class CollectionTypeTest extends TypeTestCase
public function testNotResizedIfBoundWithExtraData() public function testNotResizedIfBoundWithExtraData()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
)); ));
$form->setData(array('foo@bar.com')); $form->setData(array('foo@bar.com'));
$form->bind(array('foo@foo.com', 'bar@bar.com')); $form->bind(array('foo@foo.com', 'bar@bar.com'));
@ -104,7 +104,7 @@ class CollectionTypeTest extends TypeTestCase
public function testResizedUpIfBoundWithExtraDataAndAllowAdd() public function testResizedUpIfBoundWithExtraDataAndAllowAdd()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
'allow_add' => true, 'allow_add' => true,
)); ));
$form->setData(array('foo@bar.com')); $form->setData(array('foo@bar.com'));
@ -120,7 +120,7 @@ class CollectionTypeTest extends TypeTestCase
public function testAllowAddButNoPrototype() public function testAllowAddButNoPrototype()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
'allow_add' => true, 'allow_add' => true,
'prototype' => false, 'prototype' => false,
)); ));
@ -169,7 +169,7 @@ class CollectionTypeTest extends TypeTestCase
public function testPrototypeNameOption() public function testPrototypeNameOption()
{ {
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
'prototype' => true, 'prototype' => true,
'allow_add' => true, 'allow_add' => true,
)); ));
@ -177,7 +177,7 @@ class CollectionTypeTest extends TypeTestCase
$this->assertSame('__name__', $form->getAttribute('prototype')->getName(), '__name__ is the default'); $this->assertSame('__name__', $form->getAttribute('prototype')->getName(), '__name__ is the default');
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'field', 'type' => 'form',
'prototype' => true, 'prototype' => true,
'allow_add' => true, 'allow_add' => true,
'prototype_name' => '__test__', 'prototype_name' => '__test__',

View File

@ -1,380 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\Tests\Fixtures\Author;
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
class FieldTypeTest extends TypeTestCase
{
public function testGetPropertyPathDefaultPath()
{
$form = $this->factory->createNamed('field', 'title');
$this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsZero()
{
$form = $this->factory->create('field', null, array('property_path' => '0'));
$this->assertEquals(new PropertyPath('0'), $form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsEmpty()
{
$form = $this->factory->create('field', null, array('property_path' => ''));
$this->assertNull($form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsFalse()
{
$form = $this->factory->create('field', null, array('property_path' => false));
$this->assertNull($form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsNull()
{
$form = $this->factory->createNamed('field', 'title', null, array('property_path' => null));
$this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
}
public function testPassRequiredAsOption()
{
$form = $this->factory->create('field', null, array('required' => false));
$this->assertFalse($form->isRequired());
$form = $this->factory->create('field', null, array('required' => true));
$this->assertTrue($form->isRequired());
}
public function testPassDisabledAsOption()
{
$form = $this->factory->create('field', null, array('disabled' => true));
$this->assertTrue($form->isDisabled());
}
public function testBoundDataIsTrimmedBeforeTransforming()
{
$form = $this->factory->createBuilder('field')
->appendClientTransformer(new FixedDataTransformer(array(
null => '',
'reverse[a]' => 'a',
)))
->getForm();
$form->bind(' a ');
$this->assertEquals('a', $form->getClientData());
$this->assertEquals('reverse[a]', $form->getData());
}
public function testBoundDataIsNotTrimmedBeforeTransformingIfNoTrimming()
{
$form = $this->factory->createBuilder('field', null, array('trim' => false))
->appendClientTransformer(new FixedDataTransformer(array(
null => '',
'reverse[ a ]' => ' a ',
)))
->getForm();
$form->bind(' a ');
$this->assertEquals(' a ', $form->getClientData());
$this->assertEquals('reverse[ a ]', $form->getData());
}
public function testPassIdAndNameToView()
{
$form = $this->factory->createNamed('field', 'name');
$view = $form->createView();
$this->assertEquals('name', $view->get('id'));
$this->assertEquals('name', $view->get('name'));
$this->assertEquals('name', $view->get('full_name'));
}
public function testStripLeadingUnderscoresAndDigitsFromId()
{
$form = $this->factory->createNamed('field', '_09name');
$view = $form->createView();
$this->assertEquals('name', $view->get('id'));
$this->assertEquals('_09name', $view->get('name'));
$this->assertEquals('_09name', $view->get('full_name'));
}
public function testPassIdAndNameToViewWithParent()
{
$parent = $this->factory->createNamed('field', 'parent');
$parent->add($this->factory->createNamed('field', 'child'));
$view = $parent->createView();
$this->assertEquals('parent_child', $view['child']->get('id'));
$this->assertEquals('child', $view['child']->get('name'));
$this->assertEquals('parent[child]', $view['child']->get('full_name'));
}
public function testPassIdAndNameToViewWithGrandParent()
{
$parent = $this->factory->createNamed('field', 'parent');
$parent->add($this->factory->createNamed('field', 'child'));
$parent['child']->add($this->factory->createNamed('field', 'grand_child'));
$view = $parent->createView();
$this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->get('id'));
$this->assertEquals('grand_child', $view['child']['grand_child']->get('name'));
$this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->get('full_name'));
}
public function testNonReadOnlyFieldWithReadOnlyParentBeingReadOnly()
{
$parent = $this->factory->createNamed('field', 'parent', null, array('read_only' => true));
$child = $this->factory->createNamed('field', 'child');
$view = $parent->add($child)->createView();
$this->assertTrue($view['child']->get('read_only'));
}
public function testReadOnlyFieldWithNonReadOnlyParentBeingReadOnly()
{
$parent = $this->factory->createNamed('field', 'parent');
$child = $this->factory->createNamed('field', 'child', null, array('read_only' => true));
$view = $parent->add($child)->createView();
$this->assertTrue($view['child']->get('read_only'));
}
public function testNonReadOnlyFieldWithNonReadOnlyParentBeingNonReadOnly()
{
$parent = $this->factory->createNamed('field', 'parent');
$child = $this->factory->createNamed('field', 'child');
$view = $parent->add($child)->createView();
$this->assertFalse($view['child']->get('read_only'));
}
public function testPassMaxLengthToView()
{
$form = $this->factory->create('field', null, array('max_length' => 10));
$view = $form->createView();
$this->assertSame(10, $view->get('max_length'));
}
public function testPassTranslationDomainToView()
{
$form = $this->factory->create('field', null, array('translation_domain' => 'test'));
$view = $form->createView();
$this->assertSame('test', $view->get('translation_domain'));
}
public function testPassDefaultLabelToView()
{
$form = $this->factory->createNamed('field', '__test___field');
$view = $form->createView();
$this->assertSame('Test field', $view->get('label'));
}
public function testPassLabelToView()
{
$form = $this->factory->createNamed('field', '__test___field', null, array('label' => 'My label'));
$view = $form->createView();
$this->assertSame('My label', $view->get('label'));
}
public function testDefaultTranslationDomain()
{
$form = $this->factory->create('field');
$view = $form->createView();
$this->assertSame('messages', $view->get('translation_domain'));
}
public function testBindWithEmptyDataCreatesObjectIfClassAvailable()
{
$form = $this->factory->create('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => false,
));
$form->add($this->factory->createNamed('field', 'firstName'));
$form->add($this->factory->createNamed('field', 'lastName'));
$form->setData(null);
// partially empty, still an object is created
$form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
$author = new Author();
$author->firstName = 'Bernhard';
$author->setLastName('');
$this->assertEquals($author, $form->getData());
}
public function testBindWithEmptyDataCreatesObjectIfInitiallyBoundWithObject()
{
$form = $this->factory->create('form', null, array(
// data class is inferred from the passed object
'data' => new Author(),
'required' => false,
));
$form->add($this->factory->createNamed('field', 'firstName'));
$form->add($this->factory->createNamed('field', 'lastName'));
$form->setData(null);
// partially empty, still an object is created
$form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
$author = new Author();
$author->firstName = 'Bernhard';
$author->setLastName('');
$this->assertEquals($author, $form->getData());
}
public function testBindWithEmptyDataDoesNotCreateObjectIfDataClassIsNull()
{
$form = $this->factory->create('form', null, array(
'data' => new Author(),
'data_class' => null,
'required' => false,
));
$form->add($this->factory->createNamed('field', 'firstName'));
$form->setData(null);
$form->bind(array('firstName' => 'Bernhard'));
$this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
}
public function testBindEmptyWithEmptyDataCreatesNoObjectIfNotRequired()
{
$form = $this->factory->create('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => false,
));
$form->add($this->factory->createNamed('field', 'firstName'));
$form->add($this->factory->createNamed('field', 'lastName'));
$form->setData(null);
$form->bind(array('firstName' => '', 'lastName' => ''));
$this->assertNull($form->getData());
}
public function testBindEmptyWithEmptyDataCreatesObjectIfRequired()
{
$form = $this->factory->create('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => true,
));
$form->add($this->factory->createNamed('field', 'firstName'));
$form->add($this->factory->createNamed('field', 'lastName'));
$form->setData(null);
$form->bind(array('firstName' => '', 'lastName' => ''));
$this->assertEquals(new Author(), $form->getData());
}
/*
* We need something to write the field values into
*/
public function testBindWithEmptyDataStoresArrayIfNoClassAvailable()
{
$form = $this->factory->create('form');
$form->add($this->factory->createNamed('field', 'firstName'));
$form->setData(null);
$form->bind(array('firstName' => 'Bernhard'));
$this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
}
public function testBindWithEmptyDataUsesEmptyDataOption()
{
$author = new Author();
$form = $this->factory->create('form', null, array(
'empty_data' => $author,
));
$form->add($this->factory->createNamed('field', 'firstName'));
$form->bind(array('firstName' => 'Bernhard'));
$this->assertSame($author, $form->getData());
$this->assertEquals('Bernhard', $author->firstName);
}
public function testGetAttributesIsEmpty()
{
$form = $this->factory->create('field', null, array('attr' => array()));
$this->assertCount(0, $form->getAttribute('attr'));
}
/**
* @see https://github.com/symfony/symfony/issues/1986
*/
public function testSetDataThroughParamsWithZero()
{
$form = $this->factory->create('field', null, array('data' => 0));
$view = $form->createView();
$this->assertFalse($form->isEmpty());
$this->assertSame('0', $view->get('value'));
$this->assertSame('0', $form->getData());
$form = $this->factory->create('field', null, array('data' => '0'));
$view = $form->createView();
$this->assertFalse($form->isEmpty());
$this->assertSame('0', $view->get('value'));
$this->assertSame('0', $form->getData());
$form = $this->factory->create('field', null, array('data' => '00000'));
$view = $form->createView();
$this->assertFalse($form->isEmpty());
$this->assertSame('00000', $view->get('value'));
$this->assertSame('00000', $form->getData());
}
/**
* @expectedException Symfony\Component\Form\Exception\FormException
*/
public function testAttributesException()
{
$form = $this->factory->create('field', null, array('attr' => ''));
}
public function testNameCanBeEmptyString()
{
$form = $this->factory->createNamed('field', '');
$this->assertEquals('', $form->getName());
}
}

View File

@ -11,9 +11,11 @@
namespace Symfony\Component\Form\Tests\Extension\Core\Type; namespace Symfony\Component\Form\Tests\Extension\Core\Type;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\Form; use Symfony\Component\Form\Form;
use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Tests\Fixtures\Author; use Symfony\Component\Form\Tests\Fixtures\Author;
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
class FormTest_AuthorWithoutRefSetter class FormTest_AuthorWithoutRefSetter
{ {
@ -49,13 +51,372 @@ class FormTest_AuthorWithoutRefSetter
class FormTypeTest extends TypeTestCase class FormTypeTest extends TypeTestCase
{ {
public function testGetPropertyPathDefaultPath()
{
$form = $this->factory->createNamed('form', 'title');
$this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsZero()
{
$form = $this->factory->create('form', null, array('property_path' => '0'));
$this->assertEquals(new PropertyPath('0'), $form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsEmpty()
{
$form = $this->factory->create('form', null, array('property_path' => ''));
$this->assertNull($form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsFalse()
{
$form = $this->factory->create('form', null, array('property_path' => false));
$this->assertNull($form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsNull()
{
$form = $this->factory->createNamed('form', 'title', null, array('property_path' => null));
$this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
}
public function testPassRequiredAsOption()
{
$form = $this->factory->create('form', null, array('required' => false));
$this->assertFalse($form->isRequired());
$form = $this->factory->create('form', null, array('required' => true));
$this->assertTrue($form->isRequired());
}
public function testPassDisabledAsOption()
{
$form = $this->factory->create('form', null, array('disabled' => true));
$this->assertTrue($form->isDisabled());
}
public function testBoundDataIsTrimmedBeforeTransforming()
{
$form = $this->factory->createBuilder('form')
->appendClientTransformer(new FixedDataTransformer(array(
null => '',
'reverse[a]' => 'a',
)))
->getForm();
$form->bind(' a ');
$this->assertEquals('a', $form->getClientData());
$this->assertEquals('reverse[a]', $form->getData());
}
public function testBoundDataIsNotTrimmedBeforeTransformingIfNoTrimming()
{
$form = $this->factory->createBuilder('form', null, array('trim' => false))
->appendClientTransformer(new FixedDataTransformer(array(
null => '',
'reverse[ a ]' => ' a ',
)))
->getForm();
$form->bind(' a ');
$this->assertEquals(' a ', $form->getClientData());
$this->assertEquals('reverse[ a ]', $form->getData());
}
public function testPassIdAndNameToView()
{
$form = $this->factory->createNamed('form', 'name');
$view = $form->createView();
$this->assertEquals('name', $view->get('id'));
$this->assertEquals('name', $view->get('name'));
$this->assertEquals('name', $view->get('full_name'));
}
public function testStripLeadingUnderscoresAndDigitsFromId()
{
$form = $this->factory->createNamed('form', '_09name');
$view = $form->createView();
$this->assertEquals('name', $view->get('id'));
$this->assertEquals('_09name', $view->get('name'));
$this->assertEquals('_09name', $view->get('full_name'));
}
public function testPassIdAndNameToViewWithParent()
{
$parent = $this->factory->createNamed('form', 'parent');
$parent->add($this->factory->createNamed('form', 'child'));
$view = $parent->createView();
$this->assertEquals('parent_child', $view['child']->get('id'));
$this->assertEquals('child', $view['child']->get('name'));
$this->assertEquals('parent[child]', $view['child']->get('full_name'));
}
public function testPassIdAndNameToViewWithGrandParent()
{
$parent = $this->factory->createNamed('form', 'parent');
$parent->add($this->factory->createNamed('form', 'child'));
$parent['child']->add($this->factory->createNamed('form', 'grand_child'));
$view = $parent->createView();
$this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->get('id'));
$this->assertEquals('grand_child', $view['child']['grand_child']->get('name'));
$this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->get('full_name'));
}
public function testNonReadOnlyFormWithReadOnlyParentBeingReadOnly()
{
$parent = $this->factory->createNamed('form', 'parent', null, array('read_only' => true));
$child = $this->factory->createNamed('form', 'child');
$view = $parent->add($child)->createView();
$this->assertTrue($view['child']->get('read_only'));
}
public function testReadOnlyFormWithNonReadOnlyParentBeingReadOnly()
{
$parent = $this->factory->createNamed('form', 'parent');
$child = $this->factory->createNamed('form', 'child', null, array('read_only' => true));
$view = $parent->add($child)->createView();
$this->assertTrue($view['child']->get('read_only'));
}
public function testNonReadOnlyFormWithNonReadOnlyParentBeingNonReadOnly()
{
$parent = $this->factory->createNamed('form', 'parent');
$child = $this->factory->createNamed('form', 'child');
$view = $parent->add($child)->createView();
$this->assertFalse($view['child']->get('read_only'));
}
public function testPassMaxLengthToView()
{
$form = $this->factory->create('form', null, array('max_length' => 10));
$view = $form->createView();
$this->assertSame(10, $view->get('max_length'));
}
public function testPassTranslationDomainToView()
{
$form = $this->factory->create('form', null, array('translation_domain' => 'test'));
$view = $form->createView();
$this->assertSame('test', $view->get('translation_domain'));
}
public function testPassDefaultLabelToView()
{
$form = $this->factory->createNamed('form', '__test___field');
$view = $form->createView();
$this->assertSame('Test field', $view->get('label'));
}
public function testPassLabelToView()
{
$form = $this->factory->createNamed('form', '__test___field', null, array('label' => 'My label'));
$view = $form->createView();
$this->assertSame('My label', $view->get('label'));
}
public function testDefaultTranslationDomain()
{
$form = $this->factory->create('form');
$view = $form->createView();
$this->assertSame('messages', $view->get('translation_domain'));
}
public function testBindWithEmptyDataCreatesObjectIfClassAvailable()
{
$form = $this->factory->create('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => false,
));
$form->add($this->factory->createNamed('form', 'firstName'));
$form->add($this->factory->createNamed('form', 'lastName'));
$form->setData(null);
// partially empty, still an object is created
$form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
$author = new Author();
$author->firstName = 'Bernhard';
$author->setLastName('');
$this->assertEquals($author, $form->getData());
}
public function testBindWithEmptyDataCreatesObjectIfInitiallyBoundWithObject()
{
$form = $this->factory->create('form', null, array(
// data class is inferred from the passed object
'data' => new Author(),
'required' => false,
));
$form->add($this->factory->createNamed('form', 'firstName'));
$form->add($this->factory->createNamed('form', 'lastName'));
$form->setData(null);
// partially empty, still an object is created
$form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
$author = new Author();
$author->firstName = 'Bernhard';
$author->setLastName('');
$this->assertEquals($author, $form->getData());
}
public function testBindWithEmptyDataDoesNotCreateObjectIfDataClassIsNull()
{
$form = $this->factory->create('form', null, array(
'data' => new Author(),
'data_class' => null,
'required' => false,
));
$form->add($this->factory->createNamed('form', 'firstName'));
$form->setData(null);
$form->bind(array('firstName' => 'Bernhard'));
$this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
}
public function testBindEmptyWithEmptyDataCreatesNoObjectIfNotRequired()
{
$form = $this->factory->create('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => false,
));
$form->add($this->factory->createNamed('form', 'firstName'));
$form->add($this->factory->createNamed('form', 'lastName'));
$form->setData(null);
$form->bind(array('firstName' => '', 'lastName' => ''));
$this->assertNull($form->getData());
}
public function testBindEmptyWithEmptyDataCreatesObjectIfRequired()
{
$form = $this->factory->create('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => true,
));
$form->add($this->factory->createNamed('form', 'firstName'));
$form->add($this->factory->createNamed('form', 'lastName'));
$form->setData(null);
$form->bind(array('firstName' => '', 'lastName' => ''));
$this->assertEquals(new Author(), $form->getData());
}
/*
* We need something to write the field values into
*/
public function testBindWithEmptyDataStoresArrayIfNoClassAvailable()
{
$form = $this->factory->create('form');
$form->add($this->factory->createNamed('form', 'firstName'));
$form->setData(null);
$form->bind(array('firstName' => 'Bernhard'));
$this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
}
public function testBindWithEmptyDataUsesEmptyDataOption()
{
$author = new Author();
$form = $this->factory->create('form', null, array(
'empty_data' => $author,
));
$form->add($this->factory->createNamed('form', 'firstName'));
$form->bind(array('firstName' => 'Bernhard'));
$this->assertSame($author, $form->getData());
$this->assertEquals('Bernhard', $author->firstName);
}
public function testGetAttributesIsEmpty()
{
$form = $this->factory->create('form', null, array('attr' => array()));
$this->assertCount(0, $form->getAttribute('attr'));
}
/**
* @see https://github.com/symfony/symfony/issues/1986
*/
public function testSetDataThroughParamsWithZero()
{
$form = $this->factory->create('form', null, array('data' => 0));
$view = $form->createView();
$this->assertFalse($form->isEmpty());
$this->assertSame('0', $view->get('value'));
$this->assertSame('0', $form->getData());
$form = $this->factory->create('form', null, array('data' => '0'));
$view = $form->createView();
$this->assertFalse($form->isEmpty());
$this->assertSame('0', $view->get('value'));
$this->assertSame('0', $form->getData());
$form = $this->factory->create('form', null, array('data' => '00000'));
$view = $form->createView();
$this->assertFalse($form->isEmpty());
$this->assertSame('00000', $view->get('value'));
$this->assertSame('00000', $form->getData());
}
/**
* @expectedException Symfony\Component\Form\Exception\FormException
*/
public function testAttributesException()
{
$form = $this->factory->create('form', null, array('attr' => ''));
}
public function testNameCanBeEmptyString()
{
$form = $this->factory->createNamed('form', '');
$this->assertEquals('', $form->getName());
}
public function testSubformDoesntCallSetters() public function testSubformDoesntCallSetters()
{ {
$author = new FormTest_AuthorWithoutRefSetter(new Author()); $author = new FormTest_AuthorWithoutRefSetter(new Author());
$builder = $this->factory->createBuilder('form'); $builder = $this->factory->createBuilder('form');
$builder->add('reference', 'form'); $builder->add('reference', 'form');
$builder->get('reference')->add('firstName', 'field'); $builder->get('reference')->add('firstName', 'form');
$builder->setData($author); $builder->setData($author);
$form = $builder->getForm(); $form = $builder->getForm();
@ -77,7 +438,7 @@ class FormTypeTest extends TypeTestCase
$builder = $this->factory->createBuilder('form'); $builder = $this->factory->createBuilder('form');
$builder->add('referenceCopy', 'form'); $builder->add('referenceCopy', 'form');
$builder->get('referenceCopy')->add('firstName', 'field'); $builder->get('referenceCopy')->add('firstName', 'form');
$builder->setData($author); $builder->setData($author);
$form = $builder->getForm(); $form = $builder->getForm();
@ -99,7 +460,7 @@ class FormTypeTest extends TypeTestCase
$builder = $this->factory->createBuilder('form'); $builder = $this->factory->createBuilder('form');
$builder->add('referenceCopy', 'form', array('by_reference' => false)); $builder->add('referenceCopy', 'form', array('by_reference' => false));
$builder->get('referenceCopy')->add('firstName', 'field'); $builder->get('referenceCopy')->add('firstName', 'form');
$builder->setData($author); $builder->setData($author);
$form = $builder->getForm(); $form = $builder->getForm();

View File

@ -21,7 +21,7 @@ class RepeatedTypeTest extends TypeTestCase
parent::setUp(); parent::setUp();
$this->form = $this->factory->create('repeated', null, array( $this->form = $this->factory->create('repeated', null, array(
'type' => 'field', 'type' => 'form',
)); ));
$this->form->setData(null); $this->form->setData(null);
} }
@ -37,7 +37,7 @@ class RepeatedTypeTest extends TypeTestCase
public function testSetOptions() public function testSetOptions()
{ {
$form = $this->factory->create('repeated', null, array( $form = $this->factory->create('repeated', null, array(
'type' => 'field', 'type' => 'form',
'options' => array('label' => 'Global'), 'options' => array('label' => 'Global'),
)); ));
@ -47,11 +47,11 @@ class RepeatedTypeTest extends TypeTestCase
$this->assertTrue($form['second']->isRequired()); $this->assertTrue($form['second']->isRequired());
} }
public function testSetOptionsPerField() public function testSetOptionsPerChild()
{ {
$form = $this->factory->create('repeated', null, array( $form = $this->factory->create('repeated', null, array(
// the global required value cannot be overriden // the global required value cannot be overriden
'type' => 'field', 'type' => 'form',
'first_options' => array('label' => 'Test', 'required' => false), 'first_options' => array('label' => 'Test', 'required' => false),
'second_options' => array('label' => 'Test2') 'second_options' => array('label' => 'Test2')
)); ));
@ -66,17 +66,17 @@ class RepeatedTypeTest extends TypeTestCase
{ {
$form = $this->factory->create('repeated', null, array( $form = $this->factory->create('repeated', null, array(
'required' => false, 'required' => false,
'type' => 'field', 'type' => 'form',
)); ));
$this->assertFalse($form['first']->isRequired()); $this->assertFalse($form['first']->isRequired());
$this->assertFalse($form['second']->isRequired()); $this->assertFalse($form['second']->isRequired());
} }
public function testSetOptionsPerFieldAndOverwrite() public function testSetOptionsPerChildAndOverwrite()
{ {
$form = $this->factory->create('repeated', null, array( $form = $this->factory->create('repeated', null, array(
'type' => 'field', 'type' => 'form',
'options' => array('label' => 'Label'), 'options' => array('label' => 'Label'),
'second_options' => array('label' => 'Second label') 'second_options' => array('label' => 'Second label')
)); ));

View File

@ -93,6 +93,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$builder = new FormBuilder($name, $this->factory, $this->dispatcher); $builder = new FormBuilder($name, $this->factory, $this->dispatcher);
$builder->setAttribute('property_path', new PropertyPath($propertyPath ?: $name)); $builder->setAttribute('property_path', new PropertyPath($propertyPath ?: $name));
$builder->setAttribute('error_mapping', array()); $builder->setAttribute('error_mapping', array());
$builder->setErrorBubbling(false);
return $builder; return $builder;
} }

View File

@ -13,18 +13,18 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
class FieldTypeValidatorExtensionTest extends TypeTestCase class FormTypeValidatorExtensionTest extends TypeTestCase
{ {
public function testValidationGroupNullByDefault() public function testValidationGroupNullByDefault()
{ {
$form = $this->factory->create('field'); $form = $this->factory->create('form');
$this->assertNull($form->getAttribute('validation_groups')); $this->assertNull($form->getAttribute('validation_groups'));
} }
public function testValidationGroupsCanBeSetToString() public function testValidationGroupsCanBeSetToString()
{ {
$form = $this->factory->create('field', null, array( $form = $this->factory->create('form', null, array(
'validation_groups' => 'group', 'validation_groups' => 'group',
)); ));
@ -33,7 +33,7 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testValidationGroupsCanBeSetToArray() public function testValidationGroupsCanBeSetToArray()
{ {
$form = $this->factory->create('field', null, array( $form = $this->factory->create('form', null, array(
'validation_groups' => array('group1', 'group2'), 'validation_groups' => array('group1', 'group2'),
)); ));
@ -42,7 +42,7 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testValidationGroupsCanBeSetToCallback() public function testValidationGroupsCanBeSetToCallback()
{ {
$form = $this->factory->create('field', null, array( $form = $this->factory->create('form', null, array(
'validation_groups' => array($this, 'testValidationGroupsCanBeSetToCallback'), 'validation_groups' => array($this, 'testValidationGroupsCanBeSetToCallback'),
)); ));
@ -51,7 +51,7 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testValidationGroupsCanBeSetToClosure() public function testValidationGroupsCanBeSetToClosure()
{ {
$form = $this->factory->create('field', null, array( $form = $this->factory->create('form', null, array(
'validation_groups' => function(FormInterface $form){ return null; }, 'validation_groups' => function(FormInterface $form){ return null; },
)); ));
@ -60,10 +60,10 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testBindValidatesData() public function testBindValidatesData()
{ {
$builder = $this->factory->createBuilder('field', null, array( $builder = $this->factory->createBuilder('form', null, array(
'validation_groups' => 'group', 'validation_groups' => 'group',
)); ));
$builder->add('firstName', 'field'); $builder->add('firstName', 'form');
$form = $builder->getForm(); $form = $builder->getForm();
$this->validator->expects($this->once()) $this->validator->expects($this->once())

View File

@ -71,7 +71,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
* Changing the name is not allowed, otherwise the name and property path * Changing the name is not allowed, otherwise the name and property path
* are not synchronized anymore * are not synchronized anymore
* *
* @see FieldType::buildForm * @see FormType::buildForm
*/ */
public function testNoSetName() public function testNoSetName()
{ {

View File

@ -346,7 +346,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo', $builder->getName()); $this->assertEquals('foo', $builder->getName());
} }
public function testCreateBuilderForPropertyCreatesFieldWithHighestConfidence() public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence()
{ {
$this->guesser1->expects($this->once()) $this->guesser1->expects($this->once())
->method('guessType') ->method('guessType')
@ -378,7 +378,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('builderInstance', $builder); $this->assertEquals('builderInstance', $builder);
} }
public function testCreateBuilderCreatesTextFieldIfNoGuess() public function testCreateBuilderCreatesTextFormIfNoGuess()
{ {
$this->guesser1->expects($this->once()) $this->guesser1->expects($this->once())
->method('guessType') ->method('guessType')
@ -541,7 +541,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$factory->createNamedBuilder($type, "text", "value", array("unknown" => "opt")); $factory->createNamedBuilder($type, "text", "value", array("unknown" => "opt"));
} }
public function testFieldTypeCreatesDefaultValueForEmptyDataOption() public function testFormTypeCreatesDefaultValueForEmptyDataOption()
{ {
$factory = new FormFactory(array(new \Symfony\Component\Form\Extension\Core\CoreExtension())); $factory = new FormFactory(array(new \Symfony\Component\Form\Extension\Core\CoreExtension()));

View File

@ -159,6 +159,35 @@ class FormTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(), $parent->getErrors()); $this->assertEquals(array(), $parent->getErrors());
} }
public function testErrorsBubbleUpIfNullAndChildren()
{
$error = new FormError('Error!');
$parent = $this->form;
$form = $this->getBuilder()
->setErrorBubbling(null)
->add($this->getBuilder('child'))
->getForm();
$form->setParent($parent);
$form->addError($error);
$this->assertEquals(array(), $form->getErrors());
$this->assertEquals(array($error), $parent->getErrors());
}
public function testErrorsDontBubbleUpIfNullAndNoChildren()
{
$error = new FormError('Error!');
$parent = $this->form;
$form = $this->getBuilder()->setErrorBubbling(null)->getForm();
$form->setParent($parent);
$form->addError($error);
$this->assertEquals(array($error), $form->getErrors());
$this->assertEquals(array(), $parent->getErrors());
}
public function testValidIfAllChildrenAreValid() public function testValidIfAllChildrenAreValid()
{ {
$this->form->add($this->getValidForm('firstName')); $this->form->add($this->getValidForm('firstName'));
@ -1026,7 +1055,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
/** /**
* @dataProvider requestMethodProvider * @dataProvider requestMethodProvider
*/ */
public function testBindPostOrPutRequestWithSingleFieldForm($method) public function testBindPostOrPutRequestWithSingleChildForm($method)
{ {
if (!class_exists('Symfony\Component\HttpFoundation\Request')) { if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
$this->markTestSkipped('The "HttpFoundation" component is not available'); $this->markTestSkipped('The "HttpFoundation" component is not available');
@ -1063,7 +1092,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
/** /**
* @dataProvider requestMethodProvider * @dataProvider requestMethodProvider
*/ */
public function testBindPostOrPutRequestWithSingleFieldFormUploadedFile($method) public function testBindPostOrPutRequestWithSingleChildFormUploadedFile($method)
{ {
if (!class_exists('Symfony\Component\HttpFoundation\Request')) { if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
$this->markTestSkipped('The "HttpFoundation" component is not available'); $this->markTestSkipped('The "HttpFoundation" component is not available');