merged branch bschussek/issue3879 (PR #4387)

Commits
-------

bc15e2d [Form] Some code cleanup
94f6f77 Restructured Form section of UPGRADE
3d800af [Form] Remove usages of deprecated features
ee803cd [Form] Renamed setVars() to addVars() in FormViewInterface
1c4f632 [Form] Fixed API docs and usage of FormBuilderInterface instead of FormBuilder
2e6cdd1 [Form] Inverted the logic of "single_control" and renamed it to "compound". The opposite is now "simple".
98a7c0c [Form] Consolidated FormInterface, FormBuilderInterface and FormViewInterface
8e128fc [Form][OptionsResolver] Fixed typos
877d8f7 [Form] Reversed the order of $type and $name in FormFactory::createNamed[Builder]()
33fecca [Form] Merged various form events and added class FormEvent
bec8015 [Form] Renamed client and application format to view and model format
8cae328 [Form] setDefaultOptions() is now coded against OptionsResolverInterface
1ecddbc [OptionsResolver] Renamed recommended method to setDefaultOptions()
dc2fa9d [OptionsResolver] Added OptionsResolverInterface
2cd99e8 [Form] Added FormBuilderInterface and FormViewInterface and cleaned up FormTypeInterface and FormTypeExtensionInterface
0ef4066 [Form] Options are now passed to buildView() and buildViewBottomUp()
027259e [Form] Changed getDefaultOptions() to setDefaultOptions(OptionsResolver $resolver) in FormTypeInterface
b4e8bcf [OptionsResolver] Relaxed tests to check that allowed values can also be passed as scalars
97de004 [OptionsResolver] Added option type validation capabilities
0af5f06 [OptionsResolver] Added method setFilters() for augmenting the final option values

Discussion
----------

[Form] Cleaned up the Form API

Bug fix: no
Feature addition: no
Backwards compatibility break: **YES**
Symfony2 tests pass: yes
Fixes the following tickets: #3855, #3879, #4342, #4371, #4375
Todo: -

This PR cleans up the Form API as described in the referenced tickets in order to stabilize and freeze this API in the future. BC is kept wherever possible. After this PR, form types are expected to follow the following interface:

```php
<?php

class MyType extends AbstractType
{
	public function buildForm(FormBuilderInterface $builder, array $options)
	{
	}

	public function buildView(FormViewInterface $view, FormInterface $form, array $options)
	{
	}

	public function finishView(FormViewInterface $view, FormInterface $form, array $options)
	{
	}

	public function setDefaultOptions(OptionsResolverInterface $resolver)
	{
	}

	public function getParent()
	{
	    return 'form';
	}

	public function getName()
	{
	    return 'my_type';
	}
}
```

Note that the options are now passed to `buildView` and `finishView` (formerly `buildViewBottomUp`) as well, reducing the need for creating form attributes in most cases.

---------------------------------------------------------------------------

by travisbot at 2012-05-23T19:07:44Z

This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1414486) (merged 277f5f78 into e0238071).

---------------------------------------------------------------------------

by bschussek at 2012-05-23T19:51:40Z

The PR now also contains the fix for #4342.

---------------------------------------------------------------------------

by travisbot at 2012-05-23T19:51:55Z

This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1414932) (merged 13d284ba into e0238071).

---------------------------------------------------------------------------

by travisbot at 2012-05-24T06:55:35Z

This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1419776) (merged 5aba0778 into e0238071).

---------------------------------------------------------------------------

by travisbot at 2012-05-24T06:56:28Z

This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1419783) (merged 00c4f7ee into b07fb3c4).

---------------------------------------------------------------------------

by travisbot at 2012-05-24T12:26:25Z

This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1421748) (merged 73cd9f8e into b07fb3c4).

---------------------------------------------------------------------------

by bschussek at 2012-05-24T12:27:32Z

The FormView changes described in #4371 are now contained as well. Invitation for final review.

---------------------------------------------------------------------------

by travisbot at 2012-05-24T14:03:10Z

This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1422116) (merged e1f502b9 into b07fb3c4).

---------------------------------------------------------------------------

by cordoval at 2012-05-25T03:26:05Z

any ETA @bschussek ? I want to use it for tackling the problem of dynamic selects city-state
here http://www.craftitonline.com/2011/08/symfony2-ajax-form-republish/

I am told:
"getDefaultOptions is changed to setDefaultOptions which will allow you to set depenedent values based on other forms"

so I am most interested +300!

---------------------------------------------------------------------------

by bschussek at 2012-05-25T06:08:53Z

@cordoval I think you misunderstood this. The OptionsResolver allows you to set options dependent on other options, but of the same field. Also, this is already possible before this merge by setting an option to a closure as described in the README of the OptionsResolver component.

---------------------------------------------------------------------------

by travisbot at 2012-05-25T06:35:53Z

This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1430534) (merged b61cc555 into b07fb3c4).

---------------------------------------------------------------------------

by vicb at 2012-05-25T06:42:24Z

@bschussek great changes ! I have just sent you a PR with some modifs related to deprecated features. I'll rebase and submit the other one we have already discussed.

---------------------------------------------------------------------------

by travisbot at 2012-05-25T07:16:18Z

This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1430699) (merged e18830da into b07fb3c4).

---------------------------------------------------------------------------

by cordoval at 2012-05-25T07:19:07Z

@bschussek what is already possilble @ "Also, this is already possible before"

I am confused could you link to what you are referring to please?

---------------------------------------------------------------------------

by travisbot at 2012-05-25T07:22:07Z

This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1430727) (merged 20c02a72 into b07fb3c4).

---------------------------------------------------------------------------

by bschussek at 2012-05-25T07:22:29Z

```
public function getDefaultOptions()
{
    return array(
        'a' => 'foo',
        'b' => function (Options $options) {
            return 'bar' === $options['a'] ? 'x' : 'y';
        }
    );
}

---------------------------------------------------------------------------

by travisbot at 2012-05-25T10:38:04Z

This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1431903) (merged bc15e2d6 into 45849ce3).
This commit is contained in:
Fabien Potencier 2012-05-25 12:39:27 +02:00
commit 023dbf809a
143 changed files with 3615 additions and 2588 deletions

View File

@ -145,19 +145,330 @@
### Form
#### BC Breaks in Form Types and Options
* A third argument `$options` was added to the methods `buildView()` and
`buildViewBottomUp()` in `FormTypeInterface` and `FormTypeExtensionInterface`.
Furthermore, `buildViewBottomUp()` was renamed to `finishView()`. At last,
all methods in these types now receive instances of `FormBuilderInterface`
and `FormViewInterface` where they received instances of `FormBuilder` and
`FormView` before. You need to change the method signatures in your
form types and extensions as shown below.
Before:
```
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
public function buildForm(FormBuilder $builder, array $options)
public function buildView(FormView $view, FormInterface $form)
public function buildViewBottomUp(FormView $view, FormInterface $form)
```
After:
```
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormViewInterface;
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
```
* No options are passed to `getParent()` of `FormTypeInterface` anymore. If
you previously dynamically inherited from `FormType` or `FieldType`, you can now
dynamically set the "compound" option instead.
Before:
```
public function getParent(array $options)
{
return $options['expanded'] ? 'form' : 'field';
}
```
After:
```
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\OptionsResolver\Options;
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$compound = function (Options $options) {
return $options['expanded'];
};
$resolver->setDefaults(array(
'compound' => $compound,
));
}
public function getParent()
{
return 'form';
}
```
The new method `setDefaultOptions` is described in the section "Deprecations".
* The "data_class" option now *must* be set if a form maps to an object. If
you leave it empty, the form will expect an array, an instance of \ArrayAccess
or a scalar value and fail with a corresponding exception.
Likewise, if a form maps to an array or an instance of \ArrayAccess, the option
*must* be left null now.
Form mapped to an instance of `Person`:
```
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\Demo\Person',
));
}
```
The new method `setDefaultOptions` is described in the section "Deprecations".
* The mapping of property paths to arrays has changed.
Previously, a property path "street" mapped to both a field `$street` of
a class (or its accessors `getStreet()` and `setStreet()`) and an index
`['street']` of an array or an object implementing `\ArrayAccess`.
Now, the property path "street" only maps to a class field (or accessors),
while the property path "[street]" only maps to indices.
If you defined property paths manually in the "property_path" option, you
should revise them and adjust them if necessary.
Before:
```
$builder->add('name', 'text', array(
'property_path' => 'address.street',
));
```
After (if the address object is an array):
```
$builder->add('name', 'text', array(
'property_path' => 'address[street]',
));
```
If address is an object in this case, the code given in "Before"
works without changes.
* The methods in class `FormView` were renamed to match the naming used in
`Form` and `FormBuilder`. The following list shows the old names on the
left and the new names on the right:
* `set`: `setVar`
* `has`: `hasVar`
* `get`: `getVar`
* `all`: `getVars`
* `addChild`: `add`
* `getChild`: `get`
* `getChildren`: `all`
* `removeChild`: `remove`
* `hasChild`: `has`
The new method `addVars` was added to make the definition of multiple
variables at once more convenient.
The method `hasChildren` was deprecated. You should use `count` instead.
Before:
```
$view->set('help', 'A text longer than six characters');
$view->set('error_class', 'max_length_error');
```
After:
```
$view->addVars(array(
'help' => 'A text longer than six characters',
'error_class' => 'max_length_error',
));
```
* Form and field names must now start with a letter, digit or underscore
and only contain letters, digits, underscores, hyphens and colons.
* In the collection type's template, the default name of the prototype field
has changed from `$$name$$` to `__name__`.
For custom names, dollar signs are no longer prepended and appended. You are
advised to prepend and append two underscores wherever you specify a value
for the field's "prototype_name" option.
Before:
```
$builder->add('tags', 'collection', array('prototype' => 'proto'));
// results in the name "$$proto$$" in the template
```
After:
```
$builder->add('tags', 'collection', array('prototype' => '__proto__'));
// results in the name "__proto__" in the template
```
* The "read_only" option now renders as `readonly="readonly"`, use
"disabled" instead for `disabled="disabled"`.
* Child forms are no longer automatically validated. That means that you must
explicitly set the `Valid` constraint in your model if you want to validate
associated objects.
objects modified by child forms.
If you don't want to set the `Valid` constraint, or if there is no reference
from the data of the parent form to the data of the child form, you can
enable BC behavior by setting the `cascade_validation` form option to `true`
enable BC behavior by setting the "cascade_validation" option to `true`
on the parent form.
* Changed implementation of choice lists
#### BC Breaks in Themes and HTML
ArrayChoiceList was replaced. If you have custom classes that extend this
class, you must now extend SimpleChoiceList.
* FormType and FieldType were merged and require you to adapt your form
themes.
The block `field_widget` and all references to it should be renamed to
`form_widget_simple`:
Before:
```
{% block url_widget %}
{% spaceless %}
{% set type = type|default('url') %}
{{ block('field_widget') }}
{% endspaceless %}
{% endblock url_widget %}
```
After:
```
{% block url_widget %}
{% spaceless %}
{% set type = type|default('url') %}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock url_widget %}
```
All other `field_*` blocks and references to them should be renamed to
`form_*`. If you previously defined both a `field_*` and a `form_*`
block, you can merge them into a single `form_*` block and check the new
Boolean variable `compound` instead:
Before:
```
{% block form_errors %}
{% spaceless %}
... form code ...
{% endspaceless %}
{% endblock form_errors %}
{% block field_errors %}
{% spaceless %}
... field code ...
{% endspaceless %}
{% endblock field_errors %}
```
After:
```
{% block form_errors %}
{% spaceless %}
{% if compound %}
... form code ...
{% else %}
... field code ...
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
```
Furthermore, the block `generic_label` was merged into `form_label`. You
should now override `form_label` in order to customize labels.
Last but not least, the block `widget_choice_options` was renamed to
`choice_widget_options` to be consistent with the rest of the default
theme.
* The strategy for generating the `id` and `name` HTML attributes for
checkboxes and radio buttons in a choice field has changed.
Instead of appending the choice value, a generated integer is now appended
by default. Take care if your JavaScript relies on that. If you want to
read the actual choice value, read the `value` attribute instead.
* In the choice field type's template, the structure of the `choices` variable
has changed.
The `choices` variable now contains `ChoiceView` objects with two getters,
`getValue()` and `getLabel()`, to access the choice data.
Before:
```
{% for choice, label in choices %}
<option value="{{ choice }}"{% if _form_is_choice_selected(form, choice) %} selected="selected"{% endif %}>
{{ label }}
</option>
{% endfor %}
```
After:
```
{% for choice in choices %}
<option value="{{ choice.value }}"{% if _form_is_choice_selected(form, choice) %} selected="selected"{% endif %}>
{{ choice.label }}
</option>
{% endfor %}
```
#### Other BC Breaks
* The order of the first two arguments of the methods `createNamed` and
`createNamedBuilder` in `FormFactoryInterface` was reversed to be
consistent with the rest of the component. You should scan your code
for occurrences of these methods and reverse the parameters.
Before:
```
$form = $factory->createNamed('text', 'firstName');
```
After:
```
$form = $factory->createNamed('firstName', 'text');
```
* The implementation of `ChoiceList` was changed heavily. As a result,
`ArrayChoiceList` was replaced. If you have custom classes that extend
this class, you must now extend `SimpleChoiceList` and pass choices
to the parent constructor.
Before:
@ -190,7 +501,8 @@
```
If you need to load the choices lazily -- that is, as soon as they are
accessed for the first time -- you can extend LazyChoiceList instead.
accessed for the first time -- you can extend `LazyChoiceList` instead
and load the choices by overriding `loadChoiceList()`.
```
class MyChoiceList extends LazyChoiceList
@ -204,81 +516,20 @@
}
```
PaddedChoiceList, MonthChoiceList and TimezoneChoiceList were removed.
Their functionality was merged into DateType, TimeType and TimezoneType.
`PaddedChoiceList`, `MonthChoiceList` and `TimezoneChoiceList` were removed.
Their functionality was merged into `DateType`, `TimeType` and `TimezoneType`.
EntityChoiceList was adapted. The methods `getEntities()`,
`EntityChoiceList` was adapted. The methods `getEntities()`,
`getEntitiesByKeys()`, `getIdentifier()` and `getIdentifierValues()` were
removed or made private. Instead of the first two, you can now use
`getChoices()` and `getChoicesByValues()`. For the latter two, no
replacement exists.
* The strategy for generating the `id` and `name` HTML attributes for
checkboxes and radio buttons in a choice field has changed.
Instead of appending the choice value, a generated integer is now appended
by default. Take care if your JavaScript relies on that.
* In the choice field type's template, the structure of the `choices` variable
has changed.
The `choices` variable now contains ChoiceView objects with two getters,
`getValue()` and `getLabel()`, to access the choice data.
Before:
```
{% for choice, label in choices %}
<option value="{{ choice }}"{% if _form_is_choice_selected(form, choice) %} selected="selected"{% endif %}>
{{ label }}
</option>
{% endfor %}
```
After:
```
{% for choice in choices %}
<option value="{{ choice.value }}"{% if _form_is_choice_selected(form, choice) %} selected="selected"{% endif %}>
{{ choice.label }}
</option>
{% endfor %}
```
* In the collection type's template, the default name of the prototype field
has changed from `$$name$$` to `__name__`.
For custom names, dollar signs are no longer prepended and appended. You are
advised to prepend and append two underscores wherever you specify a value
for the field's `prototype_name` option.
Before:
```
$builder->add('tags', 'collection', array('prototype' => 'proto'));
// results in the name "$$proto$$" in the template
```
After:
```
$builder->add('tags', 'collection', array('prototype' => '__proto__'));
// results in the name "__proto__" in the template
```
* The `read_only` field attribute now renders as `readonly="readonly"`, use
`disabled` instead for `disabled="disabled"`.
* Form and field names must now start with a letter, digit or underscore
and only contain letters, digits, underscores, hyphens and colons
* `EntitiesToArrayTransformer` and `EntityToIdTransformer` have been removed.
The former has been replaced by `CollectionToArrayTransformer` in combination
* `EntitiesToArrayTransformer` and `EntityToIdTransformer` were removed.
The former was replaced by `CollectionToArrayTransformer` in combination
with `EntityChoiceList`, the latter is not required in the core anymore.
* The following transformers have been renamed:
* The following transformers were renamed:
* `ArrayToBooleanChoicesTransformer` to `ChoicesToBooleanArrayTransformer`
* `ScalarToBooleanChoicesTransformer` to `ChoiceToBooleanArrayTransformer`
@ -287,36 +538,61 @@
to be consistent with the naming in `ChoiceListInterface`.
* `FormUtil::toArrayKey()` and `FormUtil::toArrayKeys()` have been removed.
* `FormUtil::toArrayKey()` and `FormUtil::toArrayKeys()` were removed.
They were merged into ChoiceList and have no public equivalent anymore.
* The options passed to the `getParent()` method of form types no longer
contain default options. They only contain the options passed by the user.
* The `add()`, `remove()`, `setParent()`, `bind()` and `setData()` methods in
the Form class now throw an exception if the form is already bound.
You should check if options exist before attempting to read their value.
If you used these methods on bound forms, you should consider moving your
logic to an event listener that observes `FormEvents::PRE_BIND` or
`FormEvents::BIND`.
#### Deprecations
* The following methods of `FormTypeInterface` and `FormTypeExtensionInterface`
are deprecated and will be removed in Symfony 2.3:
* `getDefaultOptions`
* `getAllowedOptionValues`
You should use the newly added `setDefaultOptions` instead, which gives you
access to the OptionsResolverInterface instance and with that a lot more power.
Before:
```
public function getParent(array $options)
public function getDefaultOptions(array $options)
{
return 'single_text' === $options['widget'] ? 'text' : 'choice';
return array(
'gender' => 'male',
);
}
public function getAllowedOptionValues(array $options)
{
return array(
'gender' => array('male', 'female'),
);
}
```
After:
```
public function getParent(array $options)
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice';
$resolver->setDefaults(array(
'gender' => 'male',
));
$resolver->setAllowedValues(array(
'gender' => array('male', 'female'),
));
}
```
* The methods `getDefaultOptions()` and `getAllowedOptionValues()` of form
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.
Before:
@ -336,109 +612,87 @@
After:
```
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
'empty_data' => function (Options $options, $previousValue) {
return $options['multiple'] ? array() : $previousValue;
$resolver->setDefaults(array(
'empty_data' => function (Options $options, $value) {
return $options['multiple'] ? array() : $value;
}
);
));
}
```
The second argument `$previousValue` does not have to be specified if not
needed.
The second argument `$value` contains the current default value and
does not have to be specified if not needed.
* The `add()`, `remove()`, `setParent()`, `bind()` and `setData()` methods in
the Form class now throw an exception if the form is already bound.
* The following methods in `FormBuilder` were deprecated and have a new
equivalent:
If you used these methods on bound forms, you should consider moving your
logic to an event listener that observes one of the following events:
`FormEvents::PRE_BIND`, `FormEvents::BIND_CLIENT_DATA` or
`FormEvents::BIND_NORM_DATA`.
* `prependClientTransformer`: `addViewTransformer`
* `appendClientTransformer`: no new equivalent, consider using `addViewTransformer`
* `getClientTransformers`: `getViewTransformers`
* `resetClientTransformers`: `resetViewTransformers`
* `prependNormTransformer`: no new equivalent, consider using `addModelTransformer`
* `appendNormTransformer`: `addModelTransformer`
* `getNormTransformers`: `getModelTransformers`
* `resetNormTransformers`: `resetModelTransformers`
* The interface FormValidatorInterface was deprecated and will be removed
The deprecated methods will be removed in Symfony 2.3. You are advised to
update your application.
Before:
```
$builder->prependClientTransformer(new MyTransformer());
```
After:
```
$builder->addViewTransformer(new MyTransformer());
```
* The following events were deprecated and have a new equivalent:
* `FormEvents::SET_DATA`: `FormEvents::PRE_SET_DATA`
* `FormEvents::BIND_CLIENT_DATA`: `FormEvents::PRE_BIND`
* `FormEvents::BIND_NORM_DATA`: `FormEvents::BIND`
The deprecated events will be removed in Symfony 2.3.
Furthermore, the event classes `DataEvent` and `FilterDataEvent` were
deprecated and replaced by the generic `FormEvent`. You are advised to
code your listeners against the new event now. The deprecated events will
be removed in Symfony 2.3.
Before:
```
$builder->addListener(FormEvents::BIND_CLIENT_DATA, function (FilterDataEvent $event) {
// ...
});
```
After:
```
$builder->addListener(FormEvents::PRE_BIND, function (FormEvent $event) {
// ...
});
```
* The interface `FormValidatorInterface` was deprecated and will be removed
in Symfony 2.3.
If you implemented custom validators using this interface, you can
substitute them by event listeners listening to the FormEvents::POST_BIND
(or any other of the BIND events). In case you used the CallbackValidator
substitute them by event listeners listening to the `FormEvents::POST_BIND`
(or any other of the `*BIND` events). In case you used the CallbackValidator
class, you should now pass the callback directly to `addEventListener`.
* Since FormType and FieldType were merged, you need to adapt your form
themes.
The "field_widget" and all references to it should be renamed to
"form_widget_single_control":
Before:
```
{% block url_widget %}
{% spaceless %}
{% set type = type|default('url') %}
{{ block('field_widget') }}
{% endspaceless %}
{% endblock url_widget %}
```
After:
```
{% block url_widget %}
{% spaceless %}
{% set type = type|default('url') %}
{{ block('form_widget_single_control') }}
{% endspaceless %}
{% endblock url_widget %}
```
All other "field_*" blocks and references to them should be renamed to
"form_*". If you previously defined both a "field_*" and a "form_*"
block, you can merge them into a single "form_*" block and check the new
Boolean variable "single_control":
Before:
```
{% block form_errors %}
{% spaceless %}
... form code ...
{% endspaceless %}
{% endblock form_errors %}
{% block field_errors %}
{% spaceless %}
... field code ...
{% endspaceless %}
{% endblock field_errors %}
```
After:
```
{% block form_errors %}
{% spaceless %}
{% if single_control %}
... field code ...
{% else %}
... form code ...
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
```
Furthermore, the block "generic_label" was merged into "form_label". You
should now override "form_label" in order to customize labels.
Last but not least, the block "widget_choice_options" was renamed to
"choice_widget_options" to be consistent with the rest of the default
theme.
* The method `guessMinLength()` of FormTypeGuesserInterface was deprecated
* The method `guessMinLength()` of `FormTypeGuesserInterface` was deprecated
and will be removed in Symfony 2.3. You should use the new method
`guessPattern()` instead which may return any regular expression that
is inserted in the HTML5 attribute "pattern".
is inserted in the HTML5 attribute `pattern`.
Before:
@ -480,52 +734,18 @@
));
```
* The "data_class" option now *must* be set if a form maps to an object. If
you leave it empty, the form will expect an array or a scalar value and
fail with a corresponding exception.
Likewise, if a form maps to an array, the option *must* be left empty now.
* The mapping of property paths to arrays has changed.
Previously, a property path "street" mapped to both a field `$street` of
a class (or its accessors `getStreet()` and `setStreet()`) and an index
`['street']` of an array or an object implementing `\ArrayAccess`.
Now, the property path "street" only maps to a class field (or accessors),
while the property path "[street]" only maps to indices.
If you defined property paths manually in the "property_path" option, you
should revise them and adjust them if necessary.
Before:
```
$builder->add('name', 'text', array(
'property_path' => 'address.street',
));
```
After (if the address object is an array):
```
$builder->add('name', 'text', array(
'property_path' => 'address[street]',
));
```
If address is an object in this case, the code given in "Before"
works without changes.
* The following methods in `Form` are deprecated and will be removed in
* The following methods in `Form` were deprecated and will be removed in
Symfony 2.3:
* `getTypes`
* `getErrorBubbling`
* `getNormTransformers`
* `getClientTransformers`
You can access these methods on the `FormConfigInterface` object instead.
* `getAttribute`
* `hasAttribute`
* `getClientData`
* `getChildren`
* `hasChildren`
Before:
@ -539,7 +759,25 @@
$form->getConfig()->getErrorBubbling();
```
* The option "validation_constraint" is deprecated and will be removed
The method `getClientData` has a new equivalent that is named `getViewData`.
You can access all other methods on the `FormConfigInterface` object instead.
Instead of `getChildren` and `hasChildren`, you should now use `all` and
`count`.
Before:
```
if ($form->hasChildren()) {
```
After:
```
if (count($form) > 0) {
```
* The option "validation_constraint" was deprecated and will be removed
in Symfony 2.3. You should use the option "constraints" instead,
where you can pass one or more constraints for a form.

View File

@ -12,7 +12,7 @@
namespace Symfony\Bridge\Doctrine\Form\EventListener;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@ -30,10 +30,10 @@ class MergeDoctrineCollectionListener implements EventSubscriberInterface
{
// Higher priority than core MergeCollectionListener so that this one
// is called before
return array(FormEvents::BIND_NORM_DATA => array('onBindNormData', 10));
return array(FormEvents::BIND => array('onBind', 10));
}
public function onBindNormData(FilterDataEvent $event)
public function onBind(FormEvent $event)
{
$collection = $event->getForm()->getData();
$data = $event->getData();

View File

@ -13,13 +13,14 @@ namespace Symfony\Bridge\Doctrine\Form\Type;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList;
use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface;
use Symfony\Bridge\Doctrine\Form\EventListener\MergeDoctrineCollectionListener;
use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
abstract class DoctrineType extends AbstractType
{
@ -33,7 +34,7 @@ abstract class DoctrineType extends AbstractType
$this->registry = $registry;
}
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['multiple']) {
$builder
@ -43,7 +44,7 @@ abstract class DoctrineType extends AbstractType
}
}
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$registry = $this->registry;
$type = $this;
@ -71,7 +72,7 @@ abstract class DoctrineType extends AbstractType
);
};
return array(
$resolver->setDefaults(array(
'em' => null,
'class' => null,
'property' => null,
@ -80,7 +81,7 @@ abstract class DoctrineType extends AbstractType
'choices' => null,
'choice_list' => $choiceList,
'group_by' => null,
);
));
}
/**
@ -93,7 +94,7 @@ abstract class DoctrineType extends AbstractType
*/
abstract public function getLoader(ObjectManager $manager, $queryBuilder, $class);
public function getParent(array $options)
public function getParent()
{
return 'choice';
}

View File

@ -108,14 +108,14 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'required' => false,
'property' => 'name'
));
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->get('choices'));
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->getVar('choices'));
}
public function testSetDataToUninitializedEntityWithNonRequiredToString()
@ -125,13 +125,13 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'required' => false,
));
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->get('choices'));
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->getVar('choices'));
}
public function testSetDataToUninitializedEntityWithNonRequiredQueryBuilder()
@ -142,7 +142,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2));
$qb = $this->em->createQueryBuilder()->select('e')->from(self::SINGLE_IDENT_CLASS, 'e');
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'required' => false,
@ -150,7 +150,7 @@ class EntityTypeTest extends TypeTestCase
'query_builder' => $qb
));
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->get('choices'));
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->getVar('choices'));
}
/**
@ -158,7 +158,7 @@ class EntityTypeTest extends TypeTestCase
*/
public function testConfigureQueryBuilderWithNonQueryBuilderAndNonClosure()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => new \stdClass(),
@ -170,7 +170,7 @@ class EntityTypeTest extends TypeTestCase
*/
public function testConfigureQueryBuilderWithClosureReturningNonQueryBuilder()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => function () {
@ -183,7 +183,7 @@ class EntityTypeTest extends TypeTestCase
public function testSetDataSingleNull()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
@ -196,7 +196,7 @@ class EntityTypeTest extends TypeTestCase
public function testSetDataMultipleExpandedNull()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'expanded' => true,
'em' => 'default',
@ -210,7 +210,7 @@ class EntityTypeTest extends TypeTestCase
public function testSetDataMultipleNonExpandedNull()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'expanded' => false,
'em' => 'default',
@ -224,7 +224,7 @@ class EntityTypeTest extends TypeTestCase
public function testSubmitSingleExpandedNull()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'expanded' => true,
'em' => 'default',
@ -238,7 +238,7 @@ class EntityTypeTest extends TypeTestCase
public function testSubmitSingleNonExpandedNull()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'expanded' => false,
'em' => 'default',
@ -252,7 +252,7 @@ class EntityTypeTest extends TypeTestCase
public function testSubmitMultipleNull()
{
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
@ -270,7 +270,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'expanded' => false,
'em' => 'default',
@ -292,7 +292,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'expanded' => false,
'em' => 'default',
@ -316,7 +316,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'expanded' => false,
'em' => 'default',
@ -341,7 +341,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'expanded' => false,
'em' => 'default',
@ -372,7 +372,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'expanded' => false,
'em' => 'default',
@ -398,7 +398,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'expanded' => false,
'em' => 'default',
@ -428,7 +428,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'expanded' => true,
'em' => 'default',
@ -454,7 +454,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => true,
'expanded' => true,
'em' => 'default',
@ -484,7 +484,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
// not all persisted entities should be displayed
@ -494,7 +494,7 @@ class EntityTypeTest extends TypeTestCase
$field->bind('2');
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->get('choices'));
$this->assertEquals(array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')), $field->createView()->getVar('choices'));
$this->assertTrue($field->isSynchronized());
$this->assertSame($entity2, $field->getData());
$this->assertSame('2', $field->getClientData());
@ -509,7 +509,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($item1, $item2, $item3, $item4));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::ITEM_GROUP_CLASS,
'choices' => array($item1, $item2, $item3, $item4),
@ -524,7 +524,7 @@ class EntityTypeTest extends TypeTestCase
'Group1' => array(1 => new ChoiceView('1', 'Foo'), 2 => new ChoiceView('2', 'Bar')),
'Group2' => array(3 => new ChoiceView('3', 'Baz')),
'4' => new ChoiceView('4', 'Boo!')
), $field->createView()->get('choices'));
), $field->createView()->getVar('choices'));
}
public function testDisallowChoicesThatAreNotIncluded_choicesSingleIdentifier()
@ -535,7 +535,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'choices' => array($entity1, $entity2),
@ -556,7 +556,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::COMPOSITE_IDENT_CLASS,
'choices' => array($entity1, $entity2),
@ -579,7 +579,7 @@ class EntityTypeTest extends TypeTestCase
$repository = $this->em->getRepository(self::SINGLE_IDENT_CLASS);
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => $repository->createQueryBuilder('e')
@ -601,7 +601,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => function ($repository) {
@ -625,7 +625,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1, $entity2, $entity3));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'em' => 'default',
'class' => self::COMPOSITE_IDENT_CLASS,
'query_builder' => function ($repository) {
@ -647,7 +647,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'expanded' => false,
'em' => 'default',
@ -668,7 +668,7 @@ class EntityTypeTest extends TypeTestCase
$this->persist(array($entity1));
$field = $this->factory->createNamed('entity', 'name', null, array(
$field = $this->factory->createNamed('name', 'entity', null, array(
'multiple' => false,
'expanded' => false,
'em' => 'default',

View File

@ -14,8 +14,9 @@ namespace Symfony\Bridge\Propel1\Form\Type;
use Symfony\Bridge\Propel1\Form\ChoiceList\ModelChoiceList;
use Symfony\Bridge\Propel1\Form\DataTransformer\CollectionToArrayTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* ModelType class.
@ -24,14 +25,14 @@ use Symfony\Component\OptionsResolver\Options;
*/
class ModelType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['multiple']) {
$builder->prependClientTransformer(new CollectionToArrayTransformer());
}
}
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$choiceList = function (Options $options) {
return new ModelChoiceList(
@ -43,7 +44,7 @@ class ModelType extends AbstractType
);
};
return array(
$resolver->setDefaults(array(
'template' => 'choice',
'multiple' => false,
'expanded' => false,
@ -54,10 +55,10 @@ class ModelType extends AbstractType
'choice_list' => $choiceList,
'group_by' => null,
'by_reference' => false,
);
));
}
public function getParent(array $options)
public function getParent()
{
return 'choice';
}

View File

@ -98,7 +98,7 @@ class FormExtension extends \Twig_Extension
public function isChoiceSelected(FormView $view, ChoiceView $choice)
{
return FormUtil::isChoiceSelected($choice->getValue(), $view->get('value'));
return FormUtil::isChoiceSelected($choice->getValue(), $view->getVar('value'));
}
/**
@ -228,7 +228,7 @@ class FormExtension extends \Twig_Extension
}
}
$custom = '_'.$view->get('id');
$custom = '_'.$view->getVar('id');
$rendering = $custom.$section;
$blocks = $this->getBlocks($view);
@ -237,11 +237,11 @@ class FormExtension extends \Twig_Extension
$types = $this->varStack[$rendering]['types'];
$this->varStack[$rendering]['variables'] = array_replace_recursive($this->varStack[$rendering]['variables'], $variables);
} else {
$types = $view->get('types');
$types = $view->getVar('types');
$types[] = $custom;
$typeIndex = count($types) - 1;
$this->varStack[$rendering] = array(
'variables' => array_replace_recursive($view->all(), $variables),
'variables' => array_replace_recursive($view->getVars(), $variables),
'types' => $types,
);
}

View File

@ -2,20 +2,20 @@
{% block form_widget %}
{% spaceless %}
{% if single_control %}
{{ block('form_widget_single_control') }}
{% else %}
{% if compound %}
{{ block('form_widget_compound') }}
{% else %}
{{ block('form_widget_simple') }}
{% endif %}
{% endspaceless %}
{% endblock form_widget %}
{% block form_widget_single_control %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_single_control %}
{% endblock form_widget_simple %}
{% block form_widget_compound %}
{% spaceless %}
@ -112,7 +112,7 @@
{% block datetime_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% else %}
<div {{ block('widget_container_attributes') }}>
{{ form_errors(form.date) }}
@ -127,7 +127,7 @@
{% block date_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% else %}
<div {{ block('widget_container_attributes') }}>
{{ date_pattern|replace({
@ -143,7 +143,7 @@
{% block time_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% else %}
<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 %}
@ -156,62 +156,62 @@
{% spaceless %}
{# type="number" doesn't work with floats #}
{% set type = type|default('text') %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock number_widget %}
{% block integer_widget %}
{% spaceless %}
{% set type = type|default('number') %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock integer_widget %}
{% block money_widget %}
{% spaceless %}
{{ money_pattern|replace({ '{{ widget }}': block('form_widget_single_control') })|raw }}
{{ money_pattern|replace({ '{{ widget }}': block('form_widget_simple') })|raw }}
{% endspaceless %}
{% endblock money_widget %}
{% block url_widget %}
{% spaceless %}
{% set type = type|default('url') %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock url_widget %}
{% block search_widget %}
{% spaceless %}
{% set type = type|default('search') %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock search_widget %}
{% block percent_widget %}
{% spaceless %}
{% set type = type|default('text') %}
{{ block('form_widget_single_control') }} %
{{ block('form_widget_simple') }} %
{% endspaceless %}
{% endblock percent_widget %}
{% block password_widget %}
{% spaceless %}
{% set type = type|default('password') %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock password_widget %}
{% block hidden_widget %}
{% spaceless %}
{% set type = type|default('hidden') %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock hidden_widget %}
{% block email_widget %}
{% spaceless %}
{% set type = type|default('email') %}
{{ block('form_widget_single_control') }}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock email_widget %}
@ -219,7 +219,7 @@
{% block form_label %}
{% spaceless %}
{% if single_control %}
{% if not compound %}
{% set label_attr = label_attr|merge({'for': id}) %}
{% endif %}
{% if required %}
@ -245,7 +245,7 @@
If the child is a compound form, the errors are rendered inside
the container. See also block form_rows.
#}
{% if single_control %}
{% if not compound %}
{{ form_errors(form) }}
{% endif %}
{{ form_widget(form) }}
@ -320,7 +320,7 @@
{% block generic_label %}{{ block('form_label') }}{% endblock %}
{% block widget_choice_options %}{{ block('choice_widget_options') }}{% endblock %}
{% block field_widget %}{{ block('form_widget_single_control') }}{% endblock %}
{% block field_widget %}{{ block('form_widget_simple') }}{% endblock %}
{% block field_label %}{{ block('form_label') }}{% endblock %}
{% block field_row %}{{ block('form_row') }}{% endblock %}
{% block field_enctype %}{{ block('form_enctype') }}{% endblock %}

View File

@ -7,7 +7,7 @@
{{ form_label(form, label|default(null)) }}
</td>
<td>
{% if single_control %}
{% if not compound %}
{{ form_errors(form) }}
{% endif %}
{{ form_widget(form) }}
@ -18,7 +18,7 @@
{% block form_errors %}
{% spaceless %}
{% if single_control %}
{% if not compound %}
{{ parent() }}
{% else %}
{% if errors|length > 0 %}

View File

@ -69,7 +69,7 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
public function testThemeBlockInheritanceUsingUse()
{
$view = $this->factory
->createNamed('email', 'name')
->createNamed('name', 'email')
->createView()
;
@ -84,7 +84,7 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
public function testThemeBlockInheritanceUsingExtend()
{
$view = $this->factory
->createNamed('email', 'name')
->createNamed('name', 'email')
->createView()
;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<?php if ($widget == 'single_text'): ?>
<?php echo $view['form']->renderBlock('form_widget_single_control'); ?>
<?php echo $view['form']->renderBlock('form_widget_simple'); ?>
<?php else: ?>
<div <?php echo $view['form']->renderBlock('widget_container_attributes') ?>>
<?php echo $view['form']->widget($form['date']).' '.$view['form']->widget($form['time']) ?>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<?php if ($single_control): ?>
<?php echo $view['form']->renderBlock('form_widget_single_control')?>
<?php else: ?>
<?php if ($compound): ?>
<?php echo $view['form']->renderBlock('form_widget_compound')?>
<?php else: ?>
<?php echo $view['form']->renderBlock('form_widget_simple')?>
<?php endif ?>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
<?php if ($single_control): ?>
<?php if (!$compound): ?>
<?php if ($errors): ?>
<ul>
<?php foreach ($errors as $error): ?>

View File

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

View File

@ -66,7 +66,7 @@ class FormHelper extends Helper
public function isChoiceSelected(FormView $view, ChoiceView $choice)
{
return FormUtil::isChoiceSelected($choice->getValue(), $view->get('value'));
return FormUtil::isChoiceSelected($choice->getValue(), $view->getVar('value'));
}
/**
@ -79,7 +79,7 @@ class FormHelper extends Helper
*/
public function setTheme(FormView $view, $themes)
{
$this->themes[$view->get('id')] = (array) $themes;
$this->themes[$view->getVar('id')] = (array) $themes;
$this->templates = array();
}
@ -237,7 +237,7 @@ class FormHelper extends Helper
$template = null;
$custom = '_'.$view->get('id');
$custom = '_'.$view->getVar('id');
$rendering = $custom.$section;
if (isset($this->varStack[$rendering])) {
@ -245,10 +245,10 @@ class FormHelper extends Helper
$types = $this->varStack[$rendering]['types'];
$variables = array_replace_recursive($this->varStack[$rendering]['variables'], $variables);
} else {
$types = $view->get('types');
$types = $view->getVar('types');
$types[] = $custom;
$typeIndex = count($types) - 1;
$variables = array_replace_recursive($view->all(), $variables);
$variables = array_replace_recursive($view->getVars(), $variables);
$this->varStack[$rendering]['types'] = $types;
}
@ -330,7 +330,7 @@ class FormHelper extends Helper
protected function lookupTemplate(FormView $view, $block)
{
$file = $block.'.html.php';
$id = $view->get('id');
$id = $view->getVar('id');
if (!isset($this->templates[$id][$block])) {
$template = false;

View File

@ -12,12 +12,13 @@
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* Form type for use with the Security component's form-based authentication
@ -28,7 +29,7 @@ use Symfony\Component\Security\Core\SecurityContextInterface;
*/
class UserLoginFormType extends AbstractType
{
private $reqeust;
private $request;
/**
* @param Request $request A request instance
@ -41,7 +42,7 @@ class UserLoginFormType extends AbstractType
/**
* @see Symfony\Component\Form\AbstractType::buildForm()
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', 'text')
@ -56,7 +57,7 @@ class UserLoginFormType extends AbstractType
* request; however, we can match the expected behavior by checking the
* session for an authentication error and last username.
*/
$builder->addEventListener(FormEvents::SET_DATA, function (FilterDataEvent $event) use ($request) {
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($request) {
if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContextInterface::AUTHENTICATION_ERROR);
} else {
@ -74,17 +75,17 @@ class UserLoginFormType extends AbstractType
}
/**
* @see Symfony\Component\Form\AbstractType::getDefaultOptions()
* @see Symfony\Component\Form\AbstractType::setDefaultOptions()
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
/* Note: the form's intention must correspond to that for the form login
* listener in order for the CSRF token to validate successfully.
*/
return array(
$resolver->setDefaults(array(
'intention' => 'authenticate',
);
));
}
/**

View File

@ -12,7 +12,11 @@
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class AbstractType implements FormTypeInterface
{
/**
@ -24,21 +28,21 @@ abstract class AbstractType implements FormTypeInterface
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
}
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
}
@ -53,13 +57,32 @@ abstract class AbstractType implements FormTypeInterface
/**
* {@inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults($this->getDefaultOptions());
$resolver->addAllowedValues($this->getAllowedOptionValues());
}
/**
* Returns the default options for this type.
*
* @return array The default options
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* Use {@link setDefaultOptions()} instead.
*/
public function getDefaultOptions()
{
return array();
}
/**
* {@inheritdoc}
* Returns the allowed option values for each option (if any).
*
* @return array The allowed option values
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* Use {@link setDefaultOptions()} instead.
*/
public function getAllowedOptionValues()
{
@ -69,7 +92,7 @@ abstract class AbstractType implements FormTypeInterface
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'form';
}

View File

@ -11,39 +11,63 @@
namespace Symfony\Component\Form;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class AbstractTypeExtension implements FormTypeExtensionInterface
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
}
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
}
/**
* {@inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults($this->getDefaultOptions());
$resolver->addAllowedValues($this->getAllowedOptionValues());
}
/**
* Overrides the default options form the extended type.
*
* @return array
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* Use {@link setDefaultOptions()} instead.
*/
public function getDefaultOptions()
{
return array();
}
/**
* {@inheritdoc}
* Returns the allowed option values for each option (if any).
*
* @return array The allowed option values
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* Use {@link setDefaultOptions()} instead.
*/
public function getAllowedOptionValues()
{

View File

@ -43,7 +43,6 @@ CHANGELOG
* forms now don't create an empty object anymore if they are completely
empty and not required. The empty value for such forms is null.
* added constant Guess::VERY_HIGH_CONFIDENCE
* [BC BREAK] FormType::getParent() does not see default options anymore
* [BC BREAK] The methods `add`, `remove`, `setParent`, `bind` and `setData`
in class Form now throw an exception if the form is already bound
* fields of constrained classes without a NotBlank or NotNull constraint are
@ -52,15 +51,14 @@ CHANGELOG
"single_text" unless "with_seconds" is set to true
* checkboxes of in an expanded multiple-choice field don't include the choice
in their name anymore. Their names terminate with "[]" now.
* [BC BREAK] FormType::getDefaultOptions() and FormType::getAllowedOptionValues()
don't receive an options array anymore.
* deprecated FormValidatorInterface and substituted its implementations
by event subscribers
* simplified CSRF protection and removed the csrf type
* deprecated FieldType and merged it into FormType
* added new option "compound" that lets you switch between field and form behavior
* [BC BREAK] renamed theme blocks
* "field_*" to "form_*"
* "field_widget" to "form_widget_single_control"
* "field_widget" to "form_widget_simple"
* "widget_choice_options" to "choice_widget_options"
* "generic_label" to "form_label"
* added theme blocks "form_widget_compound", "choice_widget_expanded" and
@ -78,13 +76,66 @@ CHANGELOG
* errors are not mapped to unsynchronized forms anymore
* [BC BREAK] changed Form constructor to accept a single `FormConfigInterface` object
* [BC BREAK] changed argument order in the FormBuilder constructor
* added Form method `getViewData`
* deprecated Form methods
* `getTypes`
* `getErrorBubbling`
* `getNormTransformers`
* `getClientTransformers`
* `getAttribute`
* `hasAttribute`
* `getClientData`
* added FormBuilder methods
* `addViewTransformer`
* `getViewTransformers`
* `resetViewTransformers`
* `addModelTransformer`
* `getModelTransformers`
* `resetModelTransformers`
* deprecated FormBuilder methods
* `prependClientTransformer`
* `appendClientTransformer`
* `getClientTransformers`
* `resetClientTransformers`
* `prependNormTransformer`
* `appendNormTransformer`
* `getNormTransformers`
* `resetNormTransformers`
* deprecated the option "validation_constraint" in favor of the new
option "constraints"
* removed superfluous methods from DataMapperInterface
* `mapFormToData`
* `mapDataToForm`
* [BC BREAK] FormType::getDefaultOptions() and FormType::getAllowedOptionValues()
don't receive an options array anymore.
* added `setDefaultOptions` to FormTypeInterface and FormTypeExtensionInterface
which accepts an OptionsResolverInterface instance
* deprecated the methods `getDefaultOptions` and `getAllowedOptionValues`
in FormTypeInterface and FormTypeExtensionInterface
* options passed during construction can now be accessed from FormConfigInterface
* added FormBuilderInterface, FormViewInterface and FormConfigEditorInterface
* [BC BREAK] the methods in FormTypeInterface and FormTypeExtensionInterface now
receive FormBuilderInterface and FormViewInterface instead of FormBuilder and
FormView
* [BC BREAK] the method `buildViewBottomUp` was renamed to `finishView` in
FormTypeInterface and FormTypeExtensionInterface
* [BC BREAK] the options array is now passed as last argument of the
methods
* `buildView`
* `finishView`
in FormTypeInterface and FormTypeExtensionInterface
* [BC BREAK] no options are passed to `getParent` of FormTypeInterface anymore
* deprecated DataEvent and FilterDataEvent in favor of the new FormEvent which is
now passed to all events thrown by the component
* FormEvents::BIND now replaces FormEvents::BIND_NORM_DATA
* FormEvents::PRE_SET_DATA now replaces FormEvents::SET_DATA
* FormEvents::PRE_BIND now replaces FormEvents::BIND_CLIENT_DATA
* deprecated FormEvents::SET_DATA, FormEvents::BIND_CLIENT_DATA and
FormEvents::BIND_NORM_DATA
* [BC BREAK] reversed the order of the first two arguments to `createNamed`
and `createNamedBuilder` in `FormFactoryInterface`
* [BC BREAK] adapted methods of FormView to match the naming used in
FormInterface and FormBuilder
* deprecated `getChildren` in Form and FormBuilder in favor of `all`
* deprecated `hasChildren` in Form and FormBuilder in favor of `count`
* FormBuilder now implements \IteratorAggregate

View File

@ -11,15 +11,28 @@
namespace Symfony\Component\Form;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface DataMapperInterface
{
/**
* @param dataClass $data
* @param array $forms
* Maps properties of some data to a list of forms.
*
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
* @param mixed $data Structured data.
* @param array $forms A list of {@link FormInterface} instances.
*
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported.
*/
function mapDataToForms($data, array $forms);
/**
* Maps the data of a list of forms into the properties of some data.
*
* @param array $forms A list of {@link FormInterface} instances.
* @param mixed $data Structured data.
*
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported.
*/
function mapFormsToData(array $forms, &$data);
}

View File

@ -14,6 +14,12 @@ namespace Symfony\Component\Form\Event;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\Form\FormInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Code against
* {@link \Symfony\Component\Form\FormEvent} instead.
*/
class DataEvent extends Event
{
private $form;
@ -50,4 +56,14 @@ class DataEvent extends Event
{
return $this->data;
}
/**
* Allows updating with some filtered data
*
* @param mixed $data
*/
public function setData($data)
{
$this->data = $data;
}
}

View File

@ -11,15 +11,12 @@
namespace Symfony\Component\Form\Event;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Code against
* {@link \Symfony\Component\Form\FormEvent} instead.
*/
class FilterDataEvent extends DataEvent
{
/**
* Allows updating with some filtered data
*
* @param mixed $data
*/
public function setData($data)
{
$this->data = $data;
}
}

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
@ -36,7 +36,7 @@ class FixCheckboxInputListener implements EventSubscriberInterface
$this->choiceList = $choiceList;
}
public function onBindClientData(FilterDataEvent $event)
public function preBind(FormEvent $event)
{
$values = (array) $event->getData();
$indices = $this->choiceList->getIndicesForValues($values);
@ -46,6 +46,6 @@ class FixCheckboxInputListener implements EventSubscriberInterface
static public function getSubscribedEvents()
{
return array(FormEvents::BIND_CLIENT_DATA => 'onBindClientData');
return array(FormEvents::PRE_BIND => 'preBind');
}
}

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
@ -36,7 +36,7 @@ class FixRadioInputListener implements EventSubscriberInterface
$this->choiceList = $choiceList;
}
public function onBindClientData(FilterDataEvent $event)
public function preBind(FormEvent $event)
{
$value = $event->getData();
$index = current($this->choiceList->getIndicesForValues(array($value)));
@ -46,6 +46,6 @@ class FixRadioInputListener implements EventSubscriberInterface
static public function getSubscribedEvents()
{
return array(FormEvents::BIND_CLIENT_DATA => 'onBindClientData');
return array(FormEvents::PRE_BIND => 'preBind');
}
}

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@ -29,7 +29,7 @@ class FixUrlProtocolListener implements EventSubscriberInterface
$this->defaultProtocol = $defaultProtocol;
}
public function onBindNormData(FilterDataEvent $event)
public function onBind(FormEvent $event)
{
$data = $event->getData();
@ -40,6 +40,6 @@ class FixUrlProtocolListener implements EventSubscriberInterface
static public function getSubscribedEvents()
{
return array(FormEvents::BIND_NORM_DATA => 'onBindNormData');
return array(FormEvents::BIND => 'onBind');
}
}

View File

@ -13,7 +13,7 @@ namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
/**
@ -50,15 +50,13 @@ class MergeCollectionListener implements EventSubscriberInterface
static public function getSubscribedEvents()
{
return array(
FormEvents::BIND_NORM_DATA => 'onBindNormData',
FormEvents::BIND => 'onBind',
);
}
public function onBindNormData(FilterDataEvent $event)
public function onBind(FormEvent $event)
{
$dataToMergeInto = $event->getForm()->getNormData();
$form = $event->getForm();
$data = $event->getData();
if (null === $data) {

View File

@ -12,8 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@ -67,11 +66,11 @@ class ResizeFormListener implements EventSubscriberInterface
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_BIND => 'preBind',
// (MergeCollectionListener, MergeDoctrineCollectionListener)
FormEvents::BIND_NORM_DATA => array('onBindNormData', 50),
FormEvents::BIND => array('onBind', 50),
);
}
public function preSetData(DataEvent $event)
public function preSetData(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
@ -91,13 +90,13 @@ class ResizeFormListener implements EventSubscriberInterface
// Then add all rows again in the correct order
foreach ($data as $name => $value) {
$form->add($this->factory->createNamed($this->type, $name, null, array_replace(array(
$form->add($this->factory->createNamed($name, $this->type, null, array_replace(array(
'property_path' => '['.$name.']',
), $this->options)));
}
}
public function preBind(DataEvent $event)
public function preBind(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
@ -123,7 +122,7 @@ class ResizeFormListener implements EventSubscriberInterface
if ($this->allowAdd) {
foreach ($data as $name => $value) {
if (!$form->has($name)) {
$form->add($this->factory->createNamed($this->type, $name, null, array_replace(array(
$form->add($this->factory->createNamed($name, $this->type, null, array_replace(array(
'property_path' => '['.$name.']',
), $this->options)));
}
@ -131,7 +130,7 @@ class ResizeFormListener implements EventSubscriberInterface
}
}
public function onBindNormData(FilterDataEvent $event)
public function onBind(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@ -22,7 +22,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
*/
class TrimListener implements EventSubscriberInterface
{
public function onBindClientData(FilterDataEvent $event)
public function preBind(FormEvent $event)
{
$data = $event->getData();
@ -33,6 +33,6 @@ class TrimListener implements EventSubscriberInterface
static public function getSubscribedEvents()
{
return array(FormEvents::BIND_CLIENT_DATA => 'onBindClientData');
return array(FormEvents::PRE_BIND => 'preBind');
}
}

View File

@ -12,23 +12,24 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class BirthdayType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'years' => range(date('Y') - 120, date('Y')),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'date';
}

View File

@ -12,55 +12,55 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CheckboxType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->appendClientTransformer(new BooleanToStringTransformer($options['value']))
->setAttribute('value', $options['value'])
->addViewTransformer(new BooleanToStringTransformer($options['value']))
;
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$view
->set('value', $form->getAttribute('value'))
->set('checked', null !== $form->getClientData())
;
$view->addVars(array(
'value' => $options['value'],
'checked' => null !== $form->getViewData(),
));
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$emptyData = function (FormInterface $form, $clientData) {
return $clientData;
};
return array(
'value' => '1',
'empty_data' => $emptyData,
'single_control' => true,
);
$resolver->setDefaults(array(
'value' => '1',
'empty_data' => $emptyData,
'compound' => false,
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -12,9 +12,9 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
@ -27,18 +27,15 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToBooleanArrayTr
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToBooleanArrayTransformer;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ChoiceType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['choice_list'] && !$options['choice_list'] instanceof ChoiceListInterface) {
throw new FormException('The "choice_list" must be an instance of "Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface".');
}
if (!$options['choice_list'] && !is_array($options['choices']) && !$options['choices'] instanceof \Traversable) {
throw new FormException('Either the option "choices" or "choice_list" must be set.');
}
@ -46,46 +43,23 @@ class ChoiceType extends AbstractType
if ($options['expanded']) {
$this->addSubForms($builder, $options['choice_list']->getPreferredViews(), $options);
$this->addSubForms($builder, $options['choice_list']->getRemainingViews(), $options);
}
// empty value
if ($options['multiple'] || $options['expanded']) {
// never use and empty value for these cases
$emptyValue = null;
} elseif (false === $options['empty_value']) {
// an empty value should be added but the user decided otherwise
$emptyValue = null;
} else {
// empty value has been set explicitly
$emptyValue = $options['empty_value'];
}
$builder
->setAttribute('choice_list', $options['choice_list'])
->setAttribute('preferred_choices', $options['preferred_choices'])
->setAttribute('multiple', $options['multiple'])
->setAttribute('expanded', $options['expanded'])
->setAttribute('required', $options['required'])
->setAttribute('empty_value', $emptyValue)
;
if ($options['expanded']) {
if ($options['multiple']) {
$builder
->appendClientTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']))
->addViewTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']))
->addEventSubscriber(new FixCheckboxInputListener($options['choice_list']), 10)
;
} else {
$builder
->appendClientTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list']))
->addViewTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list']))
->addEventSubscriber(new FixRadioInputListener($options['choice_list']), 10)
;
}
} else {
if ($options['multiple']) {
$builder->appendClientTransformer(new ChoicesToValuesTransformer($options['choice_list']));
$builder->addViewTransformer(new ChoicesToValuesTransformer($options['choice_list']));
} else {
$builder->appendClientTransformer(new ChoiceToValueTransformer($options['choice_list']));
$builder->addViewTransformer(new ChoiceToValueTransformer($options['choice_list']));
}
}
@ -99,43 +73,41 @@ class ChoiceType extends AbstractType
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$choiceList = $form->getAttribute('choice_list');
$view->addVars(array(
'multiple' => $options['multiple'],
'expanded' => $options['expanded'],
'preferred_choices' => $options['choice_list']->getPreferredViews(),
'choices' => $options['choice_list']->getRemainingViews(),
'separator' => '-------------------',
'empty_value' => $options['empty_value'],
));
$view
->set('multiple', $form->getAttribute('multiple'))
->set('expanded', $form->getAttribute('expanded'))
->set('preferred_choices', $choiceList->getPreferredViews())
->set('choices', $choiceList->getRemainingViews())
->set('separator', '-------------------')
->set('empty_value', $form->getAttribute('empty_value'))
;
if ($view->get('multiple') && !$view->get('expanded')) {
if ($options['multiple'] && !$options['expanded']) {
// Add "[]" to the name in case a select tag with multiple options is
// displayed. Otherwise only one of the selected options is sent in the
// POST request.
$view->set('full_name', $view->get('full_name').'[]');
$view->setVar('full_name', $view->getVar('full_name').'[]');
}
}
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
if ($view->get('expanded')) {
if ($options['expanded']) {
// Radio buttons should have the same name as the parent
$childName = $view->get('full_name');
$childName = $view->getVar('full_name');
// Checkboxes should append "[]" to allow multiple selection
if ($view->get('multiple')) {
if ($options['multiple']) {
$childName .= '[]';
}
foreach ($view->getChildren() as $childView) {
$childView->set('full_name', $childName);
foreach ($view as $childView) {
$childView->setVar('full_name', $childName);
}
}
}
@ -143,7 +115,7 @@ class ChoiceType extends AbstractType
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$choiceList = function (Options $options) {
return new SimpleChoiceList(
@ -165,11 +137,24 @@ class ChoiceType extends AbstractType
return $options['required'] ? null : '';
};
$singleControl = function (Options $options) {
return !$options['expanded'];
$emptyValueFilter = function (Options $options, $emptyValue) {
if ($options['multiple'] || $options['expanded']) {
// never use an empty value for these cases
return null;
} elseif (false === $emptyValue) {
// an empty value should be added but the user decided otherwise
return null;
}
// empty value has been set explicitly
return $emptyValue;
};
return array(
$compound = function (Options $options) {
return $options['expanded'];
};
$resolver->setDefaults(array(
'multiple' => false,
'expanded' => false,
'choice_list' => $choiceList,
@ -178,14 +163,22 @@ class ChoiceType extends AbstractType
'empty_data' => $emptyData,
'empty_value' => $emptyValue,
'error_bubbling' => false,
'single_control' => $singleControl,
);
'compound' => $compound,
));
$resolver->setFilters(array(
'empty_value' => $emptyValueFilter,
));
$resolver->setAllowedTypes(array(
'choice_list' => array('null', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'),
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}
@ -201,11 +194,11 @@ class ChoiceType extends AbstractType
/**
* Adds the sub fields for an expanded choice field.
*
* @param FormBuilder $builder The form builder.
* @param array $choiceViews The choice view objects.
* @param array $options The build options.
* @param FormBuilderInterface $builder The form builder.
* @param array $choiceViews The choice view objects.
* @param array $options The build options.
*/
private function addSubForms(FormBuilder $builder, array $choiceViews, array $options)
private function addSubForms(FormBuilderInterface $builder, array $choiceViews, array $options)
{
foreach ($choiceViews as $i => $choiceView) {
if (is_array($choiceView)) {

View File

@ -12,17 +12,18 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CollectionType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['allow_add'] && $options['prototype']) {
$prototype = $builder->create($options['prototype_name'], $options['type'], array_replace(array(
@ -39,51 +40,47 @@ class CollectionType extends AbstractType
$options['allow_delete']
);
$builder
->addEventSubscriber($resizeListener)
->setAttribute('allow_add', $options['allow_add'])
->setAttribute('allow_delete', $options['allow_delete'])
;
$builder->addEventSubscriber($resizeListener);
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$view
->set('allow_add', $form->getAttribute('allow_add'))
->set('allow_delete', $form->getAttribute('allow_delete'))
;
$view->addVars(array(
'allow_add' => $options['allow_add'],
'allow_delete' => $options['allow_delete'],
));
if ($form->hasAttribute('prototype')) {
$view->set('prototype', $form->getAttribute('prototype')->createView($view));
if ($form->getConfig()->hasAttribute('prototype')) {
$view->setVar('prototype', $form->getConfig()->getAttribute('prototype')->createView($view));
}
}
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
if ($form->hasAttribute('prototype') && $view->get('prototype')->get('multipart')) {
$view->set('multipart', true);
if ($form->getConfig()->hasAttribute('prototype') && $view->getVar('prototype')->getVar('multipart')) {
$view->setVar('multipart', true);
}
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'allow_add' => false,
'allow_delete' => false,
'prototype' => true,
'prototype_name' => '__name__',
'type' => 'text',
'options' => array(),
);
));
}
/**

View File

@ -13,23 +13,24 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Locale\Locale;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CountryType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'choices' => Locale::getDisplayCountries(\Locale::getDefault()),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'choice';
}

View File

@ -13,8 +13,8 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\ReversedTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
@ -22,13 +22,14 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransf
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class DateTimeType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$parts = array('year', 'month', 'day', 'hour', 'minute');
$timeParts = array('hour', 'minute');
@ -42,7 +43,7 @@ class DateTimeType extends AbstractType
}
if ('single_text' === $options['widget']) {
$builder->appendClientTransformer(new DateTimeToStringTransformer($options['data_timezone'], $options['user_timezone'], $format));
$builder->addViewTransformer(new DateTimeToStringTransformer($options['data_timezone'], $options['user_timezone'], $format));
} else {
// Only pass a subset of the options to children
$dateOptions = array_intersect_key($options, array_flip(array(
@ -85,7 +86,7 @@ class DateTimeType extends AbstractType
$timeOptions['input'] = 'array';
$builder
->appendClientTransformer(new DataTransformerChain(array(
->addViewTransformer(new DataTransformerChain(array(
new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts),
new ArrayToPartsTransformer(array(
'date' => array('year', 'month', 'day'),
@ -110,32 +111,30 @@ class DateTimeType extends AbstractType
new DateTimeToArrayTransformer($options['data_timezone'], $options['data_timezone'], $parts)
));
}
$builder->setAttribute('widget', $options['widget']);
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$view->set('widget', $form->getAttribute('widget'));
$view->setVar('widget', $options['widget']);
if ('single_text' === $form->getAttribute('widget')) {
$view->set('type', 'datetime');
if ('single_text' === $options['widget']) {
$view->setVar('type', 'datetime');
}
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$singleControl = function (Options $options) {
return $options['widget'] === 'single_text';
$compound = function (Options $options) {
return $options['widget'] !== 'single_text';
};
return array(
$resolver->setDefaults(array(
'input' => 'datetime',
'data_timezone' => null,
'user_timezone' => null,
@ -163,16 +162,10 @@ class DateTimeType extends AbstractType
// representation is not \DateTime, but an array, we need to unset
// this option.
'data_class' => null,
'single_control' => $singleControl,
);
}
'compound' => $compound,
));
/**
* {@inheritdoc}
*/
public function getAllowedOptionValues()
{
return array(
$resolver->setAllowedValues(array(
'input' => array(
'datetime',
'string',
@ -198,13 +191,13 @@ class DateTimeType extends AbstractType
'text',
'choice',
),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -13,27 +13,30 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Exception\CreationException;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\ReversedTransformer;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class DateType extends AbstractType
{
const DEFAULT_FORMAT = \IntlDateFormatter::MEDIUM;
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$format = $options['format'];
$pattern = null;
$allowedFormatOptionValues = array(
$allowedFormats = array(
\IntlDateFormatter::FULL,
\IntlDateFormatter::LONG,
\IntlDateFormatter::MEDIUM,
@ -41,11 +44,9 @@ class DateType extends AbstractType
);
// If $format is not in the allowed options, it's considered as the pattern of the formatter if it is a string
if (!in_array($format, $allowedFormatOptionValues, true)) {
if (!in_array($format, $allowedFormats, true)) {
if (is_string($format)) {
$defaultOptions = $this->getDefaultOptions();
$format = $defaultOptions['format'];
$format = self::DEFAULT_FORMAT;
$pattern = $options['format'];
} else {
throw new CreationException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom pattern');
@ -62,7 +63,7 @@ class DateType extends AbstractType
);
if ('single_text' === $options['widget']) {
$builder->appendClientTransformer(new DateTimeToLocalizedStringTransformer($options['data_timezone'], $options['user_timezone'], $format, \IntlDateFormatter::NONE, \IntlDateFormatter::GREGORIAN, $pattern));
$builder->addViewTransformer(new DateTimeToLocalizedStringTransformer($options['data_timezone'], $options['user_timezone'], $format, \IntlDateFormatter::NONE, \IntlDateFormatter::GREGORIAN, $pattern));
} else {
$yearOptions = $monthOptions = $dayOptions = array();
@ -109,7 +110,7 @@ class DateType extends AbstractType
->add('year', $options['widget'], $yearOptions)
->add('month', $options['widget'], $monthOptions)
->add('day', $options['widget'], $dayOptions)
->appendClientTransformer(new DateTimeToArrayTransformer(
->addViewTransformer(new DateTimeToArrayTransformer(
$options['data_timezone'], $options['user_timezone'], array('year', 'month', 'day')
))
;
@ -129,24 +130,22 @@ class DateType extends AbstractType
));
}
$builder
->setAttribute('formatter', $formatter)
->setAttribute('widget', $options['widget']);
$builder->setAttribute('formatter', $formatter);
}
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
$view->set('widget', $form->getAttribute('widget'));
$view->setVar('widget', $options['widget']);
if ('single_text' === $form->getAttribute('widget')) {
$view->set('type', 'date');
if ('single_text' === $options['widget']) {
$view->setVar('type', 'date');
}
if ($view->hasChildren()) {
$pattern = $form->getAttribute('formatter')->getPattern();
if (count($view) > 0) {
$pattern = $form->getConfig()->getAttribute('formatter')->getPattern();
// set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy)
// lookup various formats at http://userguide.icu-project.org/formatparse/datetime
@ -157,26 +156,26 @@ class DateType extends AbstractType
$pattern = '{{ year }}-{{ month }}-{{ day }}';
}
$view->set('date_pattern', $pattern);
$view->setVar('date_pattern', $pattern);
}
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$singleControl = function (Options $options) {
return $options['widget'] === 'single_text';
$compound = function (Options $options) {
return $options['widget'] !== 'single_text';
};
return array(
$resolver->setDefaults(array(
'years' => range(date('Y') - 5, date('Y') + 5),
'months' => range(1, 12),
'days' => range(1, 31),
'widget' => 'choice',
'input' => 'datetime',
'format' => \IntlDateFormatter::MEDIUM,
'format' => self::DEFAULT_FORMAT,
'data_timezone' => null,
'user_timezone' => null,
'empty_value' => null,
@ -189,16 +188,10 @@ class DateType extends AbstractType
// representation is not \DateTime, but an array, we need to unset
// this option.
'data_class' => null,
'single_control' => $singleControl,
);
}
'compound' => $compound,
));
/**
* {@inheritdoc}
*/
public function getAllowedOptionValues()
{
return array(
$resolver->setAllowedValues(array(
'input' => array(
'datetime',
'string',
@ -210,13 +203,13 @@ class DateType extends AbstractType
'text',
'choice',
),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -18,7 +18,7 @@ class EmailType extends AbstractType
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'text';
}

View File

@ -13,45 +13,46 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class FileType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$view->addVars(array(
'type' => 'file',
'value' => '',
));
}
/**
* {@inheritdoc}
*/
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
$view
->set('type', 'file')
->set('value', '')
->setVar('multipart', true)
;
}
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$view
->set('multipart', true)
;
$resolver->setDefaults(array(
'compound' => false,
));
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
{
return array(
'single_control' => true,
);
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -14,30 +14,24 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class FormType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (!is_array($options['attr'])) {
throw new FormException('The "attr" option must be an "array".');
}
if (!is_array($options['label_attr'])) {
throw new FormException('The "label_attr" option must be an "array".');
}
$builder
->setRequired($options['required'])
->setDisabled($options['disabled'])
@ -48,14 +42,6 @@ class FormType extends AbstractType
->setMapped($options['mapped'])
->setByReference($options['by_reference'])
->setVirtual($options['virtual'])
->setAttribute('read_only', $options['read_only'])
->setAttribute('max_length', $options['max_length'])
->setAttribute('pattern', $options['pattern'])
->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
->setAttribute('attr', $options['attr'])
->setAttribute('label_attr', $options['label_attr'])
->setAttribute('translation_domain', $options['translation_domain'])
->setAttribute('single_control', $options['single_control'])
->setData($options['data'])
->setDataMapper(new PropertyPathMapper())
;
@ -68,18 +54,18 @@ class FormType extends AbstractType
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$name = $form->getName();
$readOnly = $form->getAttribute('read_only');
$readOnly = $options['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);
if ('' !== ($parentFullName = $view->getParent()->getVar('full_name'))) {
$id = sprintf('%s_%s', $view->getParent()->getVar('id'), $name);
$fullName = sprintf('%s[%s]', $parentFullName, $name);
} else {
$id = $name;
@ -87,7 +73,7 @@ class FormType extends AbstractType
}
// Complex fields are read-only if themselves or their parent is.
$readOnly = $readOnly || $view->getParent()->get('read_only');
$readOnly = $readOnly || $view->getParent()->getVar('read_only');
} else {
$id = $name;
$fullName = $name;
@ -103,59 +89,55 @@ class FormType extends AbstractType
$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('valid', $form->isBound() ? $form->isValid() : true)
->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('label_attr', $form->getAttribute('label_attr'))
->set('single_control', $form->getAttribute('single_control'))
->set('types', $types)
->set('translation_domain', $form->getAttribute('translation_domain'))
;
$view->addVars(array(
'form' => $view,
'id' => $id,
'name' => $name,
'full_name' => $fullName,
'read_only' => $readOnly,
'errors' => $form->getErrors(),
'valid' => $form->isBound() ? $form->isValid() : true,
'value' => $form->getViewData(),
'disabled' => $form->isDisabled(),
'required' => $form->isRequired(),
'max_length' => $options['max_length'],
'pattern' => $options['pattern'],
'size' => null,
'label' => $options['label'] ?: $this->humanize($form->getName()),
'multipart' => false,
'attr' => $options['attr'],
'label_attr' => $options['label_attr'],
'compound' => $options['compound'],
'types' => $types,
'translation_domain' => $options['translation_domain'],
));
}
/**
* {@inheritdoc}
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
$multipart = false;
foreach ($view->getChildren() as $child) {
if ($child->get('multipart')) {
foreach ($view as $child) {
if ($child->getVar('multipart')) {
$multipart = true;
break;
}
}
$view->set('multipart', $multipart);
$view->setVar('multipart', $multipart);
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// Derive "data_class" option from passed "data" object
$dataClass = function (Options $options) {
if (is_object($options['data'])) {
return get_class($options['data']);
}
return null;
return is_object($options['data']) ? get_class($options['data']) : null;
};
// Derive "empty_data" closure from "data_class" option
@ -164,27 +146,19 @@ class FormType extends AbstractType
if (null !== $class) {
return function (FormInterface $form) use ($class) {
if ($form->isEmpty() && !$form->isRequired()) {
return null;
}
return new $class();
return $form->isEmpty() && !$form->isRequired() ? null : new $class();
};
}
return function (FormInterface $form) {
if ($form->hasChildren()) {
return array();
}
return '';
return count($form) > 0 ? array() : '';
};
};
// For any form that is not represented by a single HTML control,
// errors should bubble up by default
$errorBubbling = function (Options $options) {
return !$options['single_control'];
return $options['compound'];
};
// BC clause: former property_path=false now equals mapped=false
@ -192,7 +166,7 @@ class FormType extends AbstractType
return false !== $options['property_path'];
};
return array(
$resolver->setDefaults(array(
'data' => null,
'data_class' => $dataClass,
'empty_data' => $emptyData,
@ -210,9 +184,14 @@ class FormType extends AbstractType
'attr' => array(),
'label_attr' => array(),
'virtual' => false,
'single_control' => false,
'compound' => true,
'translation_domain' => 'messages',
);
));
$resolver->setAllowedTypes(array(
'attr' => 'array',
'label_attr' => 'array',
));
}
/**
@ -220,13 +199,13 @@ class FormType extends AbstractType
*/
public function createBuilder($name, FormFactoryInterface $factory, array $options)
{
return new FormBuilder($name, $options['data_class'], new EventDispatcher(), $factory);
return new FormBuilder($name, $options['data_class'], new EventDispatcher(), $factory, $options);
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return null;
}

View File

@ -12,27 +12,28 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class HiddenType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
// hidden fields cannot have a required attribute
'required' => false,
// Pass errors to the parent
'error_bubbling' => true,
'single_control' => true,
);
'compound' => false,
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -12,17 +12,18 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class IntegerType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->appendClientTransformer(
$builder->addViewTransformer(
new IntegerToLocalizedStringTransformer(
$options['precision'],
$options['grouping'],
@ -33,24 +34,18 @@ class IntegerType extends AbstractType
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
// default precision is locale specific (usually around 3)
'precision' => null,
'grouping' => false,
'precision' => null,
'grouping' => false,
// Integer cast rounds towards 0, so do the same when displaying fractions
'rounding_mode' => \NumberFormatter::ROUND_DOWN,
'single_control' => true,
);
}
'rounding_mode' => \NumberFormatter::ROUND_DOWN,
'compound' => false,
));
/**
* {@inheritdoc}
*/
public function getAllowedOptionValues()
{
return array(
$resolver->setAllowedValues(array(
'rounding_mode' => array(
\NumberFormatter::ROUND_FLOOR,
\NumberFormatter::ROUND_DOWN,
@ -60,13 +55,13 @@ class IntegerType extends AbstractType
\NumberFormatter::ROUND_UP,
\NumberFormatter::ROUND_CEILING,
),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -13,23 +13,24 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Locale\Locale;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class LanguageType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'choices' => Locale::getDisplayLanguages(\Locale::getDefault()),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'choice';
}

View File

@ -13,23 +13,24 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Locale\Locale;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class LocaleType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'choices' => Locale::getDisplayLocales(\Locale::getDefault()),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'choice';
}

View File

@ -13,9 +13,10 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MoneyType extends AbstractType
{
@ -24,45 +25,44 @@ class MoneyType extends AbstractType
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->appendClientTransformer(new MoneyToLocalizedStringTransformer(
->addViewTransformer(new MoneyToLocalizedStringTransformer(
$options['precision'],
$options['grouping'],
null,
$options['divisor']
))
->setAttribute('currency', $options['currency'])
;
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$view->set('money_pattern', self::getPattern($form->getAttribute('currency')));
$view->setVar('money_pattern', self::getPattern($options['currency']));
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
'precision' => 2,
'grouping' => false,
'divisor' => 1,
'currency' => 'EUR',
'single_control' => true,
);
$resolver->setDefaults(array(
'precision' => 2,
'grouping' => false,
'divisor' => 1,
'currency' => 'EUR',
'compound' => false,
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -12,17 +12,18 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class NumberType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->appendClientTransformer(new NumberToLocalizedStringTransformer(
$builder->addViewTransformer(new NumberToLocalizedStringTransformer(
$options['precision'],
$options['grouping'],
$options['rounding_mode']
@ -32,23 +33,17 @@ class NumberType extends AbstractType
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
// default precision is locale specific (usually around 3)
'precision' => null,
'grouping' => false,
'rounding_mode' => \NumberFormatter::ROUND_HALFUP,
'single_control' => true,
);
}
'precision' => null,
'grouping' => false,
'rounding_mode' => \NumberFormatter::ROUND_HALFUP,
'compound' => false,
));
/**
* {@inheritdoc}
*/
public function getAllowedOptionValues()
{
return array(
$resolver->setAllowedValues(array(
'rounding_mode' => array(
\NumberFormatter::ROUND_FLOOR,
\NumberFormatter::ROUND_DOWN,
@ -58,13 +53,13 @@ class NumberType extends AbstractType
\NumberFormatter::ROUND_UP,
\NumberFormatter::ROUND_CEILING,
),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -13,43 +13,36 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class PasswordType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$builder->setAttribute('always_empty', $options['always_empty']);
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
{
if ($form->getAttribute('always_empty') || !$form->isBound()) {
$view->set('value', '');
if ($options['always_empty'] || !$form->isBound()) {
$view->setVar('value', '');
}
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'always_empty' => true,
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'text';
}

View File

@ -12,48 +12,43 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class PercentType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->appendClientTransformer(new PercentToLocalizedStringTransformer($options['precision'], $options['type']));
$builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['precision'], $options['type']));
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
'precision' => 0,
'type' => 'fractional',
'single_control' => true,
);
}
$resolver->setDefaults(array(
'precision' => 0,
'type' => 'fractional',
'compound' => false,
));
/**
* {@inheritdoc}
*/
public function getAllowedOptionValues()
{
return array(
$resolver->setAllowedValues(array(
'type' => array(
'fractional',
'integer',
),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -18,7 +18,7 @@ class RadioType extends AbstractType
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'checkbox';
}

View File

@ -12,23 +12,24 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RepeatedType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Overwrite required option for child fields
$options['first_options']['required'] = $options['required'];
$options['second_options']['required'] = $options['required'];
$builder
->appendClientTransformer(new ValueToDuplicatesTransformer(array(
->addViewTransformer(new ValueToDuplicatesTransformer(array(
$options['first_name'],
$options['second_name'],
)))
@ -40,9 +41,9 @@ class RepeatedType extends AbstractType
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'type' => 'text',
'options' => array(),
'first_options' => array(),
@ -50,7 +51,7 @@ class RepeatedType extends AbstractType
'first_name' => 'first',
'second_name' => 'second',
'error_bubbling' => false,
);
));
}
/**

View File

@ -18,7 +18,7 @@ class SearchType extends AbstractType
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'text';
}

View File

@ -12,35 +12,36 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToStringTransformer;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TextType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->appendClientTransformer(new ValueToStringTransformer())
->addViewTransformer(new ValueToStringTransformer())
;
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
'single_control' => true,
);
$resolver->setDefaults(array(
'compound' => false,
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\FormInterface;
class TextareaType extends AbstractType
@ -20,15 +20,15 @@ class TextareaType extends AbstractType
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$view->set('pattern', null);
$view->setVar('pattern', null);
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'text';
}

View File

@ -13,20 +13,21 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\ReversedTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TimeType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$parts = array('hour', 'minute');
$format = 'H:i';
@ -36,17 +37,11 @@ class TimeType extends AbstractType
}
if ('single_text' === $options['widget']) {
$builder->appendClientTransformer(new DateTimeToStringTransformer($options['data_timezone'], $options['user_timezone'], $format));
$builder->addViewTransformer(new DateTimeToStringTransformer($options['data_timezone'], $options['user_timezone'], $format));
} else {
$hourOptions = $minuteOptions = $secondOptions = array();
if ('choice' === $options['widget']) {
if (is_array($options['empty_value'])) {
$options['empty_value'] = array_merge(array('hour' => null, 'minute' => null, 'second' => null), $options['empty_value']);
} else {
$options['empty_value'] = array('hour' => $options['empty_value'], 'minute' => $options['empty_value'], 'second' => $options['empty_value']);
}
$hours = $minutes = array();
foreach ($options['hours'] as $hour) {
@ -97,7 +92,7 @@ class TimeType extends AbstractType
$builder->add('second', $options['widget'], $secondOptions);
}
$builder->appendClientTransformer(new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts, 'text' === $options['widget']));
$builder->addViewTransformer(new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts, 'text' === $options['widget']));
}
if ('string' === $options['input']) {
@ -113,38 +108,48 @@ class TimeType extends AbstractType
new DateTimeToArrayTransformer($options['data_timezone'], $options['data_timezone'], $parts)
));
}
$builder
->setAttribute('widget', $options['widget'])
->setAttribute('with_seconds', $options['with_seconds'])
;
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
public function buildView(FormViewInterface $view, FormInterface $form, array $options)
{
$view
->set('widget', $form->getAttribute('widget'))
->set('with_seconds', $form->getAttribute('with_seconds'))
;
$view->addVars(array(
'widget' => $options['widget'],
'with_seconds' => $options['with_seconds'],
));
if ('single_text' === $form->getAttribute('widget')) {
$view->set('type', 'time');
if ('single_text' === $options['widget']) {
$view->setVar('type', 'time');
}
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$singleControl = function (Options $options) {
return $options['widget'] === 'single_text';
$compound = function (Options $options) {
return $options['widget'] !== 'single_text';
};
return array(
$emptyValueFilter = function (Options $options, $emptyValue) {
if (is_array($emptyValue)) {
return array_merge(
array('hour' => null, 'minute' => null, 'second' => null),
$emptyValue
);
}
return array(
'hour' => $emptyValue,
'minute' => $emptyValue,
'second' => $emptyValue
);
};
$resolver->setDefaults(array(
'hours' => range(0, 23),
'minutes' => range(0, 59),
'seconds' => range(0, 59),
@ -163,16 +168,14 @@ class TimeType extends AbstractType
// representation is not \DateTime, but an array, we need to unset
// this option.
'data_class' => null,
'single_control' => $singleControl,
);
}
'compound' => $compound,
));
/**
* {@inheritdoc}
*/
public function getAllowedOptionValues()
{
return array(
$resolver->setFilters(array(
'empty_value' => $emptyValueFilter,
));
$resolver->setAllowedValues(array(
'input' => array(
'datetime',
'string',
@ -184,13 +187,13 @@ class TimeType extends AbstractType
'text',
'choice',
),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'field';
}

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TimezoneType extends AbstractType
{
@ -24,17 +25,17 @@ class TimezoneType extends AbstractType
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'choices' => self::getTimezones(),
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'choice';
}

View File

@ -12,15 +12,16 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UrlType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber(new FixUrlProtocolListener($options['default_protocol']));
}
@ -28,17 +29,17 @@ class UrlType extends AbstractType
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'default_protocol' => 'http',
);
));
}
/**
* {@inheritdoc}
*/
public function getParent(array $options)
public function getParent()
{
return 'text';
}

View File

@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Extension\Csrf\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
/**
@ -47,7 +47,7 @@ class CsrfValidationListener implements EventSubscriberInterface
static public function getSubscribedEvents()
{
return array(
FormEvents::BIND_CLIENT_DATA => 'onBindClientData',
FormEvents::PRE_BIND => 'preBind',
);
}
@ -58,12 +58,12 @@ class CsrfValidationListener implements EventSubscriberInterface
$this->intention = $intention;
}
public function onBindClientData(FilterDataEvent $event)
public function preBind(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
if ($form->isRoot() && !$form->getAttribute('single_control')) {
if ($form->isRoot() && $form->getConfig()->getOption('compound')) {
if (!isset($data[$this->fieldName]) || !$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) {
$form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form'));
}

View File

@ -14,9 +14,10 @@ namespace Symfony\Component\Form\Extension\Csrf\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
@ -40,17 +41,13 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
* @param FormBuilder $builder The form builder
* @param array $options The options
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (!$options['csrf_protection']) {
return;
}
// use a low priority so higher priority listeners don't remove the field
$builder
->setAttribute('csrf_field_name', $options['csrf_field_name'])
->setAttribute('csrf_provider', $options['csrf_provider'])
->setAttribute('csrf_intention', $options['intention'])
->setAttribute('csrf_factory', $builder->getFormFactory())
->addEventSubscriber(new CsrfValidationListener($options['csrf_field_name'], $options['csrf_provider'], $options['intention']))
;
@ -62,33 +59,31 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
* @param FormView $view The form view
* @param FormInterface $form The form
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
{
if (!$view->hasParent() && !$form->getAttribute('single_control') && $form->hasAttribute('csrf_field_name')) {
$name = $form->getAttribute('csrf_field_name');
$csrfProvider = $form->getAttribute('csrf_provider');
$intention = $form->getAttribute('csrf_intention');
$factory = $form->getAttribute('csrf_factory');
$data = $csrfProvider->generateCsrfToken($intention);
$csrfForm = $factory->createNamed('hidden', $name, $data, array(
'property_path' => false,
if ($options['csrf_protection'] && !$view->hasParent() && $options['compound']) {
$factory = $form->getConfig()->getAttribute('csrf_factory');
$data = $options['csrf_provider']->generateCsrfToken($options['intention']);
$csrfForm = $factory->createNamed($options['csrf_field_name'], 'hidden', $data, array(
'mapped' => false,
));
$view->addChild($csrfForm->createView($view));
$view->add($csrfForm->createView($view));
}
}
/**
* {@inheritDoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array(
$resolver->setDefaults(array(
'csrf_protection' => $this->defaultEnabled,
'csrf_field_name' => $this->defaultFieldName,
'csrf_provider' => $this->defaultCsrfProvider,
'intention' => 'unknown',
);
));
}
/**

View File

@ -34,11 +34,7 @@ class FormValidator extends ConstraintValidator
*/
public function __construct(ServerParams $params = null)
{
if (null === $params) {
$params = new ServerParams();
}
$this->serverParams = $params;
$this->serverParams = $params ?: new ServerParams();
}
/**
@ -55,6 +51,7 @@ class FormValidator extends ConstraintValidator
$path = $this->context->getPropertyPath();
$graphWalker = $this->context->getGraphWalker();
$groups = $this->getValidationGroups($form);
$config = $form->getConfig();
if (!empty($path)) {
$path .= '.';
@ -72,22 +69,22 @@ class FormValidator extends ConstraintValidator
// Validate the data against the constraints defined
// in the form
$constraints = $form->getAttribute('constraints');
$constraints = $config->getOption('constraints');
foreach ($constraints as $constraint) {
foreach ($groups as $group) {
$graphWalker->walkConstraint($constraint, $form->getData(), $group, $path . 'data');
}
}
} else {
$clientDataAsString = is_scalar($form->getClientData())
? (string) $form->getClientData()
: gettype($form->getClientData());
$clientDataAsString = is_scalar($form->getViewData())
? (string) $form->getViewData()
: gettype($form->getViewData());
// Mark the form with an error if it is not synchronized
$this->context->addViolation(
$form->getAttribute('invalid_message'),
$config->getOption('invalid_message'),
array('{{ value }}' => $clientDataAsString),
$form->getClientData(),
$form->getViewData(),
null,
Form::ERR_INVALID
);
@ -96,7 +93,7 @@ class FormValidator extends ConstraintValidator
// Mark the form with an error if it contains extra fields
if (count($form->getExtraData()) > 0) {
$this->context->addViolation(
$form->getAttribute('extra_fields_message'),
$config->getOption('extra_fields_message'),
array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
$form->getExtraData()
);
@ -106,31 +103,14 @@ class FormValidator extends ConstraintValidator
$length = $this->serverParams->getContentLength();
if ($form->isRoot() && null !== $length) {
$max = strtoupper(trim($this->serverParams->getPostMaxSize()));
$max = $this->serverParams->getPostMaxSize();
if ('' !== $max) {
$maxLength = (int) $max;
switch (substr($max, -1)) {
// The 'G' modifier is available since PHP 5.1.0
case 'G':
$maxLength *= pow(1024, 3);
break;
case 'M':
$maxLength *= pow(1024, 2);
break;
case 'K':
$maxLength *= 1024;
break;
}
if ($length > $maxLength) {
$this->context->addViolation(
$form->getAttribute('post_max_size_message'),
array('{{ max }}' => $max),
$length
);
}
if (null !== $max && $length > $max) {
$this->context->addViolation(
$config->getOption('post_max_size_message'),
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()),
$length
);
}
}
}
@ -158,14 +138,10 @@ class FormValidator extends ConstraintValidator
// Non-root forms are validated if validation cascading
// is enabled in all ancestor forms
$parent = $form->getParent();
while (null !== $parent) {
if (!$parent->getAttribute('cascade_validation')) {
while (null !== ($form = $form->getParent())) {
if (!$form->getConfig()->getOption('cascade_validation')) {
return false;
}
$parent = $parent->getParent();
}
return true;
@ -180,33 +156,20 @@ class FormValidator extends ConstraintValidator
*/
private function getValidationGroups(FormInterface $form)
{
$groups = null;
if ($form->hasAttribute('validation_groups')) {
$groups = $form->getAttribute('validation_groups');
if (is_callable($groups)) {
$groups = (array) call_user_func($groups, $form);
}
}
$currentForm = $form;
while (!$groups && $currentForm->hasParent()) {
$currentForm = $currentForm->getParent();
if ($currentForm->hasAttribute('validation_groups')) {
$groups = $currentForm->getAttribute('validation_groups');
do {
$groups = $form->getConfig()->getOption('validation_groups');
if (null !== $groups) {
if (is_callable($groups)) {
$groups = (array) call_user_func($groups, $currentForm);
$groups = call_user_func($groups, $form);
}
return (array) $groups;
}
}
if (null === $groups) {
$groups = array('Default');
}
$form = $form->getParent();
} while (null !== $form);
return (array) $groups;
return array(Constraint::DEFAULT_GROUP);
}
}

View File

@ -12,18 +12,11 @@
namespace Symfony\Component\Form\Extension\Validator\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Validator\ExecutionContext;
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
/**
* @author Bernhard Schussek <bschussek@gmail.com>

View File

@ -12,11 +12,12 @@
namespace Symfony\Component\Form\Extension\Validator\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
@ -42,44 +43,40 @@ class FormTypeValidatorExtension extends AbstractTypeExtension
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilder $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (empty($options['validation_groups'])) {
$options['validation_groups'] = null;
} else {
$options['validation_groups'] = is_callable($options['validation_groups'])
? $options['validation_groups']
: (array) $options['validation_groups'];
}
// Objects, when casted to an array, are split into their properties
$constraints = is_object($options['constraints'])
? array($options['constraints'])
: (array) $options['constraints'];
$builder
->setAttribute('error_mapping', $options['error_mapping'])
->setAttribute('validation_groups', $options['validation_groups'])
->setAttribute('constraints', $constraints)
->setAttribute('cascade_validation', $options['cascade_validation'])
->setAttribute('invalid_message', $options['invalid_message'])
->setAttribute('extra_fields_message', $options['extra_fields_message'])
->setAttribute('post_max_size_message', $options['post_max_size_message'])
->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper))
;
$builder->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper));
}
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// BC clause
$constraints = function (Options $options) {
return $options['validation_constraint'];
};
return array(
// Make sure that validation groups end up as null, closure or array
$validationGroupsFilter = function (Options $options, $groups) {
if (empty($groups)) {
return null;
}
if (is_callable($groups)) {
return $groups;
}
return (array) $groups;
};
// Constraint should always be converted to an array
$constraintsFilter = function (Options $options, $constraints) {
return is_object($constraints) ? array($constraints) : (array) $constraints;
};
$resolver->setDefaults(array(
'error_mapping' => array(),
'validation_groups' => null,
// "validation_constraint" is deprecated. Use "constraints".
@ -89,7 +86,12 @@ class FormTypeValidatorExtension extends AbstractTypeExtension
'invalid_message' => 'This value is not valid.',
'extra_fields_message' => 'This form should not contain extra fields.',
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
);
));
$resolver->setFilters(array(
'validation_groups' => $validationGroupsFilter,
'constraints' => $constraintsFilter,
));
}
/**

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Extension\Validator\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
@ -22,16 +23,16 @@ class RepeatedTypeValidatorExtension extends AbstractTypeExtension
/**
* {@inheritdoc}
*/
public function getDefaultOptions()
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// Map errors to the first field
$errorMapping = function (Options $options) {
return array('.' => $options['first_name']);
};
return array(
$resolver->setDefaults(array(
'error_mapping' => $errorMapping,
);
));
}
/**

View File

@ -17,13 +17,40 @@ namespace Symfony\Component\Form\Extension\Validator\Util;
class ServerParams
{
/**
* Returns the "post_max_size" ini setting.
* Returns maximum post size in bytes.
*
* @return string The value of the ini setting.
* @return null|integer The maximum post size in bytes
*/
public function getPostMaxSize()
{
return ini_get('post_max_size');
$iniMax = $this->getNormalizedIniPostMaxSize();
if ('' === $iniMax) {
return null;
}
$max = (int) $iniMax;
switch (substr($iniMax, -1)) {
case 'G':
$max *= 1024;
case 'M':
$max *= 1024;
case 'K':
$max *= 1024;
}
return $max;
}
/**
* Returns the normalized "post_max_size" ini setting.
*
* @return string
*/
public function getNormalizedIniPostMaxSize()
{
return strtoupper(trim(ini_get('post_max_size')));
}
/**

View File

@ -109,12 +109,12 @@ class ViolationMapper implements ViolationMapperInterface
}
// Follow dot rules until we have the final target
$mapping = $this->scope->getAttribute('error_mapping');
$mapping = $this->scope->getConfig()->getAttribute('error_mapping');
while ($this->isValidScope() && isset($mapping['.'])) {
$dotRule = new MappingRule($this->scope, '.', $mapping['.']);
$this->scope = $dotRule->getTarget();
$mapping = $this->scope->getAttribute('error_mapping');
$mapping = $this->scope->getConfig()->getAttribute('error_mapping');
}
// Only add the error if the form is synchronized
@ -279,9 +279,9 @@ class ViolationMapper implements ViolationMapperInterface
{
$this->scope = $form;
$this->children = new \RecursiveIteratorIterator(
new VirtualFormAwareIterator($form->getChildren())
new VirtualFormAwareIterator($form->all())
);
foreach ($form->getAttribute('error_mapping') as $propertyPath => $targetPath) {
foreach ($form->getConfig()->getAttribute('error_mapping') as $propertyPath => $targetPath) {
// Dot rules are considered at the very end
if ('.' !== $propertyPath) {
$this->rules[] = new MappingRule($form, $propertyPath, $targetPath);

View File

@ -11,8 +11,6 @@
namespace Symfony\Component\Form;
use Symfony\Component\Form\Event\DataEvent;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Exception\AlreadyBoundException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
@ -89,10 +87,10 @@ class Form implements \IteratorAggregate, FormInterface
private $bound = false;
/**
* The form data in application format
* The form data in model format
* @var mixed
*/
private $appData;
private $modelData;
/**
* The form data in normalized format
@ -101,10 +99,10 @@ class Form implements \IteratorAggregate, FormInterface
private $normData;
/**
* The form data in client format
* The form data in view format
* @var mixed
*/
private $clientData;
private $viewData;
/**
* The bound values that don't belong to any children
@ -113,7 +111,7 @@ class Form implements \IteratorAggregate, FormInterface
private $extraData = array();
/**
* Whether the data in application, normalized and client format is
* Whether the data in model, normalized and view format is
* synchronized. Data may not be synchronized if transformation errors
* occur.
* @var Boolean
@ -288,6 +286,9 @@ class Form implements \IteratorAggregate, FormInterface
* @param string $name The name of the attribute.
*
* @return Boolean Whether the attribute exists.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::hasAttribute()} instead.
*/
public function hasAttribute($name)
{
@ -300,6 +301,9 @@ class Form implements \IteratorAggregate, FormInterface
* @param string $name The name of the attribute
*
* @return mixed The attribute value.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getAttribute()} instead.
*/
public function getAttribute($name)
{
@ -309,75 +313,74 @@ class Form implements \IteratorAggregate, FormInterface
/**
* Updates the form with default data.
*
* @param array $appData The data formatted as expected for the underlying object
* @param array $modelData The data formatted as expected for the underlying object
*
* @return Form The current form
*/
public function setData($appData)
public function setData($modelData)
{
if ($this->bound) {
throw new AlreadyBoundException('You cannot change the data of a bound form');
}
if (is_object($appData) && !$this->config->getByReference()) {
$appData = clone $appData;
if (is_object($modelData) && !$this->config->getByReference()) {
$modelData = clone $modelData;
}
$event = new DataEvent($this, $appData);
$this->config->getEventDispatcher()->dispatch(FormEvents::PRE_SET_DATA, $event);
// Hook to change content of the data
$event = new FilterDataEvent($this, $appData);
$event = new FormEvent($this, $modelData);
$this->config->getEventDispatcher()->dispatch(FormEvents::PRE_SET_DATA, $event);
// BC until 2.3
$this->config->getEventDispatcher()->dispatch(FormEvents::SET_DATA, $event);
$appData = $event->getData();
$modelData = $event->getData();
// Treat data as strings unless a value transformer exists
if (!$this->config->getClientTransformers() && !$this->config->getNormTransformers() && is_scalar($appData)) {
$appData = (string) $appData;
if (!$this->config->getViewTransformers() && !$this->config->getModelTransformers() && is_scalar($modelData)) {
$modelData = (string) $modelData;
}
// Synchronize representations - must not change the content!
$normData = $this->appToNorm($appData);
$clientData = $this->normToClient($normData);
$normData = $this->modelToNorm($modelData);
$viewData = $this->normToView($normData);
// Validate if client data matches data class (unless empty)
if (!empty($clientData)) {
// Validate if view data matches data class (unless empty)
if (!empty($viewData)) {
$dataClass = $this->config->getDataClass();
if (null === $dataClass && is_object($clientData) && !$clientData instanceof \ArrayAccess) {
if (null === $dataClass && is_object($viewData) && !$viewData instanceof \ArrayAccess) {
$expectedType = 'scalar, array or an instance of \ArrayAccess';
throw new FormException(
'The form\'s client data is expected to be of type ' . $expectedType . ', ' .
'but is an instance of class ' . get_class($clientData) . '. You ' .
'The form\'s view data is expected to be of type ' . $expectedType . ', ' .
'but is an instance of class ' . get_class($viewData) . '. You ' .
'can avoid this error by setting the "data_class" option to ' .
'"' . get_class($clientData) . '" or by adding a client transformer ' .
'that transforms ' . get_class($clientData) . ' to ' . $expectedType . '.'
'"' . get_class($viewData) . '" or by adding a view transformer ' .
'that transforms ' . get_class($viewData) . ' to ' . $expectedType . '.'
);
}
if (null !== $dataClass && !$clientData instanceof $dataClass) {
if (null !== $dataClass && !$viewData instanceof $dataClass) {
throw new FormException(
'The form\'s client data is expected to be an instance of class ' .
$dataClass . ', but has the type ' . gettype($clientData) . '. You ' .
'The form\'s view data is expected to be an instance of class ' .
$dataClass . ', but has the type ' . gettype($viewData) . '. You ' .
'can avoid this error by setting the "data_class" option to ' .
'null or by adding a client transformer that transforms ' .
gettype($clientData) . ' to ' . $dataClass . '.'
'null or by adding a view transformer that transforms ' .
gettype($viewData) . ' to ' . $dataClass . '.'
);
}
}
$this->appData = $appData;
$this->modelData = $modelData;
$this->normData = $normData;
$this->clientData = $clientData;
$this->viewData = $viewData;
$this->synchronized = true;
if (count($this->children) > 0 && $this->config->getDataMapper()) {
// Update child forms from the data
$this->config->getDataMapper()->mapDataToForms($clientData, $this->children);
$this->config->getDataMapper()->mapDataToForms($viewData, $this->children);
}
$event = new DataEvent($this, $appData);
$event = new FormEvent($this, $modelData);
$this->config->getEventDispatcher()->dispatch(FormEvents::POST_SET_DATA, $event);
return $this;
@ -390,7 +393,7 @@ class Form implements \IteratorAggregate, FormInterface
*/
public function getData()
{
return $this->appData;
return $this->modelData;
}
/**
@ -398,9 +401,22 @@ class Form implements \IteratorAggregate, FormInterface
*
* @return string
*/
public function getViewData()
{
return $this->viewData;
}
/**
* Alias of {@link getViewData()}.
*
* @return string
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getViewData()} instead.
*/
public function getClientData()
{
return $this->clientData;
return $this->getViewData();
}
/**
@ -416,13 +432,13 @@ class Form implements \IteratorAggregate, FormInterface
/**
* Binds data to the form, transforms and validates it.
*
* @param string|array $clientData The data
* @param string|array $submittedData The data
*
* @return Form The current form
*
* @throws UnexpectedTypeException
*/
public function bind($clientData)
public function bind($submittedData)
{
if ($this->bound) {
throw new AlreadyBoundException('A form can only be bound once');
@ -438,43 +454,45 @@ class Form implements \IteratorAggregate, FormInterface
// whether an empty value has been submitted or whether no value has
// been submitted at all. This is important for processing checkboxes
// and radio buttons with empty values.
if (is_scalar($clientData)) {
$clientData = (string) $clientData;
if (is_scalar($submittedData)) {
$submittedData = (string) $submittedData;
}
// Initialize errors in the very beginning so that we don't lose any
// errors added during listeners
$this->errors = array();
$event = new DataEvent($this, $clientData);
$this->config->getEventDispatcher()->dispatch(FormEvents::PRE_BIND, $event);
$appData = null;
$modelData = null;
$normData = null;
$extraData = array();
$synchronized = false;
// Hook to change content of the data bound by the browser
$event = new FilterDataEvent($this, $clientData);
$event = new FormEvent($this, $submittedData);
$this->config->getEventDispatcher()->dispatch(FormEvents::PRE_BIND, $event);
// BC until 2.3
$this->config->getEventDispatcher()->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
$clientData = $event->getData();
$submittedData = $event->getData();
// Build the data in the view format
$viewData = $submittedData;
if (count($this->children) > 0) {
if (null === $clientData || '' === $clientData) {
$clientData = array();
if (null === $viewData || '' === $viewData) {
$viewData = array();
}
if (!is_array($clientData)) {
throw new UnexpectedTypeException($clientData, 'array');
if (!is_array($viewData)) {
throw new UnexpectedTypeException($viewData, 'array');
}
foreach ($this->children as $name => $child) {
if (!isset($clientData[$name])) {
$clientData[$name] = null;
if (!isset($viewData[$name])) {
$viewData[$name] = null;
}
}
foreach ($clientData as $name => $value) {
foreach ($viewData as $name => $value) {
if ($this->has($name)) {
$this->children[$name]->bind($value);
} else {
@ -482,31 +500,32 @@ class Form implements \IteratorAggregate, FormInterface
}
}
// If we have a data mapper, use old client data and merge
// If we have a data mapper, use old view data and merge
// data from the children into it later
if ($this->config->getDataMapper()) {
$clientData = $this->getClientData();
$viewData = $this->getViewData();
}
}
if (null === $clientData || '' === $clientData) {
if (null === $viewData || '' === $viewData) {
$emptyData = $this->config->getEmptyData();
if ($emptyData instanceof \Closure) {
$emptyData = $emptyData($this, $clientData);
/* @var \Closure $emptyData */
$emptyData = $emptyData($this, $viewData);
}
$clientData = $emptyData;
$viewData = $emptyData;
}
// Merge form data from children into existing client data
if (count($this->children) > 0 && $this->config->getDataMapper() && null !== $clientData) {
$this->config->getDataMapper()->mapFormsToData($this->children, $clientData);
// Merge form data from children into existing view data
if (count($this->children) > 0 && $this->config->getDataMapper() && null !== $viewData) {
$this->config->getDataMapper()->mapFormsToData($this->children, $viewData);
}
try {
// Normalize data to unified representation
$normData = $this->clientToNorm($clientData);
$normData = $this->viewToNorm($viewData);
$synchronized = true;
} catch (TransformationFailedException $e) {
}
@ -514,23 +533,26 @@ class Form implements \IteratorAggregate, FormInterface
if ($synchronized) {
// Hook to change content of the data into the normalized
// representation
$event = new FilterDataEvent($this, $normData);
$event = new FormEvent($this, $normData);
$this->config->getEventDispatcher()->dispatch(FormEvents::BIND, $event);
// BC until 2.3
$this->config->getEventDispatcher()->dispatch(FormEvents::BIND_NORM_DATA, $event);
$normData = $event->getData();
// Synchronize representations - must not change the content!
$appData = $this->normToApp($normData);
$clientData = $this->normToClient($normData);
$modelData = $this->normToModel($normData);
$viewData = $this->normToView($normData);
}
$this->bound = true;
$this->appData = $appData;
$this->modelData = $modelData;
$this->normData = $normData;
$this->clientData = $clientData;
$this->viewData = $viewData;
$this->extraData = $extraData;
$this->synchronized = $synchronized;
$event = new DataEvent($this, $clientData);
$event = new FormEvent($this, $viewData);
$this->config->getEventDispatcher()->dispatch(FormEvents::POST_BIND, $event);
foreach ($this->config->getValidators() as $validator) {
@ -566,7 +588,7 @@ class Form implements \IteratorAggregate, FormInterface
// Form bound without name
$params = $request->request->all();
$files = $request->files->all();
} elseif ($this->hasChildren()) {
} elseif (count($this->children) > 0) {
// Form bound with name and children
$params = $request->request->get($name, array());
$files = $request->files->get($name, array());
@ -667,7 +689,7 @@ class Form implements \IteratorAggregate, FormInterface
}
}
return array() === $this->appData || null === $this->appData || '' === $this->appData;
return array() === $this->modelData || null === $this->modelData || '' === $this->modelData;
}
/**
@ -735,14 +757,12 @@ class Form implements \IteratorAggregate, FormInterface
$errors .= str_repeat(' ', $level).'ERROR: '.$error->getMessage()."\n";
}
if ($this->hasChildren()) {
foreach ($this->children as $key => $child) {
$errors .= str_repeat(' ', $level).$key.":\n";
if ($err = $child->getErrorsAsString($level + 4)) {
$errors .= $err;
} else {
$errors .= str_repeat(' ', $level + 4)."No errors\n";
}
foreach ($this->children as $key => $child) {
$errors .= str_repeat(' ', $level).$key.":\n";
if ($err = $child->getErrorsAsString($level + 4)) {
$errors .= $err;
} else {
$errors .= str_repeat(' ', $level + 4)."No errors\n";
}
}
@ -755,11 +775,11 @@ class Form implements \IteratorAggregate, FormInterface
* @return array An array of DataTransformerInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getNormTransformers()} instead.
* {@link getConfig()} and {@link FormConfigInterface::getModelTransformers()} instead.
*/
public function getNormTransformers()
{
return $this->config->getNormTransformers();
return $this->config->getModelTransformers();
}
/**
@ -768,27 +788,41 @@ class Form implements \IteratorAggregate, FormInterface
* @return array An array of DataTransformerInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getClientTransformers()} instead.
* {@link getConfig()} and {@link FormConfigInterface::getViewTransformers()} instead.
*/
public function getClientTransformers()
{
return $this->config->getClientTransformers();
return $this->config->getViewTransformers();
}
/**
* {@inheritdoc}
*/
public function all()
{
return $this->children;
}
/**
* Returns all children in this group.
*
* @return array
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link all()} instead.
*/
public function getChildren()
{
return $this->children;
return $this->all();
}
/**
* Returns whether the form has children.
*
* @return Boolean
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link count()} instead.
*/
public function hasChildren()
{
@ -809,7 +843,7 @@ class Form implements \IteratorAggregate, FormInterface
$child->setParent($this);
if ($this->config->getDataMapper()) {
$this->config->getDataMapper()->mapDataToForms($this->getClientData(), array($child));
$this->config->getDataMapper()->mapDataToForms($this->getViewData(), array($child));
}
return $this;
@ -919,13 +953,9 @@ class Form implements \IteratorAggregate, FormInterface
}
/**
* Creates a view.
*
* @param FormView $parent The parent view
*
* @return FormView The view
* {@inheritdoc}
*/
public function createView(FormView $parent = null)
public function createView(FormViewInterface $parent = null)
{
if (null === $parent && $this->parent) {
$parent = $this->parent->createView();
@ -936,24 +966,25 @@ class Form implements \IteratorAggregate, FormInterface
$view->setParent($parent);
$types = (array) $this->config->getTypes();
$options = $this->config->getOptions();
foreach ($types as $type) {
$type->buildView($view, $this);
$type->buildView($view, $this, $options);
foreach ($type->getExtensions() as $typeExtension) {
$typeExtension->buildView($view, $this);
$typeExtension->buildView($view, $this, $options);
}
}
foreach ($this->children as $child) {
$view->addChild($child->createView($view));
$view->add($child->createView($view));
}
foreach ($types as $type) {
$type->buildViewBottomUp($view, $this);
$type->finishView($view, $this, $options);
foreach ($type->getExtensions() as $typeExtension) {
$typeExtension->buildViewBottomUp($view, $this);
$typeExtension->finishView($view, $this, $options);
}
}
@ -967,9 +998,9 @@ class Form implements \IteratorAggregate, FormInterface
*
* @return string
*/
private function appToNorm($value)
private function modelToNorm($value)
{
foreach ($this->config->getNormTransformers() as $transformer) {
foreach ($this->config->getModelTransformers() as $transformer) {
$value = $transformer->transform($value);
}
@ -983,9 +1014,9 @@ class Form implements \IteratorAggregate, FormInterface
*
* @return mixed
*/
private function normToApp($value)
private function normToModel($value)
{
$transformers = $this->config->getNormTransformers();
$transformers = $this->config->getModelTransformers();
for ($i = count($transformers) - 1; $i >= 0; --$i) {
$value = $transformers[$i]->reverseTransform($value);
@ -1001,15 +1032,15 @@ class Form implements \IteratorAggregate, FormInterface
*
* @return string
*/
private function normToClient($value)
private function normToView($value)
{
if (!$this->config->getClientTransformers()) {
if (!$this->config->getViewTransformers()) {
// Scalar values should always be converted to strings to
// facilitate differentiation between empty ("") and zero (0).
return null === $value || is_scalar($value) ? (string) $value : $value;
}
foreach ($this->config->getClientTransformers() as $transformer) {
foreach ($this->config->getViewTransformers() as $transformer) {
$value = $transformer->transform($value);
}
@ -1023,9 +1054,9 @@ class Form implements \IteratorAggregate, FormInterface
*
* @return mixed
*/
private function clientToNorm($value)
private function viewToNorm($value)
{
$transformers = $this->config->getClientTransformers();
$transformers = $this->config->getViewTransformers();
if (!$transformers) {
return '' === $value ? null : $value;

View File

@ -22,7 +22,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormBuilder extends FormConfig
class FormBuilder extends FormConfig implements \IteratorAggregate, FormBuilderInterface
{
/**
* The form factory.
@ -61,17 +61,15 @@ class FormBuilder extends FormConfig
* @param EventDispatcherInterface $dispatcher
* @param FormFactoryInterface $factory
*/
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory)
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = array())
{
parent::__construct($name, $dataClass, $dispatcher);
parent::__construct($name, $dataClass, $dispatcher, $options);
$this->factory = $factory;
}
/**
* Returns the associated form factory.
*
* @return FormFactoryInterface The factory
* {@inheritdoc}
*/
public function getFormFactory()
{
@ -79,17 +77,7 @@ class FormBuilder extends FormConfig
}
/**
* Adds a new field to this group. A field must have a unique name within
* the group. Otherwise the existing field is overwritten.
*
* If you add a nested group, this group should also be represented in the
* object hierarchy.
*
* @param string|FormBuilder $child
* @param string|FormTypeInterface $type
* @param array $options
*
* @return FormBuilder The builder object.
* {@inheritdoc}
*/
public function add($child, $type = null, array $options = array())
{
@ -124,13 +112,7 @@ class FormBuilder extends FormConfig
}
/**
* Creates a form builder.
*
* @param string $name The name of the form or the name of the property
* @param string|FormTypeInterface $type The type of the form or null if name is a property
* @param array $options The options
*
* @return FormBuilder The created builder.
* {@inheritdoc}
*/
public function create($name, $type = null, array $options = array())
{
@ -139,20 +121,14 @@ class FormBuilder extends FormConfig
}
if (null !== $type) {
return $this->getFormFactory()->createNamedBuilder($type, $name, null, $options, $this);
return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options, $this);
}
return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options, $this);
}
/**
* Returns a child by name.
*
* @param string $name The name of the child
*
* @return FormBuilder The builder for the child
*
* @throws FormException if the given child does not exist
* {@inheritdoc}
*/
public function get($name)
{
@ -168,11 +144,7 @@ class FormBuilder extends FormConfig
}
/**
* Removes the field with the given name.
*
* @param string $name
*
* @return FormBuilder The builder object.
* {@inheritdoc}
*/
public function remove($name)
{
@ -189,11 +161,7 @@ class FormBuilder extends FormConfig
}
/**
* Returns whether a field with the given name exists.
*
* @param string $name
*
* @return Boolean
* {@inheritdoc}
*/
public function has($name)
{
@ -209,9 +177,7 @@ class FormBuilder extends FormConfig
}
/**
* Returns the children.
*
* @return array
* {@inheritdoc}
*/
public function all()
{
@ -221,9 +187,15 @@ class FormBuilder extends FormConfig
}
/**
* Creates the form.
*
* @return Form The form
* {@inheritdoc}
*/
public function count()
{
return count($this->children);
}
/**
* {@inheritdoc}
*/
public function getForm()
{
@ -244,9 +216,7 @@ class FormBuilder extends FormConfig
}
/**
* Returns the parent builder.
*
* @return FormBuilder The parent builder
* {@inheritdoc}
*/
public function getParent()
{
@ -254,19 +224,23 @@ class FormBuilder extends FormConfig
}
/**
* Sets the parent builder.
*
* @param FormBuilder $parent The parent builder
*
* @return FormBuilder The builder object.
* {@inheritdoc}
*/
public function setParent(FormBuilder $parent = null)
public function setParent(FormBuilderInterface $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* {@inheritdoc}
*/
public function hasParent()
{
return null !== $this->parent;
}
/**
* Converts an unresolved child into a {@link FormBuilder} instance.
*
@ -295,4 +269,12 @@ class FormBuilder extends FormConfig
$this->unresolvedChildren = array();
}
/**
* {@inheritdoc}
*/
public function getIterator()
{
return new \ArrayIterator($this->children);
}
}

View File

@ -0,0 +1,116 @@
<?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;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface FormBuilderInterface extends FormConfigEditorInterface, \Traversable, \Countable
{
/**
* Adds a new field to this group. A field must have a unique name within
* the group. Otherwise the existing field is overwritten.
*
* If you add a nested group, this group should also be represented in the
* object hierarchy.
*
* @param string|FormBuilderInterface $child
* @param string|FormTypeInterface $type
* @param array $options
*
* @return FormBuilderInterface The builder object.
*/
function add($child, $type = null, array $options = array());
/**
* Creates a form builder.
*
* @param string $name The name of the form or the name of the property
* @param string|FormTypeInterface $type The type of the form or null if name is a property
* @param array $options The options
*
* @return FormBuilderInterface The created builder.
*/
function create($name, $type = null, array $options = array());
/**
* Returns a child by name.
*
* @param string $name The name of the child
*
* @return FormBuilderInterface The builder for the child
*
* @throws Exception\FormException if the given child does not exist
*/
function get($name);
/**
* Removes the field with the given name.
*
* @param string $name
*
* @return FormBuilderInterface The builder object.
*/
function remove($name);
/**
* Returns whether a field with the given name exists.
*
* @param string $name
*
* @return Boolean
*/
function has($name);
/**
* Returns the children.
*
* @return array
*/
function all();
/**
* Returns the associated form factory.
*
* @return FormFactoryInterface The factory
*/
function getFormFactory();
/**
* Creates the form.
*
* @return Form The form
*/
function getForm();
/**
* Sets the parent builder.
*
* @param FormBuilderInterface $parent The parent builder
*
* @return FormBuilderInterface The builder object.
*/
function setParent(FormBuilderInterface $parent = null);
/**
* Returns the parent builder.
*
* @return FormBuilderInterface The parent builder
*/
function getParent();
/**
* Returns whether the builder has a parent.
*
* @return Boolean
*/
function hasParent();
}

View File

@ -21,7 +21,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormConfig implements FormConfigInterface
class FormConfig implements FormConfigEditorInterface
{
/**
* @var EventDispatcherInterface
@ -61,12 +61,12 @@ class FormConfig implements FormConfigInterface
/**
* @var array
*/
private $clientTransformers = array();
private $viewTransformers = array();
/**
* @var array
*/
private $normTransformers = array();
private $modelTransformers = array();
/**
* @var DataMapperInterface
@ -113,6 +113,11 @@ class FormConfig implements FormConfigInterface
*/
private $dataClass;
/**
* @var array
*/
private $options;
/**
* Creates an empty form configuration.
*
@ -124,7 +129,7 @@ class FormConfig implements FormConfigInterface
* @throws \InvalidArgumentException If the data class is not a valid class or if
* the name contains invalid characters.
*/
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher)
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, array $options = array())
{
$name = (string) $name;
@ -137,18 +142,11 @@ class FormConfig implements FormConfigInterface
$this->name = $name;
$this->dataClass = $dataClass;
$this->dispatcher = $dispatcher;
$this->options = $options;
}
/**
* Adds an event listener to an event on this form.
*
* @param string $eventName The name of the event to listen to.
* @param callable $listener The listener to execute.
* @param integer $priority The priority of the listener. Listeners
* with a higher priority are called before
* listeners with a lower priority.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function addEventListener($eventName, $listener, $priority = 0)
{
@ -158,11 +156,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Adds an event subscriber for events on this form.
*
* @param EventSubscriberInterface $subscriber The subscriber to attach.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function addEventSubscriber(EventSubscriberInterface $subscriber)
{
@ -172,13 +166,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Adds a validator to the form.
*
* @param FormValidatorInterface $validator The validator.
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* {@inheritdoc}
*/
public function addValidator(FormValidatorInterface $validator)
{
@ -188,41 +176,85 @@ class FormConfig implements FormConfigInterface
}
/**
* Appends a transformer to the client transformer chain
*
* @param DataTransformerInterface $clientTransformer
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function appendClientTransformer(DataTransformerInterface $clientTransformer)
public function addViewTransformer(DataTransformerInterface $viewTransformer)
{
$this->clientTransformers[] = $clientTransformer;
$this->viewTransformers[] = $viewTransformer;
return $this;
}
/**
* {@inheritdoc}
*/
public function resetViewTransformers()
{
$this->viewTransformers = array();
return $this;
}
/**
* Alias of {@link addViewTransformer()}.
*
* @param DataTransformerInterface $viewTransformer
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link addViewTransformer()} instead.
*/
public function appendClientTransformer(DataTransformerInterface $viewTransformer)
{
return $this->addViewTransformer($viewTransformer);
}
/**
* Prepends a transformer to the client transformer chain.
*
* @param DataTransformerInterface $clientTransformer
* @param DataTransformerInterface $viewTransformer
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function prependClientTransformer(DataTransformerInterface $clientTransformer)
public function prependClientTransformer(DataTransformerInterface $viewTransformer)
{
array_unshift($this->clientTransformers, $clientTransformer);
array_unshift($this->viewTransformers, $viewTransformer);
return $this;
}
/**
* Clears the client transformers.
* Alias of {@link resetViewTransformers()}.
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link resetViewTransformers()} instead.
*/
public function resetClientTransformers()
{
$this->clientTransformers = array();
return $this->resetViewTransformers();
}
/**
* {@inheritdoc}
*/
public function addModelTransformer(DataTransformerInterface $modelTransformer)
{
array_unshift($this->modelTransformers, $modelTransformer);
return $this;
}
/**
* {@inheritdoc}
*/
public function resetModelTransformers()
{
$this->modelTransformers = array();
return $this;
}
@ -230,41 +262,45 @@ class FormConfig implements FormConfigInterface
/**
* Appends a transformer to the normalization transformer chain
*
* @param DataTransformerInterface $normTransformer
* @param DataTransformerInterface $modelTransformer
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function appendNormTransformer(DataTransformerInterface $normTransformer)
public function appendNormTransformer(DataTransformerInterface $modelTransformer)
{
$this->normTransformers[] = $normTransformer;
$this->modelTransformers[] = $modelTransformer;
return $this;
}
/**
* Prepends a transformer to the normalization transformer chain
* Alias of {@link addModelTransformer()}.
*
* @param DataTransformerInterface $normTransformer
* @param DataTransformerInterface $modelTransformer
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link addModelTransformer()} instead.
*/
public function prependNormTransformer(DataTransformerInterface $normTransformer)
public function prependNormTransformer(DataTransformerInterface $modelTransformer)
{
array_unshift($this->normTransformers, $normTransformer);
return $this;
return $this->addModelTransformer($modelTransformer);
}
/**
* Clears the normalization transformers.
* Alias of {@link resetModelTransformers()}.
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link resetModelTransformers()} instead.
*/
public function resetNormTransformers()
{
$this->normTransformers = array();
return $this;
return $this->resetModelTransformers();
}
/**
@ -326,23 +362,47 @@ class FormConfig implements FormConfigInterface
/**
* {@inheritdoc}
*/
public function getViewTransformers()
{
return $this->viewTransformers;
}
/**
* Alias of {@link getViewTransformers()}.
*
* @return array The view transformers.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getViewTransformers()} instead.
*/
public function getClientTransformers()
{
return $this->clientTransformers;
return $this->getViewTransformers();
}
/**
* {@inheritdoc}
*/
public function getNormTransformers()
public function getModelTransformers()
{
return $this->normTransformers;
return $this->modelTransformers;
}
/**
* Returns the data mapper of the form.
* Alias of {@link getModelTransformers()}.
*
* @return DataMapperInterface The data mapper.
* @return array The model transformers.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getModelTransformers()} instead.
*/
public function getNormTransformers()
{
return $this->getModelTransformers();
}
/**
* {@inheritdoc}
*/
public function getDataMapper()
{
@ -408,9 +468,9 @@ class FormConfig implements FormConfigInterface
/**
* {@inheritdoc}
*/
public function getAttribute($name)
public function getAttribute($name, $default = null)
{
return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
}
/**
@ -430,12 +490,31 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets the value for an attribute.
*
* @param string $name The name of the attribute
* @param string $value The value of the attribute
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function getOptions()
{
return $this->options;
}
/**
* {@inheritdoc}
*/
public function hasOption($name)
{
return isset($this->options[$name]);
}
/**
* {@inheritdoc}
*/
public function getOption($name, $default = null)
{
return isset($this->options[$name]) ? $this->options[$name] : $default;
}
/**
* {@inheritdoc}
*/
public function setAttribute($name, $value)
{
@ -445,11 +524,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets the attributes.
*
* @param array $attributes The attributes.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setAttributes(array $attributes)
{
@ -459,11 +534,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets the data mapper used by the form.
*
* @param DataMapperInterface $dataMapper
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setDataMapper(DataMapperInterface $dataMapper = null)
{
@ -473,11 +544,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Set whether the form is disabled.
*
* @param Boolean $disabled Whether the form is disabled
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setDisabled($disabled)
{
@ -487,11 +554,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets the data used for the client data when no value is bound.
*
* @param mixed $emptyData The empty data.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setEmptyData($emptyData)
{
@ -501,11 +564,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets whether errors bubble up to the parent.
*
* @param Boolean $errorBubbling
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setErrorBubbling($errorBubbling)
{
@ -515,11 +574,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets whether this field is required to be filled out when bound.
*
* @param Boolean $required
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setRequired($required)
{
@ -529,13 +584,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets the property path that the form should be mapped to.
*
* @param string|PropertyPath $propertyPath The property path or null if the path
* should be set automatically based on
* the form's name.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setPropertyPath($propertyPath)
{
@ -549,12 +598,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets whether the form should be mapped to an element of its
* parent's data.
*
* @param Boolean $mapped Whether the form should be mapped.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setMapped($mapped)
{
@ -564,12 +608,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets whether the form's data should be modified by reference.
*
* @param Boolean $byReference Whether the data should be
modified by reference.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setByReference($byReference)
{
@ -579,11 +618,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets whether the form should be virtual.
*
* @param Boolean $virtual Whether the form should be virtual.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setVirtual($virtual)
{
@ -593,11 +628,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Set the types.
*
* @param array $types An array FormTypeInterface
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setTypes(array $types)
{
@ -607,11 +638,7 @@ class FormConfig implements FormConfigInterface
}
/**
* Sets the initial data of the form.
*
* @param array $data The data of the form in application format.
*
* @return self The configuration object.
* {@inheritdoc}
*/
public function setData($data)
{

View File

@ -0,0 +1,207 @@
<?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;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface FormConfigEditorInterface extends FormConfigInterface
{
/**
* Adds an event listener to an event on this form.
*
* @param string $eventName The name of the event to listen to.
* @param callable $listener The listener to execute.
* @param integer $priority The priority of the listener. Listeners
* with a higher priority are called before
* listeners with a lower priority.
*
* @return self The configuration object.
*/
function addEventListener($eventName, $listener, $priority = 0);
/**
* Adds an event subscriber for events on this form.
*
* @param EventSubscriberInterface $subscriber The subscriber to attach.
*
* @return self The configuration object.
*/
function addEventSubscriber(EventSubscriberInterface $subscriber);
/**
* Adds a validator to the form.
*
* @param FormValidatorInterface $validator The validator.
*
* @return self The configuration object.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
function addValidator(FormValidatorInterface $validator);
/**
* Appends a transformer to the client transformer chain
*
* @param DataTransformerInterface $viewTransformer
*
* @return self The configuration object.
*/
function addViewTransformer(DataTransformerInterface $viewTransformer);
/**
* Clears the client transformers.
*
* @return self The configuration object.
*/
function resetViewTransformers();
/**
* Prepends a transformer to the normalization transformer chain
*
* @param DataTransformerInterface $modelTransformer
*
* @return self The configuration object.
*/
function addModelTransformer(DataTransformerInterface $modelTransformer);
/**
* Clears the normalization transformers.
*
* @return self The configuration object.
*/
function resetModelTransformers();
/**
* Sets the value for an attribute.
*
* @param string $name The name of the attribute
* @param string $value The value of the attribute
*
* @return self The configuration object.
*/
function setAttribute($name, $value);
/**
* Sets the attributes.
*
* @param array $attributes The attributes.
*
* @return self The configuration object.
*/
function setAttributes(array $attributes);
/**
* Sets the data mapper used by the form.
*
* @param DataMapperInterface $dataMapper
*
* @return self The configuration object.
*/
function setDataMapper(DataMapperInterface $dataMapper = null);
/**
* Set whether the form is disabled.
*
* @param Boolean $disabled Whether the form is disabled
*
* @return self The configuration object.
*/
function setDisabled($disabled);
/**
* Sets the data used for the client data when no value is bound.
*
* @param mixed $emptyData The empty data.
*
* @return self The configuration object.
*/
function setEmptyData($emptyData);
/**
* Sets whether errors bubble up to the parent.
*
* @param Boolean $errorBubbling
*
* @return self The configuration object.
*/
function setErrorBubbling($errorBubbling);
/**
* Sets whether this field is required to be filled out when bound.
*
* @param Boolean $required
*
* @return self The configuration object.
*/
function setRequired($required);
/**
* Sets the property path that the form should be mapped to.
*
* @param string|PropertyPath $propertyPath The property path or null if the path
* should be set automatically based on
* the form's name.
*
* @return self The configuration object.
*/
function setPropertyPath($propertyPath);
/**
* Sets whether the form should be mapped to an element of its
* parent's data.
*
* @param Boolean $mapped Whether the form should be mapped.
*
* @return self The configuration object.
*/
function setMapped($mapped);
/**
* Sets whether the form's data should be modified by reference.
*
* @param Boolean $byReference Whether the data should be
modified by reference.
*
* @return self The configuration object.
*/
function setByReference($byReference);
/**
* Sets whether the form should be virtual.
*
* @param Boolean $virtual Whether the form should be virtual.
*
* @return self The configuration object.
*/
function setVirtual($virtual);
/**
* Set the types.
*
* @param array $types An array FormTypeInterface
*
* @return self The configuration object.
*/
function setTypes(array $types);
/**
* Sets the initial data of the form.
*
* @param array $data The data of the form in application format.
*
* @return self The configuration object.
*/
function setData($data);
}

View File

@ -77,14 +77,14 @@ interface FormConfigInterface
*
* @return array An array of {@link DataTransformerInterface} instances.
*/
function getClientTransformers();
function getViewTransformers();
/**
* Returns the view transformers of the form.
*
* @return array An array of {@link DataTransformerInterface} instances.
*/
function getNormTransformers();
function getModelTransformers();
/**
* Returns the data mapper of the form.
@ -149,11 +149,12 @@ interface FormConfigInterface
/**
* Returns the value of the given attribute.
*
* @param string $name The attribute name.
* @param string $name The attribute name.
* @param mixed $default The value returned if the attribute does not exist.
*
* @return mixed The attribute value.
*/
function getAttribute($name);
function getAttribute($name, $default = null);
/**
* Returns the initial data of the form.
@ -168,4 +169,30 @@ interface FormConfigInterface
* @return string The data class or null.
*/
function getDataClass();
/**
* Returns all options passed during the construction of the form.
*
* @return array The passed options.
*/
function getOptions();
/**
* Returns whether a specific option exists.
*
* @param string $name The option name,
*
* @return Boolean Whether the option exists.
*/
function hasOption($name);
/**
* Returns the value of a specific option.
*
* @param string $name The option name.
* @param mixed $default The value returned if the option does not exist.
*
* @return mixed The option value.
*/
function getOption($name, $default = null);
}

View File

@ -0,0 +1,21 @@
<?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;
use Symfony\Component\Form\Event\FilterDataEvent;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormEvent extends FilterDataEvent
{
}

View File

@ -18,15 +18,33 @@ final class FormEvents
{
const PRE_BIND = 'form.pre_bind';
const BIND = 'form.bind';
const POST_BIND = 'form.post_bind';
const PRE_SET_DATA = 'form.pre_set_data';
const POST_SET_DATA = 'form.post_set_data';
/**
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* Use {@link PRE_BIND} instead.
*/
const BIND_CLIENT_DATA = 'form.bind_client_data';
/**
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* Use {@link BIND} instead.
*/
const BIND_NORM_DATA = 'form.bind_norm_data';
/**
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
* Use {@link PRE_SET_DATA} instead.
*/
const SET_DATA = 'form.set_data';
private function __construct()
{
}
}

View File

@ -109,7 +109,7 @@ class FormFactory implements FormFactoryInterface
/**
* {@inheritdoc}
*/
public function create($type, $data = null, array $options = array(), FormBuilder $parent = null)
public function create($type, $data = null, array $options = array(), FormBuilderInterface $parent = null)
{
return $this->createBuilder($type, $data, $options, $parent)->getForm();
}
@ -117,15 +117,15 @@ class FormFactory implements FormFactoryInterface
/**
* {@inheritdoc}
*/
public function createNamed($type, $name, $data = null, array $options = array(), FormBuilder $parent = null)
public function createNamed($name, $type, $data = null, array $options = array(), FormBuilderInterface $parent = null)
{
return $this->createNamedBuilder($type, $name, $data, $options, $parent)->getForm();
return $this->createNamedBuilder($name, $type, $data, $options, $parent)->getForm();
}
/**
* {@inheritdoc}
*/
public function createForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null)
public function createForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null)
{
return $this->createBuilderForProperty($class, $property, $data, $options, $parent)->getForm();
}
@ -133,17 +133,17 @@ class FormFactory implements FormFactoryInterface
/**
* {@inheritdoc}
*/
public function createBuilder($type, $data = null, array $options = array(), FormBuilder $parent = null)
public function createBuilder($type, $data = null, array $options = array(), FormBuilderInterface $parent = null)
{
$name = is_object($type) ? $type->getName() : $type;
return $this->createNamedBuilder($type, $name, $data, $options, $parent);
return $this->createNamedBuilder($name, $type, $data, $options, $parent);
}
/**
* {@inheritdoc}
*/
public function createNamedBuilder($type, $name, $data = null, array $options = array(), FormBuilder $parent = null)
public function createNamedBuilder($name, $type, $data = null, array $options = array(), FormBuilderInterface $parent = null)
{
if (!array_key_exists('data', $options)) {
$options['data'] = $data;
@ -151,7 +151,6 @@ class FormFactory implements FormFactoryInterface
$builder = null;
$types = array();
$knownOptions = array();
$optionsResolver = new OptionsResolver();
// Bottom-up determination of the type hierarchy
@ -185,16 +184,12 @@ class FormFactory implements FormFactoryInterface
// Merge the default options of all types to an array of default
// options. Default options of children override default options
// of parents.
$typeOptions = $type->getDefaultOptions();
$optionsResolver->setDefaults($typeOptions);
$optionsResolver->addAllowedValues($type->getAllowedOptionValues());
$knownOptions = array_merge($knownOptions, array_keys($typeOptions));
/* @var FormTypeInterface $type */
$type->setDefaultOptions($optionsResolver);
foreach ($type->getExtensions() as $typeExtension) {
$extensionOptions = $typeExtension->getDefaultOptions();
$optionsResolver->setDefaults($extensionOptions);
$optionsResolver->addAllowedValues($typeExtension->getAllowedOptionValues());
$knownOptions = array_merge($knownOptions, array_keys($extensionOptions));
/* @var FormTypeExtensionInterface $typeExtension */
$typeExtension->setDefaultOptions($optionsResolver);
}
}
@ -202,7 +197,13 @@ class FormFactory implements FormFactoryInterface
$type = end($types);
// Validate options required by the factory
$diff = array_diff(self::$requiredOptions, $knownOptions);
$diff = array();
foreach (self::$requiredOptions as $requiredOption) {
if (!$optionsResolver->isKnown($requiredOption)) {
$diff[] = $requiredOption;
}
}
if (count($diff) > 0) {
throw new TypeDefinitionException(sprintf('Type "%s" should support the option(s) "%s"', $type->getName(), implode('", "', $diff)));
@ -216,7 +217,7 @@ class FormFactory implements FormFactoryInterface
}
if (!$builder) {
throw new TypeDefinitionException(sprintf('Type "%s" or any of its parents should return a FormBuilder instance from createBuilder()', $type->getName()));
throw new TypeDefinitionException(sprintf('Type "%s" or any of its parents should return a FormBuilderInterface instance from createBuilder()', $type->getName()));
}
$builder->setTypes($types);
@ -238,7 +239,7 @@ class FormFactory implements FormFactoryInterface
/**
* {@inheritdoc}
*/
public function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null)
public function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null)
{
if (!$this->guesser) {
$this->loadGuesser();
@ -279,7 +280,7 @@ class FormFactory implements FormFactoryInterface
$options = array_merge($typeGuess->getOptions(), $options);
}
return $this->createNamedBuilder($type, $property, $data, $options, $parent);
return $this->createNamedBuilder($property, $type, $data, $options, $parent);
}
/**

View File

@ -11,6 +11,9 @@
namespace Symfony\Component\Form;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface FormFactoryInterface
{
/**
@ -21,47 +24,47 @@ interface FormFactoryInterface
* @param string|FormTypeInterface $type The type of the form
* @param mixed $data The initial data
* @param array $options The options
* @param FormBuilder $parent The parent builder
* @param FormBuilderInterface $parent The parent builder
*
* @return FormInterface The form named after the type
*
* @throws Exception\FormException if any given option is not applicable to the given type
*/
function create($type, $data = null, array $options = array(), FormBuilder $parent = null);
function create($type, $data = null, array $options = array(), FormBuilderInterface $parent = null);
/**
* Returns a form.
*
* @see createNamedBuilder()
*
* @param string|FormTypeInterface $type The type of the form
* @param string $name The name of the form
* @param string|FormTypeInterface $type The type of the form
* @param mixed $data The initial data
* @param array $options The options
* @param FormBuilder $parent The parent builder
* @param FormBuilderInterface $parent The parent builder
*
* @return FormInterface The form
*
* @throws Exception\FormException if any given option is not applicable to the given type
*/
function createNamed($type, $name, $data = null, array $options = array(), FormBuilder $parent = null);
function createNamed($name, $type, $data = null, array $options = array(), FormBuilderInterface $parent = null);
/**
* Returns a form for a property of a class.
*
* @see createBuilderForProperty()
*
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
* @param mixed $data The initial data
* @param array $options The options for the builder
* @param FormBuilder $parent The parent builder
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
* @param mixed $data The initial data
* @param array $options The options for the builder
* @param FormBuilderInterface $parent The parent builder
*
* @return FormInterface The form named after the property
*
* @throws Exception\FormException if any given option is not applicable to the form type
*/
function createForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null);
function createForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null);
/**
* Returns a form builder.
@ -69,28 +72,28 @@ interface FormFactoryInterface
* @param string|FormTypeInterface $type The type of the form
* @param mixed $data The initial data
* @param array $options The options
* @param FormBuilder $parent The parent builder
* @param FormBuilderInterface $parent The parent builder
*
* @return FormBuilder The form builder
* @return FormBuilderInterface The form builder
*
* @throws Exception\FormException if any given option is not applicable to the given type
*/
function createBuilder($type, $data = null, array $options = array(), FormBuilder $parent = null);
function createBuilder($type, $data = null, array $options = array(), FormBuilderInterface $parent = null);
/**
* Returns a form builder.
*
* @param string|FormTypeInterface $type The type of the form
* @param string $name The name of the form
* @param string|FormTypeInterface $type The type of the form
* @param mixed $data The initial data
* @param array $options The options
* @param FormBuilder $parent The parent builder
* @param FormBuilderInterface $parent The parent builder
*
* @return FormBuilder The form builder
* @return FormBuilderInterface The form builder
*
* @throws Exception\FormException if any given option is not applicable to the given type
*/
function createNamedBuilder($type, $name, $data = null, array $options = array(), FormBuilder $parent = null);
function createNamedBuilder($name, $type, $data = null, array $options = array(), FormBuilderInterface $parent = null);
/**
* Returns a form builder for a property of a class.
@ -98,17 +101,17 @@ interface FormFactoryInterface
* If any of the 'max_length', 'required' and type options can be guessed,
* and are not provided in the options argument, the guessed value is used.
*
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
* @param mixed $data The initial data
* @param array $options The options for the builder
* @param FormBuilder $parent The parent builder
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
* @param mixed $data The initial data
* @param array $options The options for the builder
* @param FormBuilderInterface $parent The parent builder
*
* @return FormBuilder The form builder named after the property
* @return FormBuilderInterface The form builder named after the property
*
* @throws Exception\FormException if any given option is not applicable to the form type
*/
function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null);
function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null);
/**
* Returns a type by name.

View File

@ -82,14 +82,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
*
* @return array An array of FormInterface instances
*/
function getChildren();
/**
* Return whether the form has children.
*
* @return Boolean
*/
function hasChildren();
function all();
/**
* Returns all errors.
@ -101,11 +94,11 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
/**
* Updates the field with default data.
*
* @param array $appData The data formatted as expected for the underlying object
* @param array $modelData The data formatted as expected for the underlying object
*
* @return FormInterface The form instance
*/
function setData($appData);
function setData($modelData);
/**
* Returns the data in the format needed for the underlying object.
@ -128,7 +121,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
*
* @return string
*/
function getClientData();
function getViewData();
/**
* Returns the extra data.
@ -228,20 +221,6 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
*/
function bind($data);
/**
* Returns whether the form has an attribute with the given name.
*
* @param string $name The name of the attribute
*/
function hasAttribute($name);
/**
* Returns the value of the attributes with the given name.
*
* @param string $name The name of the attribute
*/
function getAttribute($name);
/**
* Returns the root of the form tree.
*
@ -259,9 +238,9 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
/**
* Creates a view.
*
* @param FormView $parent The parent view
* @param FormViewInterface $parent The parent view
*
* @return FormView The view
* @return FormViewInterface The view
*/
function createView(FormView $parent = null);
function createView(FormViewInterface $parent = null);
}

View File

@ -11,61 +11,60 @@
namespace Symfony\Component\Form;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface FormTypeExtensionInterface
{
/**
* Builds the form.
*
* This method gets called after the extended type has built the form to
* This method is called after the extended type has built the form to
* further modify it.
*
* @see FormTypeInterface::buildForm()
*
* @param FormBuilder $builder The form builder
* @param array $options The options
* @param FormBuilderInterface $builder The form builder
* @param array $options The options
*/
function buildForm(FormBuilder $builder, array $options);
function buildForm(FormBuilderInterface $builder, array $options);
/**
* Builds the view.
*
* This method gets called after the extended type has built the view to
* This method is called after the extended type has built the view to
* further modify it.
*
* @see FormTypeInterface::buildView()
*
* @param FormView $view The view
* @param FormInterface $form The form
* @param FormViewInterface $view The view
* @param FormInterface $form The form
* @param array $options The options
*/
function buildView(FormView $view, FormInterface $form);
function buildView(FormViewInterface $view, FormInterface $form, array $options);
/**
* Builds the view.
* Finishes the view.
*
* This method gets called after the extended type has built the view to
* This method is called after the extended type has finished the view to
* further modify it.
*
* @see FormTypeInterface::buildViewBottomUp()
* @see FormTypeInterface::finishView()
*
* @param FormView $view The view
* @param FormInterface $form The form
* @param FormViewInterface $view The view
* @param FormInterface $form The form
* @param array $options The options
*/
function buildViewBottomUp(FormView $view, FormInterface $form);
function finishView(FormViewInterface $view, FormInterface $form, array $options);
/**
* Overrides the default options form the extended type.
* Overrides the default options from the extended type.
*
* @return array
* @param OptionsResolverInterface $resolver The resolver for the options.
*/
function getDefaultOptions();
/**
* Returns the allowed option values for each option (if any).
*
* @return array The allowed option values
*/
function getAllowedOptionValues();
function setDefaultOptions(OptionsResolverInterface $resolver);
/**
* Returns the name of the type being extended.

View File

@ -11,6 +11,9 @@
namespace Symfony\Component\Form;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface FormTypeGuesserInterface
{
/**
@ -19,7 +22,7 @@ interface FormTypeGuesserInterface
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return TypeGuess A guess for the field's type and options
* @return Guess\TypeGuess A guess for the field's type and options
*/
function guessType($class, $property);
@ -29,7 +32,7 @@ interface FormTypeGuesserInterface
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess A guess for the field's required setting
* @return Guess\Guess A guess for the field's required setting
*/
function guessRequired($class, $property);
@ -39,7 +42,7 @@ interface FormTypeGuesserInterface
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess A guess for the field's maximum length
* @return Guess\Guess A guess for the field's maximum length
*/
function guessMaxLength($class, $property);
@ -49,7 +52,7 @@ interface FormTypeGuesserInterface
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess A guess for the field's minimum length
* @return Guess\Guess A guess for the field's minimum length
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
@ -67,7 +70,7 @@ interface FormTypeGuesserInterface
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess A guess for the field's required pattern
* @return Guess\Guess A guess for the field's required pattern
*/
function guessPattern($class, $property);
}

View File

@ -11,52 +11,62 @@
namespace Symfony\Component\Form;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface FormTypeInterface
{
/**
* Builds the form.
*
* This method gets called for each type in the hierarchy starting form the
* top most type.
* Type extensions can further modify the form.
* This method is called for each type in the hierarchy starting form the
* top most type. Type extensions can further modify the form.
*
* @see FormTypeExtensionInterface::buildForm()
*
* @param FormBuilder $builder The form builder
* @param array $options The options
* @param FormBuilderInterface $builder The form builder
* @param array $options The options
*/
function buildForm(FormBuilder $builder, array $options);
function buildForm(FormBuilderInterface $builder, array $options);
/**
* Builds the form view.
*
* This method gets called for each type in the hierarchy starting form the
* top most type.
* Type extensions can further modify the view.
* This method is called for each type in the hierarchy starting form the
* top most type. Type extensions can further modify the view.
*
* A view of a form is built before the views of the child forms are built.
* This means that you cannot access child views in this method. If you need
* to do so, move your logic to {@link finishView()} instead.
*
* @see FormTypeExtensionInterface::buildView()
*
* @param FormView $view The view
* @param FormInterface $form The form
* @param FormViewInterface $view The view
* @param FormInterface $form The form
* @param array $options The options
*/
function buildView(FormView $view, FormInterface $form);
function buildView(FormViewInterface $view, FormInterface $form, array $options);
/**
* Builds the form view.
* Finishes the form view.
*
* This method gets called for each type in the hierarchy starting form the
* top most type.
* Type extensions can further modify the view.
* top most type. Type extensions can further modify the view.
*
* Children views have been built when this method gets called so you get
* a chance to modify them.
* When this method is called, views of the form's children have already
* been built and finished and can be accessed. You should only implement
* such logic in this method that actually accesses child views. For everything
* else you are recommended to implement {@link buildView()} instead.
*
* @see FormTypeExtensionInterface::buildViewBottomUp()
* @see FormTypeExtensionInterface::finishView()
*
* @param FormView $view The view
* @param FormInterface $form The form
* @param FormViewInterface $view The view
* @param FormInterface $form The form
* @param array $options The options
*/
function buildViewBottomUp(FormView $view, FormInterface $form);
function finishView(FormViewInterface $view, FormInterface $form, array $options);
/**
* Returns a builder for the current type.
@ -68,32 +78,23 @@ interface FormTypeInterface
* @param FormFactoryInterface $factory The form factory
* @param array $options The options
*
* @return FormBuilder|null A form builder or null when the type does not have a builder
* @return FormBuilderInterface|null A form builder or null when the type does not have a builder
*/
function createBuilder($name, FormFactoryInterface $factory, array $options);
/**
* Returns the default options for this type.
* Sets the default options for this type.
*
* @return array The default options
* @param OptionsResolverInterface $resolver The resolver for the options.
*/
function getDefaultOptions();
/**
* Returns the allowed option values for each option (if any).
*
* @return array The allowed option values
*/
function getAllowedOptionValues();
function setDefaultOptions(OptionsResolverInterface $resolver);
/**
* Returns the name of the parent type.
*
* @param array $options
*
* @return string|null The name of the parent type if any otherwise null
* @return string|null The name of the parent type if any, null otherwise.
*/
function getParent(array $options);
function getParent();
/**
* Returns the name of this type.

View File

@ -11,14 +11,10 @@
namespace Symfony\Component\Form;
use ArrayAccess;
use IteratorAggregate;
use Countable;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormView implements ArrayAccess, IteratorAggregate, Countable
class FormView implements \IteratorAggregate, FormViewInterface
{
private $name;
@ -47,18 +43,18 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
* @param mixed $value
*
* @return FormView The current view
* {@inheritdoc}
*/
public function set($name, $value)
public function setVar($name, $value)
{
$this->vars[$name] = $value;
@ -66,24 +62,19 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* @param $name
*
* @return Boolean
* {@inheritdoc}
*/
public function has($name)
public function hasVar($name)
{
return array_key_exists($name, $this->vars);
}
/**
* @param $name
* @param $default
*
* @return mixed
* {@inheritdoc}
*/
public function get($name, $default = null)
public function getVar($name, $default = null)
{
if (false === $this->has($name)) {
if (false === $this->hasVar($name)) {
return $default;
}
@ -91,21 +82,21 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* @return array
* {@inheritdoc}
*/
public function all()
public function addVars(array $vars)
{
return $this->vars;
$this->vars = array_replace($this->vars, $vars);
return $this;
}
/**
* Alias of all so it is possible to do `form.vars.foo`
*
* @return array
* {@inheritdoc}
*/
public function getVars()
{
return $this->all();
return $this->vars;
}
/**
@ -124,9 +115,7 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Returns whether the attached form is rendered.
*
* @return Boolean Whether the form is rendered
* {@inheritdoc}
*/
public function isRendered()
{
@ -150,9 +139,7 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Marks the attached form as rendered
*
* @return FormView The current view
* {@inheritdoc}
*/
public function setRendered()
{
@ -162,13 +149,9 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Sets the parent view.
*
* @param FormView $parent The parent view
*
* @return FormView The current view
* {@inheritdoc}
*/
public function setParent(FormView $parent = null)
public function setParent(FormViewInterface $parent = null)
{
$this->parent = $parent;
@ -176,9 +159,7 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Returns the parent view.
*
* @return FormView The parent view
* {@inheritdoc}
*/
public function getParent()
{
@ -186,9 +167,7 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Returns whether this view has a parent.
*
* @return Boolean Whether this view has a parent
* {@inheritdoc}
*/
public function hasParent()
{
@ -196,13 +175,9 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Adds a child view.
*
* @param FormView $child The child view to add.
*
* @return FormView The current view
* {@inheritdoc}
*/
public function addChild(FormView $child)
public function add(FormViewInterface $child)
{
$this->children[$child->getName()] = $child;
@ -210,13 +185,9 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Removes a child view.
*
* @param string $name The name of the removed child view.
*
* @return FormView The current view
* {@inheritdoc}
*/
public function removeChild($name)
public function remove($name)
{
unset($this->children[$name]);
@ -224,31 +195,32 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Returns the children.
*
* @return array The children as instances of FormView
* {@inheritdoc}
*/
public function getChildren()
public function all()
{
return $this->children;
}
/**
* Returns a given child.
*
* @param string $name The name of the child
*
* @return FormView The child view
* {@inheritdoc}
*/
public function getChild($name)
public function get($name)
{
if (!isset($this->children[$name])) {
throw new \InvalidArgumentException(sprintf('Child "%s" does not exist.', $name));
}
return $this->children[$name];
}
/**
* Returns whether this view has children.
* Returns whether this view has any children.
*
* @return Boolean Whether this view has children
* @return Boolean Whether the view has children.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link count()} instead.
*/
public function hasChildren()
{
@ -256,13 +228,9 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
}
/**
* Returns whether this view has a given child.
*
* @param string $name The name of the child
*
* @return Boolean Whether the child with the given name exists
* {@inheritdoc}
*/
public function hasChild($name)
public function has($name)
{
return isset($this->children[$name]);
}
@ -276,7 +244,7 @@ class FormView implements ArrayAccess, IteratorAggregate, Countable
*/
public function offsetGet($name)
{
return $this->getChild($name);
return $this->get($name);
}
/**

View File

@ -0,0 +1,150 @@
<?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;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface FormViewInterface extends \ArrayAccess, \Traversable, \Countable
{
/**
* Returns the name of the form.
*
* @return string The form name.
*/
function getName();
/**
* Returns whether the view was already rendered.
*
* @return Boolean Whether this view's widget is rendered.
*/
function isRendered();
/**
* Marks the view as rendered.
*
* @return FormViewInterface The view object.
*/
function setRendered();
/**
* Sets the parent view.
*
* @param FormViewInterface $parent The parent view.
*
* @return FormViewInterface The view object.
*/
function setParent(FormViewInterface $parent = null);
/**
* Returns the parent view.
*
* @return FormViewInterface The parent view.
*/
function getParent();
/**
* Returns whether this view has a parent.
*
* @return Boolean Whether this view has a parent
*/
function hasParent();
/**
* Adds a child view.
*
* @param FormViewInterface $child The child view to add.
*
* @return FormViewInterface The view object.
*/
function add(FormViewInterface $child);
/**
* Removes a child view.
*
* @param string $name The name of the removed child view.
*
* @return FormViewInterface The view object.
*/
function remove($name);
/**
* Returns the children.
*
* @return array The children as instances of FormView
*/
function all();
/**
* Returns a given child.
*
* @param string $name The name of the child
*
* @return FormViewInterface The child view
*/
function get($name);
/**
* Returns whether this view has a given child.
*
* @param string $name The name of the child
*
* @return Boolean Whether the child with the given name exists
*/
function has($name);
/**
* Sets a view variable.
*
* @param string $name The variable name.
* @param string $value The variable value.
*
* @return FormViewInterface The view object.
*/
function setVar($name, $value);
/**
* Adds a list of view variables.
*
* @param array $values An array of variable names and values.
*
* @return FormViewInterface The view object.
*/
function addVars(array $values);
/**
* Returns whether a view variable exists.
*
* @param string $name The variable name.
*
* @return Boolean Whether the variable exists.
*/
function hasVar($name);
/**
* Returns the value of a view variable.
*
* @param string $name The variable name.
* @param mixed $default The value to return if the variable is not set.
*
* @return mixed The variable value.
*/
function getVar($name, $default = null);
/**
* Returns the values of all view variables.
*
* @return array The values of all variables.
*/
function getVars();
}

View File

@ -17,7 +17,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
{
public function testRow()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$form->addError(new FormError('Error!'));
$view = $form->createView();
$html = $this->renderRow($view);
@ -37,7 +37,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRowOverrideVariables()
{
$view = $this->factory->createNamed('text', 'name')->createView();
$view = $this->factory->createNamed('name', 'text')->createView();
$html = $this->renderRow($view, array('label' => 'foo&bar'));
$this->assertMatchesXpath($html,
@ -52,7 +52,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRepeatedRow()
{
$form = $this->factory->createNamed('repeated', 'name');
$form = $this->factory->createNamed('name', 'repeated');
$form->addError(new FormError('Error!'));
$view = $form->createView();
$html = $this->renderRow($view);
@ -77,7 +77,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRest()
{
$view = $this->factory->createNamedBuilder('form', 'name')
$view = $this->factory->createNamedBuilder('name', 'form')
->add('field1', 'text')
->add('field2', 'repeated')
->add('field3', 'text')
@ -118,17 +118,17 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRestWithChildrenForms()
{
$child1 = $this->factory->createNamedBuilder('form', 'child1')
$child1 = $this->factory->createNamedBuilder('child1', 'form')
->add('field1', 'text')
->add('field2', 'text')
->getForm();
$child2 = $this->factory->createNamedBuilder('form', 'child2')
$child2 = $this->factory->createNamedBuilder('child2', 'form')
->add('field1', 'text')
->add('field2', 'text')
->getForm();
$view = $this->factory->createNamedBuilder('form', 'parent')
$view = $this->factory->createNamedBuilder('parent', 'form')
->getForm()
->add($child1)
->add($child2)
@ -178,7 +178,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRestAndRepeatedWithRow()
{
$view = $this->factory->createNamedBuilder('form', 'name')
$view = $this->factory->createNamedBuilder('name', 'form')
->add('first', 'text')
->add('password', 'repeated')
->getForm()
@ -204,7 +204,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRestAndRepeatedWithRowPerChild()
{
$view = $this->factory->createNamedBuilder('form', 'name')
$view = $this->factory->createNamedBuilder('name', 'form')
->add('first', 'text')
->add('password', 'repeated')
->getForm()
@ -232,7 +232,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRestAndRepeatedWithWidgetPerChild()
{
$view = $this->factory->createNamedBuilder('form', 'name')
$view = $this->factory->createNamedBuilder('name', 'form')
->add('first', 'text')
->add('password', 'repeated')
->getForm()
@ -262,7 +262,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testCollection()
{
$form = $this->factory->createNamed('collection', 'name', array('a', 'b'), array(
$form = $this->factory->createNamed('name', 'collection', array('a', 'b'), array(
'type' => 'text',
));
@ -279,7 +279,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testEmptyCollection()
{
$form = $this->factory->createNamed('collection', 'name', array(), array(
$form = $this->factory->createNamed('name', 'collection', array(), array(
'type' => 'text',
));
@ -333,7 +333,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testForm()
{
$form = $this->factory->createNamedBuilder('form', 'name')
$form = $this->factory->createNamedBuilder('name', 'form')
->add('firstName', 'text')
->add('lastName', 'text')
->getForm();
@ -361,9 +361,9 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
// https://github.com/symfony/symfony/issues/2308
public function testNestedFormError()
{
$form = $this->factory->createNamedBuilder('form', 'name')
$form = $this->factory->createNamedBuilder('name', 'form')
->add($this->factory
->createNamedBuilder('form', 'child', null, array('error_bubbling' => false))
->createNamedBuilder('child', 'form', null, array('error_bubbling' => false))
->add('grandChild', 'form')
)
->getForm();
@ -386,11 +386,11 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
->method('generateCsrfToken')
->will($this->returnValue('foo&bar'));
$form = $this->factory->createNamedBuilder('form', 'name')
$form = $this->factory->createNamedBuilder('name', 'form')
->add($this->factory
// No CSRF protection on nested forms
->createNamedBuilder('form', 'child')
->add($this->factory->createNamedBuilder('text', 'grandchild'))
->createNamedBuilder('child', 'form')
->add($this->factory->createNamedBuilder('grandchild', 'text'))
)
->getForm();
@ -407,7 +407,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRepeated()
{
$form = $this->factory->createNamed('repeated', 'name', 'foobar', array(
$form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
'type' => 'text',
));
@ -433,7 +433,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRepeatedWithCustomOptions()
{
$form = $this->factory->createNamed('repeated', 'name', null, array(
$form = $this->factory->createNamed('name', 'repeated', null, array(
// the global required value cannot be overriden
'first_options' => array('label' => 'Test', 'required' => false),
'second_options' => array('label' => 'Test2')
@ -461,7 +461,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testSearchInputName()
{
$form = $this->factory->createNamedBuilder('form', 'full')
$form = $this->factory->createNamedBuilder('full', 'form')
->add('name', 'search')
->getForm();
@ -482,7 +482,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testLabelHasNoId()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$html = $this->renderRow($form->createView());
$this->assertMatchesXpath($html,
@ -501,7 +501,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testThemeBlockInheritance($theme)
{
$view = $this->factory
->createNamed('email', 'name')
->createNamed('name', 'email')
->createView()
;
@ -518,11 +518,11 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
*/
public function testThemeInheritance($parentTheme, $childTheme)
{
$child = $this->factory->createNamedBuilder('form', 'child')
$child = $this->factory->createNamedBuilder('child', 'form')
->add('field', 'text')
->getForm();
$view = $this->factory->createNamedBuilder('form', 'parent')
$view = $this->factory->createNamedBuilder('parent', 'form')
->add('field', 'text')
->getForm()
->add($child)

View File

@ -114,7 +114,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testEnctype()
{
$form = $this->factory->createNamedBuilder('form', 'name')
$form = $this->factory->createNamedBuilder('name', 'form')
->add('file', 'file')
->getForm();
@ -123,7 +123,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testNoEnctype()
{
$form = $this->factory->createNamedBuilder('form', 'name')
$form = $this->factory->createNamedBuilder('name', 'form')
->add('text', 'text')
->getForm();
@ -132,7 +132,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabel()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$view = $form->createView();
$this->renderWidget($view, array('label' => 'foo'));
$html = $this->renderLabel($view);
@ -147,7 +147,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabelOnForm()
{
$form = $this->factory->createNamed('date', 'name');
$form = $this->factory->createNamed('name', 'date');
$view = $form->createView();
$this->renderWidget($view, array('label' => 'foo'));
$html = $this->renderLabel($view);
@ -162,7 +162,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabelWithCustomTextPassedAsOption()
{
$form = $this->factory->createNamed('text', 'name', null, array(
$form = $this->factory->createNamed('name', 'text', null, array(
'label' => 'Custom label',
));
$html = $this->renderLabel($form->createView());
@ -177,7 +177,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabelWithCustomTextPassedDirectly()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$html = $this->renderLabel($form->createView(), 'Custom label');
$this->assertMatchesXpath($html,
@ -190,7 +190,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabelWithCustomTextPassedAsOptionAndDirectly()
{
$form = $this->factory->createNamed('text', 'name', null, array(
$form = $this->factory->createNamed('name', 'text', null, array(
'label' => 'Custom label',
));
$html = $this->renderLabel($form->createView(), 'Overridden label');
@ -205,7 +205,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabelDoesNotRenderFieldAttributes()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$html = $this->renderLabel($form->createView(), null, array(
'attr' => array(
'class' => 'my&class'
@ -222,7 +222,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabelWithCustomOptionsPassedDirectly()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$html = $this->renderLabel($form->createView(), null, array(
'label_attr' => array(
'class' => 'my&class'
@ -239,7 +239,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLabelWithCustomTextAndCustomOptionsPassedDirectly()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$html = $this->renderLabel($form->createView(), 'Custom label', array(
'label_attr' => array(
'class' => 'my&class'
@ -257,7 +257,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testErrors()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$form->addError(new FormError('Error 1'));
$form->addError(new FormError('Error 2'));
$view = $form->createView();
@ -276,7 +276,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testWidgetById()
{
$form = $this->factory->createNamed('text', 'text_id');
$form = $this->factory->createNamed('text_id', 'text');
$html = $this->renderWidget($form->createView());
$this->assertMatchesXpath($html,
@ -293,7 +293,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testCheckedCheckbox()
{
$form = $this->factory->createNamed('checkbox', 'name', true);
$form = $this->factory->createNamed('name', 'checkbox', true);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -307,7 +307,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testUncheckedCheckbox()
{
$form = $this->factory->createNamed('checkbox', 'name', false);
$form = $this->factory->createNamed('name', 'checkbox', false);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -320,7 +320,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testCheckboxWithValue()
{
$form = $this->factory->createNamed('checkbox', 'name', false, array(
$form = $this->factory->createNamed('name', 'checkbox', false, array(
'value' => 'foo&bar',
));
@ -335,7 +335,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoice()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => false,
@ -356,7 +356,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceWithPreferred()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&b'),
'multiple' => false,
@ -380,7 +380,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceWithPreferredAndNoSeparator()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&b'),
'multiple' => false,
@ -402,7 +402,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceWithPreferredAndBlankSeparator()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&b'),
'multiple' => false,
@ -425,7 +425,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testChoiceWithOnlyPreferred()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&a', '&b'),
'multiple' => false,
@ -441,7 +441,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceNonRequired()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => false,
'multiple' => false,
@ -464,7 +464,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceNonRequiredNoneSelected()
{
$form = $this->factory->createNamed('choice', 'name', null, array(
$form = $this->factory->createNamed('name', 'choice', null, array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => false,
'multiple' => false,
@ -487,7 +487,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceWithNonRequiredEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => false,
@ -511,7 +511,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceRequiredWithEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => true,
'multiple' => false,
@ -535,7 +535,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceRequiredWithEmptyValueViaView()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => true,
'multiple' => false,
@ -558,7 +558,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceGrouped()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array(
'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'Group&2' => array('&c' => 'Choice&C'),
@ -588,7 +588,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testMultipleChoice()
{
$form = $this->factory->createNamed('choice', 'name', array('&a'), array(
$form = $this->factory->createNamed('name', 'choice', array('&a'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => true,
'expanded' => false,
@ -609,7 +609,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testMultipleChoiceSkipEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', array('&a'), array(
$form = $this->factory->createNamed('name', 'choice', array('&a'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => true,
'expanded' => false,
@ -631,7 +631,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testMultipleChoiceNonRequired()
{
$form = $this->factory->createNamed('choice', 'name', array('&a'), array(
$form = $this->factory->createNamed('name', 'choice', array('&a'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => false,
'multiple' => true,
@ -653,7 +653,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceExpanded()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => true,
@ -675,7 +675,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceExpandedSkipEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
$form = $this->factory->createNamed('name', 'choice', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => true,
@ -698,7 +698,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSingleChoiceExpandedWithBooleanValue()
{
$form = $this->factory->createNamed('choice', 'name', true, array(
$form = $this->factory->createNamed('name', 'choice', true, array(
'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
'multiple' => false,
'expanded' => true,
@ -720,7 +720,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testMultipleChoiceExpanded()
{
$form = $this->factory->createNamed('choice', 'name', array('&a', '&c'), array(
$form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
'multiple' => true,
'expanded' => true,
@ -745,7 +745,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testCountry()
{
$form = $this->factory->createNamed('country', 'name', 'AT');
$form = $this->factory->createNamed('name', 'country', 'AT');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
@ -758,7 +758,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testCountryWithEmptyValue()
{
$form = $this->factory->createNamed('country', 'name', 'AT', array(
$form = $this->factory->createNamed('name', 'country', 'AT', array(
'empty_value' => 'Select&Country',
'required' => false,
));
@ -775,7 +775,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateTime()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
$form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
'input' => 'string',
'with_seconds' => false,
));
@ -814,7 +814,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateTimeWithEmptyValueGlobal()
{
$form = $this->factory->createNamed('datetime', 'name', null, array(
$form = $this->factory->createNamed('name', 'datetime', null, array(
'input' => 'string',
'empty_value' => 'Change&Me',
'required' => false,
@ -854,7 +854,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateTimeWithEmptyValueOnTime()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03', array(
$form = $this->factory->createNamed('name', 'datetime', '2011-02-03', array(
'input' => 'string',
'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
'required' => false,
@ -894,7 +894,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateTimeWithSeconds()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
$form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
'input' => 'string',
'with_seconds' => true,
));
@ -936,7 +936,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateTimeSingleText()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
$form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
'input' => 'string',
'date_widget' => 'single_text',
'time_widget' => 'single_text',
@ -962,7 +962,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateTimeWithWidgetSingleText()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
$form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
'input' => 'string',
'widget' => 'single_text',
));
@ -978,7 +978,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
$form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
'input' => 'string',
'date_widget' => 'choice',
'time_widget' => 'choice',
@ -996,7 +996,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateChoice()
{
$form = $this->factory->createNamed('date', 'name', '2011-02-03', array(
$form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
'input' => 'string',
'widget' => 'choice',
));
@ -1021,7 +1021,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateChoiceWithEmptyValueGlobal()
{
$form = $this->factory->createNamed('date', 'name', null, array(
$form = $this->factory->createNamed('name', 'date', null, array(
'input' => 'string',
'widget' => 'choice',
'empty_value' => 'Change&Me',
@ -1048,7 +1048,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateChoiceWithEmptyValueOnYear()
{
$form = $this->factory->createNamed('date', 'name', null, array(
$form = $this->factory->createNamed('name', 'date', null, array(
'input' => 'string',
'widget' => 'choice',
'required' => false,
@ -1075,7 +1075,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateText()
{
$form = $this->factory->createNamed('date', 'name', '2011-02-03', array(
$form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
'input' => 'string',
'widget' => 'text',
));
@ -1103,7 +1103,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDateSingleText()
{
$form = $this->factory->createNamed('date', 'name', '2011-02-03', array(
$form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
'input' => 'string',
'widget' => 'single_text',
));
@ -1130,7 +1130,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testBirthDay()
{
$form = $this->factory->createNamed('birthday', 'name', '2000-02-03', array(
$form = $this->factory->createNamed('name', 'birthday', '2000-02-03', array(
'input' => 'string',
));
@ -1154,7 +1154,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testBirthDayWithEmptyValue()
{
$form = $this->factory->createNamed('birthday', 'name', '1950-01-01', array(
$form = $this->factory->createNamed('name', 'birthday', '1950-01-01', array(
'input' => 'string',
'empty_value' => '',
'required' => false,
@ -1183,7 +1183,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testEmail()
{
$form = $this->factory->createNamed('email', 'name', 'foo&bar');
$form = $this->factory->createNamed('name', 'email', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1197,7 +1197,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testEmailWithMaxLength()
{
$form = $this->factory->createNamed('email', 'name', 'foo&bar', array(
$form = $this->factory->createNamed('name', 'email', 'foo&bar', array(
'max_length' => 123,
));
@ -1213,7 +1213,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testFile()
{
$form = $this->factory->createNamed('file', 'name');
$form = $this->factory->createNamed('name', 'file');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1224,7 +1224,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testHidden()
{
$form = $this->factory->createNamed('hidden', 'name', 'foo&bar');
$form = $this->factory->createNamed('name', 'hidden', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1237,7 +1237,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testReadOnly()
{
$form = $this->factory->createNamed('text', 'name', null, array(
$form = $this->factory->createNamed('name', 'text', null, array(
'read_only' => true,
));
@ -1252,7 +1252,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testDisabled()
{
$form = $this->factory->createNamed('text', 'name', null, array(
$form = $this->factory->createNamed('name', 'text', null, array(
'disabled' => true,
));
@ -1267,7 +1267,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testInteger()
{
$form = $this->factory->createNamed('integer', 'name', 123);
$form = $this->factory->createNamed('name', 'integer', 123);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1280,7 +1280,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLanguage()
{
$form = $this->factory->createNamed('language', 'name', 'de');
$form = $this->factory->createNamed('name', 'language', 'de');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
@ -1293,7 +1293,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testLocale()
{
$form = $this->factory->createNamed('locale', 'name', 'de_AT');
$form = $this->factory->createNamed('name', 'locale', 'de_AT');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
@ -1306,7 +1306,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testMoney()
{
$form = $this->factory->createNamed('money', 'name', 1234.56, array(
$form = $this->factory->createNamed('name', 'money', 1234.56, array(
'currency' => 'EUR',
));
@ -1322,7 +1322,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testNumber()
{
$form = $this->factory->createNamed('number', 'name', 1234.56);
$form = $this->factory->createNamed('name', 'number', 1234.56);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1335,7 +1335,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testPassword()
{
$form = $this->factory->createNamed('password', 'name', 'foo&bar');
$form = $this->factory->createNamed('name', 'password', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1347,7 +1347,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testPasswordBoundNotAlwaysEmpty()
{
$form = $this->factory->createNamed('password', 'name', null, array(
$form = $this->factory->createNamed('name', 'password', null, array(
'always_empty' => false,
));
$form->bind('foo&bar');
@ -1363,7 +1363,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testPasswordWithMaxLength()
{
$form = $this->factory->createNamed('password', 'name', 'foo&bar', array(
$form = $this->factory->createNamed('name', 'password', 'foo&bar', array(
'max_length' => 123,
));
@ -1378,7 +1378,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testPercent()
{
$form = $this->factory->createNamed('percent', 'name', 0.1);
$form = $this->factory->createNamed('name', 'percent', 0.1);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1392,7 +1392,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testCheckedRadio()
{
$form = $this->factory->createNamed('radio', 'name', true);
$form = $this->factory->createNamed('name', 'radio', true);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1406,7 +1406,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testUncheckedRadio()
{
$form = $this->factory->createNamed('radio', 'name', false);
$form = $this->factory->createNamed('name', 'radio', false);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1419,7 +1419,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testRadioWithValue()
{
$form = $this->factory->createNamed('radio', 'name', false, array(
$form = $this->factory->createNamed('name', 'radio', false, array(
'value' => 'foo&bar',
));
@ -1434,7 +1434,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTextarea()
{
$form = $this->factory->createNamed('textarea', 'name', 'foo&bar', array(
$form = $this->factory->createNamed('name', 'textarea', 'foo&bar', array(
'pattern' => 'foo',
));
@ -1449,7 +1449,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testText()
{
$form = $this->factory->createNamed('text', 'name', 'foo&bar');
$form = $this->factory->createNamed('name', 'text', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1463,7 +1463,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTextWithMaxLength()
{
$form = $this->factory->createNamed('text', 'name', 'foo&bar', array(
$form = $this->factory->createNamed('name', 'text', 'foo&bar', array(
'max_length' => 123,
));
@ -1479,7 +1479,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testSearch()
{
$form = $this->factory->createNamed('search', 'name', 'foo&bar');
$form = $this->factory->createNamed('name', 'search', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1493,7 +1493,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTime()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
$form = $this->factory->createNamed('name', 'time', '04:05:06', array(
'input' => 'string',
'with_seconds' => false,
));
@ -1517,7 +1517,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTimeWithSeconds()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
$form = $this->factory->createNamed('name', 'time', '04:05:06', array(
'input' => 'string',
'with_seconds' => true,
));
@ -1548,7 +1548,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTimeText()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
$form = $this->factory->createNamed('name', 'time', '04:05:06', array(
'input' => 'string',
'widget' => 'text',
));
@ -1578,7 +1578,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTimeSingleText()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
$form = $this->factory->createNamed('name', 'time', '04:05:06', array(
'input' => 'string',
'widget' => 'single_text',
));
@ -1594,7 +1594,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTimeWithEmptyValueGlobal()
{
$form = $this->factory->createNamed('time', 'name', null, array(
$form = $this->factory->createNamed('name', 'time', null, array(
'input' => 'string',
'empty_value' => 'Change&Me',
'required' => false,
@ -1619,7 +1619,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTimeWithEmptyValueOnYear()
{
$form = $this->factory->createNamed('time', 'name', null, array(
$form = $this->factory->createNamed('name', 'time', null, array(
'input' => 'string',
'required' => false,
'empty_value' => array('hour' => 'Change&Me'),
@ -1655,7 +1655,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTimezone()
{
$form = $this->factory->createNamed('timezone', 'name', 'Europe/Vienna');
$form = $this->factory->createNamed('name', 'timezone', 'Europe/Vienna');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
@ -1673,7 +1673,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testTimezoneWithEmptyValue()
{
$form = $this->factory->createNamed('timezone', 'name', null, array(
$form = $this->factory->createNamed('name', 'timezone', null, array(
'empty_value' => 'Select&Timezone',
'required' => false,
));
@ -1690,7 +1690,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testUrl()
{
$url = 'http://www.google.com?foo1=bar1&foo2=bar2';
$form = $this->factory->createNamed('url', 'name', $url);
$form = $this->factory->createNamed('name', 'url', $url);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
@ -1703,7 +1703,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testCollectionPrototype()
{
$form = $this->factory->createNamedBuilder('form', 'name', array('items' => array('one', 'two', 'three')))
$form = $this->factory->createNamedBuilder('name', 'form', array('items' => array('one', 'two', 'three')))
->add('items', 'collection', array('allow_add' => true))
->getForm()
->createView();
@ -1721,7 +1721,7 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
public function testEmptyRootFormName()
{
$form = $this->factory->createNamedBuilder('form', '', '')
$form = $this->factory->createNamedBuilder('', 'form', '')
->add('child', 'text')
->getForm();

View File

@ -17,7 +17,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
{
public function testRow()
{
$form = $this->factory->createNamed('text', 'name');
$form = $this->factory->createNamed('name', 'text');
$form->addError(new FormError('Error!'));
$view = $form->createView();
$html = $this->renderRow($view);
@ -41,7 +41,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testRepeatedRow()
{
$form = $this->factory->createNamed('repeated', 'name');
$form = $this->factory->createNamed('name', 'repeated');
$html = $this->renderRow($form->createView());
$this->assertMatchesXpath($html,
@ -71,7 +71,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testRepeatedRowWithErrors()
{
$form = $this->factory->createNamed('repeated', 'name');
$form = $this->factory->createNamed('name', 'repeated');
$form->addError(new FormError('Error!'));
$view = $form->createView();
$html = $this->renderRow($view);
@ -107,7 +107,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testRest()
{
$view = $this->factory->createNamedBuilder('form', 'name')
$view = $this->factory->createNamedBuilder('name', 'form')
->add('field1', 'text')
->add('field2', 'repeated')
->add('field3', 'text')
@ -154,7 +154,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testCollection()
{
$form = $this->factory->createNamed('collection', 'name', array('a', 'b'), array(
$form = $this->factory->createNamed('name', 'collection', array('a', 'b'), array(
'type' => 'text',
));
@ -172,7 +172,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testEmptyCollection()
{
$form = $this->factory->createNamed('collection', 'name', array(), array(
$form = $this->factory->createNamed('name', 'collection', array(), array(
'type' => 'text',
));
@ -186,7 +186,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testForm()
{
$view = $this->factory->createNamedBuilder('form', 'name')
$view = $this->factory->createNamedBuilder('name', 'form')
->add('firstName', 'text')
->add('lastName', 'text')
->getForm()
@ -223,9 +223,9 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
// https://github.com/symfony/symfony/issues/2308
public function testNestedFormError()
{
$form = $this->factory->createNamedBuilder('form', 'name')
$form = $this->factory->createNamedBuilder('name', 'form')
->add($this->factory
->createNamedBuilder('form', 'child', null, array('error_bubbling' => false))
->createNamedBuilder('child', 'form', null, array('error_bubbling' => false))
->add('grandChild', 'form')
)
->getForm();
@ -250,11 +250,11 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
->method('generateCsrfToken')
->will($this->returnValue('foo&bar'));
$form = $this->factory->createNamedBuilder('form', 'name')
$form = $this->factory->createNamedBuilder('name', 'form')
->add($this->factory
// No CSRF protection on nested forms
->createNamedBuilder('form', 'child')
->add($this->factory->createNamedBuilder('text', 'grandchild'))
->createNamedBuilder('child', 'form')
->add($this->factory->createNamedBuilder('grandchild', 'text'))
)
->getForm();
@ -274,7 +274,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testRepeated()
{
$form = $this->factory->createNamed('repeated', 'name', 'foobar', array(
$form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
'type' => 'text',
));
@ -308,7 +308,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testRepeatedWithCustomOptions()
{
$form = $this->factory->createNamed('repeated', 'name', 'foobar', array(
$form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
'type' => 'password',
'first_options' => array('label' => 'Test', 'required' => false),
'second_options' => array('label' => 'Test2')

Some files were not shown because too many files have changed in this diff Show More