renderBlock('container_attributes') ?>>
- renderBlock('field_widget'); ?>
+ renderBlock('input'); ?>
renderBlock('container_attributes') ?>>
widget($form['date']).' '.$view['form']->widget($form['time']) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/email_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/email_widget.html.php
index c30cfb35c3..a00dda278e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/email_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/email_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget', array('type' => isset($type) ? $type : 'email')) ?>
+renderBlock('input', array('type' => isset($type) ? $type : 'email')) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_enctype.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_enctype.html.php
index 424d425969..aa4ff39bba 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_enctype.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_enctype.html.php
@@ -1 +1 @@
-get('multipart')): ?>enctype="multipart/form-data"
+renderBlock('form_enctype') ?>
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_errors.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_errors.html.php
index 339e3d0009..d7b87ea2bc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_errors.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_errors.html.php
@@ -1,21 +1 @@
-
-
-
- getMessagePluralization()) {
- echo $view['translator']->trans(
- $error->getMessageTemplate(),
- $error->getMessageParameters(),
- 'validators'
- );
- } else {
- echo $view['translator']->transChoice(
- $error->getMessageTemplate(),
- $error->getMessagePluralization(),
- $error->getMessageParameters(),
- 'validators'
- );
- }?>
-
-
-
+renderBlock('form_errors') ?>
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_label.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_label.html.php
index 1434301d4c..7c0c1b7559 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_label.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_label.html.php
@@ -1,2 +1 @@
-
-
$v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>>escape($view['translator']->trans($label, array(), $translation_domain)) ?>
+renderBlock('form_label') ?>
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rest.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rest.html.php
index 89041c6ec6..a570b1045a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rest.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rest.html.php
@@ -1,5 +1 @@
-
- isRendered()): ?>
- row($child) ?>
-
-
+renderBlock('form_rest') ?>
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_row.html.php
index 091807020d..c91dcb5543 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_row.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_row.html.php
@@ -1,5 +1 @@
-
- label($form, isset($label) ? $label : null) ?>
- errors($form) ?>
- widget($form) ?>
-
+renderBlock('form_row') ?>
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rows.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rows.html.php
index a5f1dfbf5f..ef0bf384a6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rows.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rows.html.php
@@ -1,4 +1 @@
-errors($form) ?>
-
- row($child) ?>
-
+renderBlock('form_rows') ?>
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_widget.html.php
index 0c86483386..f1ca2edadb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_widget.html.php
@@ -1,5 +1 @@
-
"
- value="escape($value) ?>"
- renderBlock('attributes') ?>
-/>
+renderBlock('input') ?>
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_enctype.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_enctype.html.php
new file mode 100644
index 0000000000..424d425969
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_enctype.html.php
@@ -0,0 +1 @@
+get('multipart')): ?>enctype="multipart/form-data"
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_errors.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_errors.html.php
new file mode 100644
index 0000000000..339e3d0009
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_errors.html.php
@@ -0,0 +1,21 @@
+
+
+
+ getMessagePluralization()) {
+ echo $view['translator']->trans(
+ $error->getMessageTemplate(),
+ $error->getMessageParameters(),
+ 'validators'
+ );
+ } else {
+ echo $view['translator']->transChoice(
+ $error->getMessageTemplate(),
+ $error->getMessagePluralization(),
+ $error->getMessageParameters(),
+ 'validators'
+ );
+ }?>
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php
index e5c5843c46..3ddc300fd4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php
@@ -1,2 +1,3 @@
+hasChildren()) { $attr['for'] = $id; } ?>
$v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>>escape($view['translator']->trans($label, array(), $translation_domain)) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_rest.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_rest.html.php
new file mode 100644
index 0000000000..89041c6ec6
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_rest.html.php
@@ -0,0 +1,5 @@
+
+ isRendered()): ?>
+ row($child) ?>
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_row.html.php
index 0a79a0cc53..02fb9ae9b6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_row.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_row.html.php
@@ -1,4 +1,7 @@
label($form, isset($label) ? $label : null) ?>
+ hasChildren()): ?>
+ errors($form) ?>
+
widget($form) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_rows.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_rows.html.php
new file mode 100644
index 0000000000..a5f1dfbf5f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_rows.html.php
@@ -0,0 +1,4 @@
+errors($form) ?>
+
+ row($child) ?>
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_widget.html.php
index 77fa483c3f..1c9368693b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_widget.html.php
@@ -1,5 +1,8 @@
+hasChildren()): ?>
renderBlock('container_attributes') ?>>
- renderBlock('field_rows') ?>
+ renderBlock('form_rows') ?>
rest($form) ?>
-
+
+renderBlock('input')?>
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden_widget.html.php
index 11942cfe2b..50a42451ae 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget', array('type' => isset($type) ? $type : "hidden")) ?>
+renderBlock('input', array('type' => isset($type) ? $type : "hidden")) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/input.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/input.html.php
new file mode 100644
index 0000000000..0c86483386
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/input.html.php
@@ -0,0 +1,5 @@
+
"
+ value="escape($value) ?>"
+ renderBlock('attributes') ?>
+/>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/integer_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/integer_widget.html.php
index 012211ab5a..1fc6ace34b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/integer_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/integer_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget', array('type' => isset($type) ? $type : "number")) ?>
+renderBlock('input', array('type' => isset($type) ? $type : "number")) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/money_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/money_widget.html.php
index 3151ecbd84..a68ad5ddac 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/money_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/money_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget'), $money_pattern) ?>
+renderBlock('input'), $money_pattern) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php
index 9a08222c91..7e1a2776a7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget', array('type' => isset($type) ? $type : "text")) ?>
+renderBlock('input', array('type' => isset($type) ? $type : "text")) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php
index 78319fcbae..7aff242ef4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget', array('type' => isset($type) ? $type : "password")) ?>
+renderBlock('input', array('type' => isset($type) ? $type : "password")) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php
index 4245b52a0c..328321f21f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget', array('type' => isset($type) ? $type : "text")) ?> %
+renderBlock('input', array('type' => isset($type) ? $type : "text")) ?> %
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/repeated_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/repeated_row.html.php
index a84bad54df..b9a07bc466 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/repeated_row.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/repeated_row.html.php
@@ -1 +1 @@
-renderBlock('field_rows') ?>
+renderBlock('form_rows') ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php
index bbfd593dbc..d8a773544e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php
@@ -1 +1 @@
-renderBlock('field_widget', array('type' => isset($type) ? $type : "search")) ?>
+renderBlock('input', array('type' => isset($type) ? $type : "search")) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/time_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/time_widget.html.php
index 599750d20a..2178974c74 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/time_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/time_widget.html.php
@@ -1,5 +1,5 @@
- renderBlock('field_widget'); ?>
+ renderBlock('input'); ?>
renderBlock('container_attributes') ?>>
renderBlock('field_widget', array('type' => isset($type) ? $type : "url")) ?>
+renderBlock('input', array('type' => isset($type) ? $type : "url")) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/field_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/field_row.html.php
deleted file mode 100644
index b9e5c5639c..0000000000
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/field_row.html.php
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- label($form, isset($label) ? $label : null) ?>
-
-
- errors($form) ?>
- widget($form) ?>
-
-
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php
index ac4315f957..05d8c4aea8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php
@@ -1,7 +1,51 @@
-
-
-
- renderBlock('field_errors'); ?>
-
-
-
+hasChildren()): ?>
+ 0): ?>
+
+
+
+
+
+ getMessagePluralization()) {
+ echo $view['translator']->trans(
+ $error->getMessageTemplate(),
+ $error->getMessageParameters(),
+ 'validators'
+ );
+ } else {
+ echo $view['translator']->transChoice(
+ $error->getMessageTemplate(),
+ $error->getMessagePluralization(),
+ $error->getMessageParameters(),
+ 'validators'
+ );
+ }?>
+
+
+
+
+
+
+
+
+
+
+ getMessagePluralization()) {
+ echo $view['translator']->trans(
+ $error->getMessageTemplate(),
+ $error->getMessageParameters(),
+ 'validators'
+ );
+ } else {
+ echo $view['translator']->transChoice(
+ $error->getMessageTemplate(),
+ $error->getMessagePluralization(),
+ $error->getMessageParameters(),
+ 'validators'
+ );
+ }?>
+
+
+
+
\ No newline at end of file
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_row.html.php
index d1bbbb1b2a..9262a1bae1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_row.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_row.html.php
@@ -3,6 +3,9 @@
label($form, isset($label) ? $label : null) ?>
+ hasChildren()): ?>
+ errors($form) ?>
+
widget($form) ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_widget.html.php
index d802ccf050..171f1eb40c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_widget.html.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_widget.html.php
@@ -1,5 +1,8 @@
+hasChildren()): ?>
renderBlock('container_attributes') ?>>
- renderBlock('field_rows') ?>
+ renderBlock('form_rows') ?>
rest($form) ?>
-
+
+renderBlock('input')?>
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php
index 2004b4e67e..8fd4adef89 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php
@@ -119,7 +119,7 @@ class FormHelper extends Helper
*/
public function widget(FormView $view, array $variables = array())
{
- return trim($this->renderSection($view, 'widget', $variables));
+ return $this->renderSection($view, 'widget', $variables);
}
/**
@@ -276,7 +276,7 @@ class FormHelper extends Helper
$view->setRendered();
}
- return $html;
+ return trim($html);
}
} while (--$typeIndex >= 0);
@@ -311,7 +311,7 @@ class FormHelper extends Helper
$variables = array_replace_recursive($context['variables'], $variables);
- return $this->engine->render($template, $variables);
+ return trim($this->engine->render($template, $variables));
}
public function getName()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 859ec489ab..2c7204e735 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -27,9 +27,9 @@ abstract class FrameworkExtensionTest extends TestCase
$def = $container->getDefinition('form.type_extension.csrf');
$this->assertTrue($container->getParameter('form.type_extension.csrf.enabled'));
- $this->assertEquals('%form.type_extension.csrf.enabled%', $def->getArgument(0));
+ $this->assertEquals('%form.type_extension.csrf.enabled%', $def->getArgument(1));
$this->assertEquals('_csrf', $container->getParameter('form.type_extension.csrf.field_name'));
- $this->assertEquals('%form.type_extension.csrf.field_name%', $def->getArgument(1));
+ $this->assertEquals('%form.type_extension.csrf.field_name%', $def->getArgument(2));
$this->assertEquals('s3cr3t', $container->getParameterBag()->resolveValue($container->findDefinition('form.csrf_provider')->getArgument(1)));
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Child/field_label.html.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Child/form_label.html.php
similarity index 100%
rename from src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Child/field_label.html.php
rename to src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Child/form_label.html.php
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/field_label.html.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/form_label.html.php
similarity index 100%
rename from src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/field_label.html.php
rename to src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/form_label.html.php
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/field_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/input.html.php
similarity index 100%
rename from src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/field_widget.html.php
rename to src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Parent/input.html.php
diff --git a/src/Symfony/Component/Form/DataTransformerInterface.php b/src/Symfony/Component/Form/DataTransformerInterface.php
index add2ce3d9b..2f1543e91b 100644
--- a/src/Symfony/Component/Form/DataTransformerInterface.php
+++ b/src/Symfony/Component/Form/DataTransformerInterface.php
@@ -24,7 +24,7 @@ interface DataTransformerInterface
* This method is called on two occasions inside a form field:
*
* 1. When the form field is initialized with the data attached from the datasource (object or array).
- * 2. When data from a request is bound using {@link Field::bind()} to transform the new input data
+ * 2. When data from a request is bound using {@link Form::bind()} to transform the new input data
* back into the renderable format. For example if you have a date field and bind '2009-10-10' onto
* it you might accept this value because its easily parsed, but the transformer still writes back
* "2009/10/10" onto the form field (for further displaying or other purposes).
@@ -52,7 +52,7 @@ interface DataTransformerInterface
* Transforms a value from the transformed representation to its original
* representation.
*
- * This method is called when {@link Field::bind()} is called to transform the requests tainted data
+ * This method is called when {@link Form::bind()} is called to transform the requests tainted data
* into an acceptable format for your data processing/model layer.
*
* This method must be able to deal with empty values. Usually this will
diff --git a/src/Symfony/Component/Form/Exception/DanglingFieldException.php b/src/Symfony/Component/Form/Exception/DanglingFieldException.php
deleted file mode 100644
index 29d10be36b..0000000000
--- a/src/Symfony/Component/Form/Exception/DanglingFieldException.php
+++ /dev/null
@@ -1,21 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Thrown when a field is expected to be added to a form but is not
- *
- * @author Bernhard Schussek
- */
-class DanglingFieldException extends FormException
-{
-}
diff --git a/src/Symfony/Component/Form/Exception/FieldDefinitionException.php b/src/Symfony/Component/Form/Exception/FieldDefinitionException.php
deleted file mode 100644
index 6cd904ad4a..0000000000
--- a/src/Symfony/Component/Form/Exception/FieldDefinitionException.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-class FieldDefinitionException extends FormException
-{
-}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index 1ed495248b..1a8ba2d1be 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -44,8 +44,8 @@ class ChoiceType extends AbstractType
}
if ($options['expanded']) {
- $this->addSubFields($builder, $options['choice_list']->getPreferredViews(), $options);
- $this->addSubFields($builder, $options['choice_list']->getRemainingViews(), $options);
+ $this->addSubForms($builder, $options['choice_list']->getPreferredViews(), $options);
+ $this->addSubForms($builder, $options['choice_list']->getRemainingViews(), $options);
}
// empty value
@@ -182,7 +182,7 @@ class ChoiceType extends AbstractType
*/
public function getParent(array $options)
{
- return isset($options['expanded']) && $options['expanded'] ? 'form' : 'field';
+ return 'field';
}
/**
@@ -200,12 +200,12 @@ class ChoiceType extends AbstractType
* @param array $choiceViews The choice view objects.
* @param array $options The build options.
*/
- private function addSubFields(FormBuilder $builder, array $choiceViews, array $options)
+ private function addSubForms(FormBuilder $builder, array $choiceViews, array $options)
{
foreach ($choiceViews as $i => $choiceView) {
if (is_array($choiceView)) {
// Flatten groups
- $this->addSubFields($builder, $choiceView, $options);
+ $this->addSubForms($builder, $choiceView, $options);
} else {
$choiceOpts = array(
'value' => $choiceView->getValue(),
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
index 6eba72d4f6..f428054ede 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
@@ -153,7 +153,7 @@ class DateTimeType extends AbstractType
'widget' => null,
// This will overwrite "empty_value" child options
'empty_value' => null,
- // If initialized with a \DateTime object, FieldType initializes
+ // If initialized with a \DateTime object, FormType initializes
// this option to "\DateTime". Since the internal, normalized
// representation is not \DateTime, but an array, we need to unset
// this option.
@@ -200,7 +200,7 @@ class DateTimeType extends AbstractType
*/
public function getParent(array $options)
{
- return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
+ return 'field';
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
index e58d0d9340..c506714c7f 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
@@ -177,7 +177,7 @@ class DateType extends AbstractType
// them like immutable value objects
'by_reference' => false,
'error_bubbling' => false,
- // If initialized with a \DateTime object, FieldType initializes
+ // If initialized with a \DateTime object, FormType initializes
// this option to "\DateTime". Since the internal, normalized
// representation is not \DateTime, but an array, we need to unset
// this option.
@@ -210,7 +210,7 @@ class DateType extends AbstractType
*/
public function getParent(array $options)
{
- return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
+ return 'field';
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php b/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
index b676d81984..c509abe6a5 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
@@ -23,179 +23,15 @@ use Symfony\Component\Form\Extension\Core\EventListener\ValidationListener;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Exception\FormException;
+/**
+ * Deprecated. You should extend FormType instead.
+ *
+ * @author Bernhard Schussek
+ *
+ * @deprecated Deprecated since version 2.1, to be removed in 2.3.
+ */
class FieldType extends AbstractType
{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilder $builder, array $options)
- {
- if (null === $options['property_path']) {
- $options['property_path'] = $builder->getName();
- }
-
- if (false === $options['property_path'] || '' === $options['property_path']) {
- $options['property_path'] = null;
- } else {
- $options['property_path'] = new PropertyPath($options['property_path']);
- }
- if (!is_array($options['attr'])) {
- throw new FormException('The "attr" option must be "array".');
- }
-
- $builder
- ->setRequired($options['required'])
- ->setDisabled($options['disabled'])
- ->setErrorBubbling($options['error_bubbling'])
- ->setEmptyData($options['empty_data'])
- ->setAttribute('read_only', $options['read_only'])
- ->setAttribute('by_reference', $options['by_reference'])
- ->setAttribute('property_path', $options['property_path'])
- ->setAttribute('error_mapping', $options['error_mapping'])
- ->setAttribute('max_length', $options['max_length'])
- ->setAttribute('pattern', $options['pattern'])
- ->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
- ->setAttribute('attr', $options['attr'] ?: array())
- ->setAttribute('invalid_message', $options['invalid_message'])
- ->setAttribute('invalid_message_parameters', $options['invalid_message_parameters'])
- ->setAttribute('translation_domain', $options['translation_domain'])
- ->setData($options['data'])
- ->addEventSubscriber(new ValidationListener())
- ;
-
- if ($options['trim']) {
- $builder->addEventSubscriber(new TrimListener());
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form)
- {
- $name = $form->getName();
- $readOnly = $form->getAttribute('read_only');
-
- if ($view->hasParent()) {
- if ('' === $name) {
- throw new FormException('Form node with empty name can be used only as root form node.');
- }
-
- if ('' !== ($parentFullName = $view->getParent()->get('full_name'))) {
- $id = sprintf('%s_%s', $view->getParent()->get('id'), $name);
- $fullName = sprintf('%s[%s]', $parentFullName, $name);
- } else {
- $id = $name;
- $fullName = $name;
- }
-
- // Complex fields are read-only if themselves or their parent is.
- $readOnly = $readOnly || $view->getParent()->get('read_only');
- } else {
- $id = $name;
- $fullName = $name;
-
- // Strip leading underscores and digits. These are allowed in
- // form names, but not in HTML4 ID attributes.
- // http://www.w3.org/TR/html401/struct/global.html#adef-id
- $id = ltrim($id, '_0123456789');
- }
-
- $types = array();
- foreach ($form->getTypes() as $type) {
- $types[] = $type->getName();
- }
-
- $view
- ->set('form', $view)
- ->set('id', $id)
- ->set('name', $name)
- ->set('full_name', $fullName)
- ->set('read_only', $readOnly)
- ->set('errors', $form->getErrors())
- ->set('value', $form->getClientData())
- ->set('disabled', $form->isDisabled())
- ->set('required', $form->isRequired())
- ->set('max_length', $form->getAttribute('max_length'))
- ->set('pattern', $form->getAttribute('pattern'))
- ->set('size', null)
- ->set('label', $form->getAttribute('label'))
- ->set('multipart', false)
- ->set('attr', $form->getAttribute('attr'))
- ->set('types', $types)
- ->set('translation_domain', $form->getAttribute('translation_domain'))
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDefaultOptions()
- {
- // Derive "data_class" option from passed "data" object
- $dataClass = function (Options $options) {
- if (is_object($options['data'])) {
- return get_class($options['data']);
- }
-
- return null;
- };
-
- // Derive "empty_data" closure from "data_class" option
- $emptyData = function (Options $options) {
- $class = $options['data_class'];
-
- if (null !== $class) {
- return function (FormInterface $form) use ($class) {
- if ($form->isEmpty() && !$form->isRequired()) {
- return null;
- }
-
- return new $class();
- };
- }
-
- return '';
- };
-
- return array(
- 'data' => null,
- 'data_class' => $dataClass,
- 'empty_data' => $emptyData,
- 'trim' => true,
- 'required' => true,
- 'read_only' => false,
- 'disabled' => false,
- 'max_length' => null,
- 'pattern' => null,
- 'property_path' => null,
- 'by_reference' => true,
- 'error_bubbling' => false,
- 'error_mapping' => array(),
- 'label' => null,
- 'attr' => array(),
- 'invalid_message' => 'This value is not valid',
- 'invalid_message_parameters' => array(),
- 'translation_domain' => 'messages',
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function createBuilder($name, FormFactoryInterface $factory, array $options)
- {
- return new FormBuilder($name, $factory, new EventDispatcher(), $options['data_class']);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent(array $options)
- {
- return null;
- }
-
/**
* {@inheritdoc}
*/
@@ -203,9 +39,4 @@ class FieldType extends AbstractType
{
return 'field';
}
-
- private function humanize($text)
- {
- return ucfirst(trim(strtolower(preg_replace('/[_\s]+/', ' ', $text))));
- }
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
index 30f37203b2..468c65a0f3 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
@@ -23,12 +23,24 @@ class FileType extends AbstractType
public function buildView(FormView $view, FormInterface $form)
{
$view
- ->set('multipart', true)
->set('type', 'file')
->set('value', '')
;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function buildViewBottomUp(FormView $view, FormInterface $form)
+ {
+ $view
+ ->set('multipart', true)
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function getParent(array $options)
{
return 'field';
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
index 36e0c0c63b..1738fb4f62 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -13,10 +13,16 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Options;
+use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormInterface;
+use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormView;
+use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
+use Symfony\Component\Form\Extension\Core\EventListener\ValidationListener;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\Form\Exception\FormException;
class FormType extends AbstractType
{
@@ -25,9 +31,102 @@ class FormType extends AbstractType
*/
public function buildForm(FormBuilder $builder, array $options)
{
+ if (null === $options['property_path']) {
+ $options['property_path'] = $builder->getName();
+ }
+
+ if (false === $options['property_path'] || '' === $options['property_path']) {
+ $options['property_path'] = null;
+ } else {
+ $options['property_path'] = new PropertyPath($options['property_path']);
+ }
+ if (!is_array($options['attr'])) {
+ throw new FormException('The "attr" option must be "array".');
+ }
+
$builder
+ ->setRequired($options['required'])
+ ->setDisabled($options['disabled'])
+ ->setErrorBubbling($options['error_bubbling'])
+ ->setEmptyData($options['empty_data'])
+ ->setAttribute('read_only', $options['read_only'])
+ ->setAttribute('by_reference', $options['by_reference'])
+ ->setAttribute('property_path', $options['property_path'])
+ ->setAttribute('error_mapping', $options['error_mapping'])
+ ->setAttribute('max_length', $options['max_length'])
+ ->setAttribute('pattern', $options['pattern'])
+ ->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
+ ->setAttribute('attr', $options['attr'] ?: array())
+ ->setAttribute('invalid_message', $options['invalid_message'])
+ ->setAttribute('invalid_message_parameters', $options['invalid_message_parameters'])
+ ->setAttribute('translation_domain', $options['translation_domain'])
->setAttribute('virtual', $options['virtual'])
+ ->setData($options['data'])
->setDataMapper(new PropertyPathMapper($options['data_class']))
+ ->addEventSubscriber(new ValidationListener())
+ ;
+
+ if ($options['trim']) {
+ $builder->addEventSubscriber(new TrimListener());
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildView(FormView $view, FormInterface $form)
+ {
+ $name = $form->getName();
+ $readOnly = $form->getAttribute('read_only');
+
+ if ($view->hasParent()) {
+ if ('' === $name) {
+ throw new FormException('Form node with empty name can be used only as root form node.');
+ }
+
+ if ('' !== ($parentFullName = $view->getParent()->get('full_name'))) {
+ $id = sprintf('%s_%s', $view->getParent()->get('id'), $name);
+ $fullName = sprintf('%s[%s]', $parentFullName, $name);
+ } else {
+ $id = $name;
+ $fullName = $name;
+ }
+
+ // Complex fields are read-only if themselves or their parent is.
+ $readOnly = $readOnly || $view->getParent()->get('read_only');
+ } else {
+ $id = $name;
+ $fullName = $name;
+
+ // Strip leading underscores and digits. These are allowed in
+ // form names, but not in HTML4 ID attributes.
+ // http://www.w3.org/TR/html401/struct/global.html#adef-id
+ $id = ltrim($id, '_0123456789');
+ }
+
+ $types = array();
+ foreach ($form->getTypes() as $type) {
+ $types[] = $type->getName();
+ }
+
+ $view
+ ->set('form', $view)
+ ->set('id', $id)
+ ->set('name', $name)
+ ->set('full_name', $fullName)
+ ->set('read_only', $readOnly)
+ ->set('errors', $form->getErrors())
+ ->set('value', $form->getClientData())
+ ->set('disabled', $form->isDisabled())
+ ->set('required', $form->isRequired())
+ ->set('max_length', $form->getAttribute('max_length'))
+ ->set('pattern', $form->getAttribute('pattern'))
+ ->set('size', null)
+ ->set('label', $form->getAttribute('label'))
+ ->set('multipart', false)
+ ->set('attr', $form->getAttribute('attr'))
+ ->set('types', $types)
+ ->set('translation_domain', $form->getAttribute('translation_domain'))
;
}
@@ -53,29 +152,75 @@ class FormType extends AbstractType
*/
public function getDefaultOptions()
{
- $emptyData = function (Options $options, $currentValue) {
- if (empty($options['data_class'])) {
- return array();
+ // Derive "data_class" option from passed "data" object
+ $dataClass = function (Options $options) {
+ if (is_object($options['data'])) {
+ return get_class($options['data']);
}
- return $currentValue;
+ return null;
};
+ // Derive "empty_data" closure from "data_class" option
+ $emptyData = function (Options $options) {
+ $class = $options['data_class'];
+
+ if (null !== $class) {
+ return function (FormInterface $form) use ($class) {
+ if ($form->isEmpty() && !$form->isRequired()) {
+ return null;
+ }
+
+ return new $class();
+ };
+ }
+
+ return function (FormInterface $form) {
+ if ($form->hasChildren()) {
+ return array();
+ }
+
+ return '';
+ };
+ };
+
return array(
+ 'data' => null,
+ 'data_class' => $dataClass,
'empty_data' => $emptyData,
+ 'trim' => true,
+ 'required' => true,
+ 'read_only' => false,
+ 'disabled' => false,
+ 'max_length' => null,
+ 'pattern' => null,
+ 'property_path' => null,
+ 'by_reference' => true,
+ 'error_bubbling' => false,
+ 'error_mapping' => array(),
+ 'label' => null,
+ 'attr' => array(),
'virtual' => false,
- // Errors in forms bubble by default, so that form errors will
- // end up as global errors in the root form
- 'error_bubbling' => true,
+ 'invalid_message' => 'This value is not valid',
+ 'invalid_message_parameters' => array(),
+ 'translation_domain' => 'messages',
);
}
+ /**
+ * {@inheritdoc}
+ */
+ public function createBuilder($name, FormFactoryInterface $factory, array $options)
+ {
+ return new FormBuilder($name, $factory, new EventDispatcher(), $options['data_class']);
+ }
+
/**
* {@inheritdoc}
*/
public function getParent(array $options)
{
- return 'field';
+ return null;
}
/**
@@ -85,4 +230,9 @@ class FormType extends AbstractType
{
return 'form';
}
+
+ private function humanize($text)
+ {
+ return ucfirst(trim(strtolower(preg_replace('/[_\s]+/', ' ', $text))));
+ }
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
index 3f7258bb82..546220d0ab 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
@@ -150,7 +150,7 @@ class TimeType extends AbstractType
// them like immutable value objects
'by_reference' => false,
'error_bubbling' => false,
- // If initialized with a \DateTime object, FieldType initializes
+ // If initialized with a \DateTime object, FormType initializes
// this option to "\DateTime". Since the internal, normalized
// representation is not \DateTime, but an array, we need to unset
// this option.
@@ -183,7 +183,7 @@ class TimeType extends AbstractType
*/
public function getParent(array $options)
{
- return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
+ return 'field';
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
index 42505e2b76..5330bbda45 100644
--- a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
+++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
@@ -32,27 +32,13 @@ class CsrfExtension extends AbstractExtension
$this->csrfProvider = $csrfProvider;
}
- /**
- * {@inheritDoc}
- */
- protected function loadTypes()
- {
- return array(
- new Type\CsrfType($this->csrfProvider),
- );
- }
-
/**
* {@inheritDoc}
*/
protected function loadTypeExtensions()
{
return array(
- new Type\ChoiceTypeCsrfExtension(),
- new Type\DateTypeCsrfExtension(),
- new Type\FormTypeCsrfExtension(),
- new Type\RepeatedTypeCsrfExtension(),
- new Type\TimeTypeCsrfExtension(),
+ new Type\FormTypeCsrfExtension($this->csrfProvider),
);
}
}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
index 3de52ab867..dd74d87b2e 100644
--- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
+++ b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
@@ -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\DataEvent;
+use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
/**
@@ -22,6 +22,12 @@ use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
*/
class CsrfValidationListener implements EventSubscriberInterface
{
+ /**
+ * The name of the CSRF field
+ * @var string
+ */
+ private $fieldName;
+
/**
* The provider for generating and validating CSRF tokens
* @var CsrfProviderInterface
@@ -45,24 +51,26 @@ class CsrfValidationListener implements EventSubscriberInterface
);
}
- public function __construct(CsrfProviderInterface $csrfProvider, $intention)
+ public function __construct($fieldName, CsrfProviderInterface $csrfProvider, $intention)
{
+ $this->fieldName = $fieldName;
$this->csrfProvider = $csrfProvider;
$this->intention = $intention;
}
- public function onBindClientData(DataEvent $event)
+ public function onBindClientData(FilterDataEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
- if ((!$form->hasParent() || $form->getParent()->isRoot())
- && !$this->csrfProvider->isCsrfTokenValid($this->intention, $data)) {
- $form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form'));
+ if ($form->isRoot() && $form->hasChildren() && isset($data[$this->fieldName])) {
+ if (!$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) {
+ $form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form'));
+ }
- // If the session timed out, the token is invalid now.
- // Regenerate the token so that a resubmission is possible.
- $event->setData($this->csrfProvider->generateCsrfToken($this->intention));
+ unset($data[$this->fieldName]);
}
+
+ $event->setData($data);
}
}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/EnsureCsrfFieldListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/EnsureCsrfFieldListener.php
deleted file mode 100644
index 480d67c323..0000000000
--- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/EnsureCsrfFieldListener.php
+++ /dev/null
@@ -1,66 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\EventListener;
-
-use Symfony\Component\Form\Event\DataEvent;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-use Symfony\Component\Form\FormFactoryInterface;
-
-/**
- * Ensures the CSRF field.
- *
- * @author Bulat Shakirzyanov
- * @author Kris Wallsmith
- */
-class EnsureCsrfFieldListener
-{
- private $factory;
- private $name;
- private $intention;
- private $provider;
-
- /**
- * Constructor.
- *
- * @param FormFactoryInterface $factory The form factory
- * @param string $name A name for the CSRF field
- * @param string $intention The intention string
- * @param CsrfProviderInterface $provider The CSRF provider
- */
- public function __construct(FormFactoryInterface $factory, $name, $intention = null, CsrfProviderInterface $provider = null)
- {
- $this->factory = $factory;
- $this->name = $name;
- $this->intention = $intention;
- $this->provider = $provider;
- }
-
- /**
- * Ensures a root form has a CSRF field.
- *
- * This method should be connected to both form.pre_set_data and form.pre_bind.
- */
- public function ensureCsrfField(DataEvent $event)
- {
- $form = $event->getForm();
-
- $options = array();
- if ($this->intention) {
- $options['intention'] = $this->intention;
- }
- if ($this->provider) {
- $options['csrf_provider'] = $this->provider;
- }
-
- $form->add($this->factory->createNamed('csrf', $this->name, null, $options));
- }
-}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/ChoiceTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/ChoiceTypeCsrfExtension.php
deleted file mode 100644
index dc1e6db15b..0000000000
--- a/src/Symfony/Component/Form/Extension/Csrf/Type/ChoiceTypeCsrfExtension.php
+++ /dev/null
@@ -1,27 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-
-class ChoiceTypeCsrfExtension extends AbstractTypeExtension
-{
- public function getDefaultOptions()
- {
- return array('csrf_protection' => false);
- }
-
- public function getExtendedType()
- {
- return 'choice';
- }
-}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/CsrfType.php b/src/Symfony/Component/Form/Extension/Csrf/Type/CsrfType.php
deleted file mode 100644
index 97c69d8a5a..0000000000
--- a/src/Symfony/Component/Form/Extension/Csrf/Type/CsrfType.php
+++ /dev/null
@@ -1,83 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\Type;
-
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-
-class CsrfType extends AbstractType
-{
- private $csrfProvider;
-
- /**
- * Constructor.
- *
- * @param CsrfProviderInterface $csrfProvider The provider to use to generate the token
- */
- public function __construct(CsrfProviderInterface $csrfProvider)
- {
- $this->csrfProvider = $csrfProvider;
- }
-
- /**
- * Builds the CSRF field.
- *
- * A validator is added to check the token value when the CSRF field is added to
- * a root form
- *
- * @param FormBuilder $builder The form builder
- * @param array $options The options
- */
- public function buildForm(FormBuilder $builder, array $options)
- {
- $csrfProvider = $options['csrf_provider'];
- $intention = $options['intention'];
-
- $builder
- ->setData($csrfProvider->generateCsrfToken($intention))
- ->addEventSubscriber(new CsrfValidationListener($csrfProvider, $intention))
- ;
- }
-
- /**
- * {@inheritDoc}
- */
- public function getDefaultOptions()
- {
- return array(
- 'csrf_provider' => $this->csrfProvider,
- 'intention' => null,
- 'property_path' => false,
- );
- }
-
- /**
- * {@inheritDoc}
- */
- public function getParent(array $options)
- {
- return 'hidden';
- }
-
- /**
- * Returns the name of this form.
- *
- * @return string 'csrf'
- */
- public function getName()
- {
- return 'csrf';
- }
-}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/DateTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/DateTypeCsrfExtension.php
deleted file mode 100644
index dc54e94ddf..0000000000
--- a/src/Symfony/Component/Form/Extension/Csrf/Type/DateTypeCsrfExtension.php
+++ /dev/null
@@ -1,27 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-
-class DateTypeCsrfExtension extends AbstractTypeExtension
-{
- public function getDefaultOptions()
- {
- return array('csrf_protection' => false);
- }
-
- public function getExtendedType()
- {
- return 'date';
- }
-}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
index 8e2a57459a..c8687d4af4 100644
--- a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
+++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
@@ -12,21 +12,27 @@
namespace Symfony\Component\Form\Extension\Csrf\Type;
use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\Form\Extension\Csrf\EventListener\EnsureCsrfFieldListener;
+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\FormEvents;
use Symfony\Component\Form\FormInterface;
+/**
+ * @author Bernhard Schussek
+ */
class FormTypeCsrfExtension extends AbstractTypeExtension
{
- private $enabled;
- private $fieldName;
+ private $defaultCsrfProvider;
+ private $defaultEnabled;
+ private $defaultFieldName;
- public function __construct($enabled = true, $fieldName = '_token')
+ public function __construct(CsrfProviderInterface $defaultCsrfProvider, $defaultEnabled = true, $defaultFieldName = '_token')
{
- $this->enabled = $enabled;
- $this->fieldName = $fieldName;
+ $this->defaultCsrfProvider = $defaultCsrfProvider;
+ $this->defaultEnabled = $defaultEnabled;
+ $this->defaultFieldName = $defaultFieldName;
}
/**
@@ -41,35 +47,35 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
return;
}
- $listener = new EnsureCsrfFieldListener(
- $builder->getFormFactory(),
- $options['csrf_field_name'],
- $options['intention'],
- $options['csrf_provider']
- );
-
// use a low priority so higher priority listeners don't remove the field
$builder
->setAttribute('csrf_field_name', $options['csrf_field_name'])
- ->addEventListener(FormEvents::PRE_SET_DATA, array($listener, 'ensureCsrfField'), -10)
- ->addEventListener(FormEvents::PRE_BIND, array($listener, 'ensureCsrfField'), -10)
+ ->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']))
;
}
/**
- * Removes CSRF fields from all the form views except the root one.
+ * Adds a CSRF field to the root form view.
*
* @param FormView $view The form view
* @param FormInterface $form The form
*/
- public function buildViewBottomUp(FormView $view, FormInterface $form)
+ public function buildView(FormView $view, FormInterface $form)
{
- if ($view->hasParent() && $form->hasAttribute('csrf_field_name')) {
+ if ($form->isRoot() && $form->hasChildren() && $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 (isset($view[$name])) {
- unset($view[$name]);
- }
+ $view->addChild($csrfForm->createView($view));
}
}
@@ -79,9 +85,9 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
public function getDefaultOptions()
{
return array(
- 'csrf_protection' => $this->enabled,
- 'csrf_field_name' => $this->fieldName,
- 'csrf_provider' => null,
+ 'csrf_protection' => $this->defaultEnabled,
+ 'csrf_field_name' => $this->defaultFieldName,
+ 'csrf_provider' => $this->defaultCsrfProvider,
'intention' => 'unknown',
);
}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/RepeatedTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/RepeatedTypeCsrfExtension.php
deleted file mode 100644
index 1115ea4d69..0000000000
--- a/src/Symfony/Component/Form/Extension/Csrf/Type/RepeatedTypeCsrfExtension.php
+++ /dev/null
@@ -1,27 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-
-class RepeatedTypeCsrfExtension extends AbstractTypeExtension
-{
- public function getDefaultOptions()
- {
- return array('csrf_protection' => false);
- }
-
- public function getExtendedType()
- {
- return 'repeated';
- }
-}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/TimeTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/TimeTypeCsrfExtension.php
deleted file mode 100644
index dbd7c0d2df..0000000000
--- a/src/Symfony/Component/Form/Extension/Csrf/Type/TimeTypeCsrfExtension.php
+++ /dev/null
@@ -1,27 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-
-class TimeTypeCsrfExtension extends AbstractTypeExtension
-{
- public function getDefaultOptions()
- {
- return array('csrf_protection' => false);
- }
-
- public function getExtendedType()
- {
- return 'time';
- }
-}
diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/FieldTypeValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
similarity index 95%
rename from src/Symfony/Component/Form/Extension/Validator/Type/FieldTypeValidatorExtension.php
rename to src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
index 8d0db3f4f6..77754669f3 100644
--- a/src/Symfony/Component/Form/Extension/Validator/Type/FieldTypeValidatorExtension.php
+++ b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
@@ -19,7 +19,7 @@ use Symfony\Component\Validator\ValidatorInterface;
/**
* @author Bernhard Schussek
*/
-class FieldTypeValidatorExtension extends AbstractTypeExtension
+class FormTypeValidatorExtension extends AbstractTypeExtension
{
private $validator;
@@ -57,6 +57,6 @@ class FieldTypeValidatorExtension extends AbstractTypeExtension
public function getExtendedType()
{
- return 'field';
+ return 'form';
}
}
diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
index 94b6ea699d..b4efa1679a 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
@@ -38,7 +38,7 @@ class ValidatorExtension extends AbstractExtension
protected function loadTypeExtensions()
{
return array(
- new Type\FieldTypeValidatorExtension($this->validator),
+ new Type\FormTypeValidatorExtension($this->validator),
);
}
}
diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php
index 8f9e7b6de2..5669e0ead4 100644
--- a/src/Symfony/Component/Form/Form.php
+++ b/src/Symfony/Component/Form/Form.php
@@ -191,7 +191,7 @@ class Form implements \IteratorAggregate, FormInterface
array $types = array(), array $clientTransformers = array(),
array $normTransformers = array(),
DataMapperInterface $dataMapper = null, array $validators = array(),
- $required = false, $disabled = false, $errorBubbling = false,
+ $required = false, $disabled = false, $errorBubbling = null,
$emptyData = null, array $attributes = array())
{
$name = (string) $name;
@@ -225,7 +225,10 @@ class Form implements \IteratorAggregate, FormInterface
$this->validators = $validators;
$this->required = (Boolean) $required;
$this->disabled = (Boolean) $disabled;
- $this->errorBubbling = (Boolean) $errorBubbling;
+ // NULL is the default meaning:
+ // bubble up if the form has children (complex forms)
+ // don't bubble up if the form has no children (primitive fields)
+ $this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
$this->emptyData = $emptyData;
$this->attributes = $attributes;
@@ -312,9 +315,9 @@ class Form implements \IteratorAggregate, FormInterface
}
/**
- * Returns the parent field.
+ * Returns the parent form.
*
- * @return FormInterface The parent field
+ * @return FormInterface The parent form
*/
public function getParent()
{
@@ -342,7 +345,7 @@ class Form implements \IteratorAggregate, FormInterface
}
/**
- * Returns whether the field is the root of the form tree.
+ * Returns whether the form is the root of the form tree.
*
* @return Boolean
*/
@@ -374,7 +377,7 @@ class Form implements \IteratorAggregate, FormInterface
}
/**
- * Updates the field with default data.
+ * Updates the form with default data.
*
* @param array $appData The data formatted as expected for the underlying object
*
@@ -408,7 +411,7 @@ class Form implements \IteratorAggregate, FormInterface
$this->clientData = $clientData;
$this->synchronized = true;
- if ($this->dataMapper) {
+ if (count($this->children) > 0 && $this->dataMapper) {
// Update child forms from the data
$this->dataMapper->mapDataToForms($clientData, $this->children);
}
@@ -450,7 +453,7 @@ class Form implements \IteratorAggregate, FormInterface
}
/**
- * Binds data to the field, transforms and validates it.
+ * Binds data to the form, transforms and validates it.
*
* @param string|array $clientData The data
*
@@ -626,11 +629,11 @@ class Form implements \IteratorAggregate, FormInterface
}
/**
- * Returns the normalized data of the field.
+ * Returns the normalized data of the form.
*
- * @return mixed When the field is not bound, the default data is returned.
- * When the field is bound, the normalized bound data is
- * returned if the field is valid, null otherwise.
+ * @return mixed When the form is not bound, the default data is returned.
+ * When the form is bound, the normalized bound data is
+ * returned if the form is valid, null otherwise.
*/
public function getNormData()
{
@@ -646,7 +649,7 @@ class Form implements \IteratorAggregate, FormInterface
*/
public function addError(FormError $error)
{
- if ($this->parent && $this->errorBubbling) {
+ if ($this->parent && $this->getErrorBubbling()) {
$this->parent->addError($error);
} else {
$this->errors[] = $error;
@@ -662,11 +665,11 @@ class Form implements \IteratorAggregate, FormInterface
*/
public function getErrorBubbling()
{
- return $this->errorBubbling;
+ return null === $this->errorBubbling ? $this->hasChildren() : $this->errorBubbling;
}
/**
- * Returns whether the field is bound.
+ * Returns whether the form is bound.
*
* @return Boolean true if the form is bound to input values, false otherwise
*/
@@ -702,7 +705,7 @@ class Form implements \IteratorAggregate, FormInterface
}
/**
- * Returns whether the field is valid.
+ * Returns whether the form is valid.
*
* @return Boolean
*/
@@ -735,9 +738,8 @@ class Form implements \IteratorAggregate, FormInterface
public function hasErrors()
{
// Don't call isValid() here, as its semantics are slightly different
- // Field groups are not valid if their children are invalid, but
- // hasErrors() returns only true if a field/field group itself has
- // errors
+ // Forms are not valid if their children are invalid, but
+ // hasErrors() returns only true if a form itself has errors
return count($this->errors) > 0;
}
@@ -894,7 +896,7 @@ class Form implements \IteratorAggregate, FormInterface
return $this->children[$name];
}
- throw new \InvalidArgumentException(sprintf('Field "%s" does not exist.', $name));
+ throw new \InvalidArgumentException(sprintf('Child "%s" does not exist.', $name));
}
/**
@@ -975,7 +977,7 @@ class Form implements \IteratorAggregate, FormInterface
$parent = $this->parent->createView();
}
- $view = new FormView();
+ $view = new FormView($this->name);
$view->setParent($parent);
@@ -989,14 +991,10 @@ class Form implements \IteratorAggregate, FormInterface
}
}
- $childViews = array();
-
- foreach ($this->children as $key => $child) {
- $childViews[$key] = $child->createView($view);
+ foreach ($this->children as $child) {
+ $view->addChild($child->createView($view));
}
- $view->setChildren($childViews);
-
foreach ($types as $type) {
$type->buildViewBottomUp($view, $this);
diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php
index 208a518518..b8f7da16c6 100644
--- a/src/Symfony/Component/Form/FormBuilder.php
+++ b/src/Symfony/Component/Form/FormBuilder.php
@@ -106,7 +106,7 @@ class FormBuilder
* Whether added errors should bubble up to the parent
* @var Boolean
*/
- private $errorBubbling = false;
+ private $errorBubbling;
/**
* Data used for the client data when no value is bound
@@ -243,7 +243,7 @@ class FormBuilder
*/
public function setErrorBubbling($errorBubbling)
{
- $this->errorBubbling = (Boolean) $errorBubbling;
+ $this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
return $this;
}
diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php
index d0d8a80a8d..f3ca837356 100644
--- a/src/Symfony/Component/Form/FormInterface.php
+++ b/src/Symfony/Component/Form/FormInterface.php
@@ -183,7 +183,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
* The content of a disabled form is displayed, but not allowed to be
* modified. The validation of modified disabled forms should fail.
*
- * Fields whose parents are disabled are considered disabled regardless of
+ * Forms whose parents are disabled are considered disabled regardless of
* their own state.
*
* @return Boolean
diff --git a/src/Symfony/Component/Form/FormTypeGuesserChain.php b/src/Symfony/Component/Form/FormTypeGuesserChain.php
index b3ca91a460..9d915698ca 100644
--- a/src/Symfony/Component/Form/FormTypeGuesserChain.php
+++ b/src/Symfony/Component/Form/FormTypeGuesserChain.php
@@ -75,7 +75,7 @@ class FormTypeGuesserChain implements FormTypeGuesserInterface
* @param \Closure $closure The closure to execute. Accepts a guesser
* as argument and should return a Guess instance
*
- * @return FieldFactoryGuess The guess with the highest confidence
+ * @return Guess The guess with the highest confidence
*/
private function guess(\Closure $closure)
{
diff --git a/src/Symfony/Component/Form/FormView.php b/src/Symfony/Component/Form/FormView.php
index 5c8ab13da1..5d88346edc 100644
--- a/src/Symfony/Component/Form/FormView.php
+++ b/src/Symfony/Component/Form/FormView.php
@@ -11,8 +11,17 @@
namespace Symfony\Component\Form;
-class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
+use ArrayAccess;
+use IteratorAggregate;
+use Countable;
+
+/**
+ * @author Bernhard Schussek
+ */
+class FormView implements ArrayAccess, IteratorAggregate, Countable
{
+ private $name;
+
private $vars = array(
'value' => null,
'attr' => array(),
@@ -33,6 +42,16 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
*/
private $rendered = false;
+ public function __construct($name)
+ {
+ $this->name = $name;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
/**
* @param string $name
* @param mixed $value
@@ -177,15 +196,29 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
}
/**
- * Sets the children view.
+ * Adds a child view.
*
- * @param array $children The children as instances of FormView
+ * @param FormView $child The child view to add.
*
* @return FormView The current view
*/
- public function setChildren(array $children)
+ public function addChild(FormView $child)
{
- $this->children = $children;
+ $this->children[$child->getName()] = $child;
+
+ return $this;
+ }
+
+ /**
+ * Removes a child view.
+ *
+ * @param string $name The name of the removed child view.
+ *
+ * @return FormView The current view
+ */
+ public function removeChild($name)
+ {
+ unset($this->children[$name]);
return $this;
}
@@ -222,6 +255,18 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
return count($this->children) > 0;
}
+ /**
+ * 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
+ */
+ public function hasChild($name)
+ {
+ return isset($this->children[$name]);
+ }
+
/**
* Returns a child by name (implements \ArrayAccess).
*
diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
index d22113245a..7d1512f003 100644
--- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
@@ -202,7 +202,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
);
}
- public function testRestAndRepeatedWithRowPerField()
+ public function testRestAndRepeatedWithRowPerChild()
{
$view = $this->factory->createNamedBuilder('form', 'name')
->add('first', 'text')
@@ -230,7 +230,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
);
}
- public function testRestAndRepeatedWithWidgetPerField()
+ public function testRestAndRepeatedWithWidgetPerChild()
{
$view = $this->factory->createNamedBuilder('form', 'name')
->add('first', 'text')
@@ -348,7 +348,10 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testNestedFormError()
{
$form = $this->factory->createNamedBuilder('form', 'name')
- ->add('child', 'form', array('error_bubbling' => false))
+ ->add($this->factory
+ ->createNamedBuilder('form', 'child', null, array('error_bubbling' => false))
+ ->add('grandChild', 'form')
+ )
->getForm();
$form->get('child')->addError(new FormError('Error!'));
@@ -363,6 +366,31 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
);
}
+ public function testCsrf()
+ {
+ $this->csrfProvider->expects($this->any())
+ ->method('generateCsrfToken')
+ ->will($this->returnValue('foo&bar'));
+
+ $form = $this->factory->createNamedBuilder('form', 'name')
+ ->add($this->factory
+ // No CSRF protection on nested forms
+ ->createNamedBuilder('form', 'child')
+ ->add($this->factory->createNamedBuilder('text', 'grandchild'))
+ )
+ ->getForm();
+
+ $this->assertWidgetMatchesXpath($form->createView(), array(),
+'/div
+ [
+ ./input[@type="hidden"][@id="name__token"][@value="foo&bar"]
+ /following-sibling::div
+ ]
+ [count(.//input[@type="hidden"])=1]
+'
+ );
+ }
+
public function testRepeated()
{
$form = $this->factory->createNamed('repeated', 'name', 'foobar', array(
@@ -372,7 +400,8 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
- ./div
+ ./input[@type="hidden"][@id="name__token"]
+ /following-sibling::div
[
./label[@for="name_first"]
/following-sibling::input[@type="text"][@id="name_first"]
@@ -383,7 +412,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
/following-sibling::input[@type="text"][@id="name_second"]
]
]
- [count(.//input)=2]
+ [count(.//input)=3]
'
);
}
@@ -399,7 +428,8 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
- ./div
+ ./input[@type="hidden"][@id="name__token"]
+ /following-sibling::div
[
./label[@for="name_first"][.="[trans]Test[/trans]"]
/following-sibling::input[@type="text"][@id="name_first"][@required="required"]
@@ -410,7 +440,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
/following-sibling::input[@type="text"][@id="name_second"][@required="required"]
]
]
- [count(.//input)=2]
+ [count(.//input)=3]
'
);
}
diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php
index 32aabb86a6..5d48b9921c 100644
--- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php
@@ -646,12 +646,13 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
- ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
+ ./input[@type="hidden"][@id="name__token"]
+ /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
]
- [count(./input)=2]
+ [count(./input)=3]
'
);
}
@@ -668,12 +669,13 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
- ./input[@type="radio"][@name="name"][@id="name_0"][@checked]
+ ./input[@type="hidden"][@id="name__token"]
+ /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@checked]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
]
- [count(./input)=2]
+ [count(./input)=3]
'
);
}
@@ -689,12 +691,13 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
- ./input[@type="radio"][@name="name"][@id="name_0"][@checked]
+ ./input[@type="hidden"][@id="name__token"]
+ /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@checked]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
]
- [count(./input)=2]
+ [count(./input)=3]
'
);
}
@@ -711,14 +714,15 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
- ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
+ ./input[@type="hidden"][@id="name__token"]
+ /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
/following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
/following-sibling::label[@for="name_2"][.="[trans]Choice&C[/trans]"]
]
- [count(./input)=3]
+ [count(./input)=4]
'
);
}
@@ -753,22 +757,6 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
);
}
- public function testCsrf()
- {
- $this->csrfProvider->expects($this->any())
- ->method('generateCsrfToken')
- ->will($this->returnValue('foo&bar'));
-
- $form = $this->factory->createNamed('csrf', 'name');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="hidden"]
- [@value="foo&bar"]
-'
- );
- }
-
public function testDateTime()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
diff --git a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
index d47b15564f..0943b06c41 100644
--- a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
@@ -45,36 +45,10 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
$html = $this->renderRow($form->createView());
$this->assertMatchesXpath($html,
-'/tr
- [
- ./td
- [./label[@for="name_first"]]
- /following-sibling::td
- [./input[@id="name_first"]]
- ]
-/following-sibling::tr
- [
- ./td
- [./label[@for="name_second"]]
- /following-sibling::td
- [./input[@id="name_second"]]
- ]
- [count(../tr)=2]
-'
- );
- }
-
- public function testRepeatedRowWithErrors()
- {
- $form = $this->factory->createNamed('repeated', 'name');
- $form->addError(new FormError('Error!'));
- $view = $form->createView();
- $html = $this->renderRow($view);
-
- $this->assertMatchesXpath($html,
-'/tr
- [./td[@colspan="2"]/ul
- [./li[.="[trans]Error![/trans]"]]
+'/tr[@style="display: none"]
+ [./td[@colspan="2"]/input
+ [@type="hidden"]
+ [@id="name__token"]
]
/following-sibling::tr
[
@@ -95,6 +69,42 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
);
}
+ public function testRepeatedRowWithErrors()
+ {
+ $form = $this->factory->createNamed('repeated', 'name');
+ $form->addError(new FormError('Error!'));
+ $view = $form->createView();
+ $html = $this->renderRow($view);
+
+ $this->assertMatchesXpath($html,
+'/tr
+ [./td[@colspan="2"]/ul
+ [./li[.="[trans]Error![/trans]"]]
+ ]
+/following-sibling::tr[@style="display: none"]
+ [./td[@colspan="2"]/input
+ [@type="hidden"]
+ [@id="name__token"]
+ ]
+/following-sibling::tr
+ [
+ ./td
+ [./label[@for="name_first"]]
+ /following-sibling::td
+ [./input[@id="name_first"]]
+ ]
+/following-sibling::tr
+ [
+ ./td
+ [./label[@for="name_second"]]
+ /following-sibling::td
+ [./input[@id="name_second"]]
+ ]
+ [count(../tr)=4]
+'
+ );
+ }
+
public function testRest()
{
$view = $this->factory->createNamedBuilder('form', 'name')
@@ -151,9 +161,9 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/table
[
- ./tr[./td/input[@type="text"][@value="a"]]
+ ./tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="name__token"]]
+ /following-sibling::tr[./td/input[@type="text"][@value="a"]]
/following-sibling::tr[./td/input[@type="text"][@value="b"]]
- /following-sibling::tr[./td/input[@type="hidden"][@id="name__token"]]
]
[count(./tr[./td/input])=3]
'
@@ -200,7 +210,10 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testNestedFormError()
{
$form = $this->factory->createNamedBuilder('form', 'name')
- ->add('child', 'form', array('error_bubbling' => false))
+ ->add($this->factory
+ ->createNamedBuilder('form', 'child', null, array('error_bubbling' => false))
+ ->add('grandChild', 'form')
+ )
->getForm();
$form->get('child')->addError(new FormError('Error!'));
@@ -217,6 +230,34 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
);
}
+ public function testCsrf()
+ {
+ $this->csrfProvider->expects($this->any())
+ ->method('generateCsrfToken')
+ ->will($this->returnValue('foo&bar'));
+
+ $form = $this->factory->createNamedBuilder('form', 'name')
+ ->add($this->factory
+ // No CSRF protection on nested forms
+ ->createNamedBuilder('form', 'child')
+ ->add($this->factory->createNamedBuilder('text', 'grandchild'))
+ )
+ ->getForm();
+
+ $this->assertWidgetMatchesXpath($form->createView(), array(),
+'/table
+ [
+ ./tr[@style="display: none"]
+ [./td[@colspan="2"]/input
+ [@type="hidden"]
+ [@id="name__token"]
+ ]
+ ]
+ [count(.//input[@type="hidden"])=1]
+'
+ );
+ }
+
public function testRepeated()
{
$form = $this->factory->createNamed('repeated', 'name', 'foobar', array(
@@ -226,7 +267,12 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/table
[
- ./tr
+ ./tr[@style="display: none"]
+ [./td[@colspan="2"]/input
+ [@type="hidden"]
+ [@id="name__token"]
+ ]
+ /following-sibling::tr
[
./td
[./label[@for="name_first"]]
@@ -241,7 +287,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
[./input[@type="text"][@id="name_second"]]
]
]
- [count(.//input)=2]
+ [count(.//input)=3]
'
);
}
@@ -257,7 +303,12 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/table
[
- ./tr
+ ./tr[@style="display: none"]
+ [./td[@colspan="2"]/input
+ [@type="hidden"]
+ [@id="name__token"]
+ ]
+ /following-sibling::tr
[
./td
[./label[@for="name_first"][.="[trans]Test[/trans]"]]
@@ -272,7 +323,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
[./input[@type="password"][@id="name_second"][@required="required"]]
]
]
- [count(.//input)=2]
+ [count(.//input)=3]
'
);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
index 9cf54e25ed..fbda65a3b6 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
@@ -98,7 +98,7 @@ class ChoiceTypeTest extends TypeTestCase
));
}
- public function testExpandedChoicesOptionsTurnIntoFields()
+ public function testExpandedChoicesOptionsTurnIntoChildren()
{
$form = $this->factory->create('choice', null, array(
'expanded' => true,
@@ -141,7 +141,7 @@ class ChoiceTypeTest extends TypeTestCase
}
}
- public function testExpandedRadiosAreRequiredIfChoiceFieldIsRequired()
+ public function testExpandedRadiosAreRequiredIfChoiceChildIsRequired()
{
$form = $this->factory->create('choice', null, array(
'multiple' => false,
@@ -155,7 +155,7 @@ class ChoiceTypeTest extends TypeTestCase
}
}
- public function testExpandedRadiosAreNotRequiredIfChoiceFieldIsNotRequired()
+ public function testExpandedRadiosAreNotRequiredIfChoiceChildIsNotRequired()
{
$form = $this->factory->create('choice', null, array(
'multiple' => false,
@@ -288,7 +288,7 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertNull($form[4]->getClientData());
}
- public function testBindSingleExpandedWithFalseDoesNotHaveExtraFields()
+ public function testBindSingleExpandedWithFalseDoesNotHaveExtraChildren()
{
$form = $this->factory->create('choice', null, array(
'multiple' => false,
@@ -302,7 +302,7 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertNull($form->getData());
}
- public function testBindSingleExpandedWithEmptyField()
+ public function testBindSingleExpandedWithEmptyChild()
{
$form = $this->factory->create('choice', null, array(
'multiple' => false,
@@ -422,7 +422,7 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertNull($form[4]->getClientData());
}
- public function testBindMultipleExpandedWithEmptyField()
+ public function testBindMultipleExpandedWithEmptyChild()
{
$form = $this->factory->create('choice', null, array(
'multiple' => true,
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
index b0bb62508f..5461258e95 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
@@ -15,10 +15,10 @@ use Symfony\Component\Form\Form;
class CollectionTypeTest extends TypeTestCase
{
- public function testContainsNoFieldByDefault()
+ public function testContainsNoChildByDefault()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
));
$this->assertCount(0, $form);
@@ -27,7 +27,7 @@ class CollectionTypeTest extends TypeTestCase
public function testSetDataAdjustsSize()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'options' => array(
'max_length' => 20,
),
@@ -53,7 +53,7 @@ class CollectionTypeTest extends TypeTestCase
public function testThrowsExceptionIfObjectIsNotTraversable()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
));
$this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
$form->setData(new \stdClass());
@@ -62,7 +62,7 @@ class CollectionTypeTest extends TypeTestCase
public function testNotResizedIfBoundWithMissingData()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
));
$form->setData(array('foo@foo.com', 'bar@bar.com'));
$form->bind(array('foo@bar.com'));
@@ -76,7 +76,7 @@ class CollectionTypeTest extends TypeTestCase
public function testResizedDownIfBoundWithMissingDataAndAllowDelete()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'allow_delete' => true,
));
$form->setData(array('foo@foo.com', 'bar@bar.com'));
@@ -91,7 +91,7 @@ class CollectionTypeTest extends TypeTestCase
public function testNotResizedIfBoundWithExtraData()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
));
$form->setData(array('foo@bar.com'));
$form->bind(array('foo@foo.com', 'bar@bar.com'));
@@ -104,7 +104,7 @@ class CollectionTypeTest extends TypeTestCase
public function testResizedUpIfBoundWithExtraDataAndAllowAdd()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'allow_add' => true,
));
$form->setData(array('foo@bar.com'));
@@ -120,7 +120,7 @@ class CollectionTypeTest extends TypeTestCase
public function testAllowAddButNoPrototype()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'allow_add' => true,
'prototype' => false,
));
@@ -169,7 +169,7 @@ class CollectionTypeTest extends TypeTestCase
public function testPrototypeNameOption()
{
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'prototype' => true,
'allow_add' => true,
));
@@ -177,7 +177,7 @@ class CollectionTypeTest extends TypeTestCase
$this->assertSame('__name__', $form->getAttribute('prototype')->getName(), '__name__ is the default');
$form = $this->factory->create('collection', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'prototype' => true,
'allow_add' => true,
'prototype_name' => '__test__',
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FieldTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FieldTypeTest.php
deleted file mode 100644
index b588d4433f..0000000000
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FieldTypeTest.php
+++ /dev/null
@@ -1,380 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Util\PropertyPath;
-use Symfony\Component\Form\Form;
-use Symfony\Component\Form\Tests\Fixtures\Author;
-use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
-
-class FieldTypeTest extends TypeTestCase
-{
- public function testGetPropertyPathDefaultPath()
- {
- $form = $this->factory->createNamed('field', 'title');
-
- $this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
- }
-
- public function testGetPropertyPathPathIsZero()
- {
- $form = $this->factory->create('field', null, array('property_path' => '0'));
-
- $this->assertEquals(new PropertyPath('0'), $form->getAttribute('property_path'));
- }
-
- public function testGetPropertyPathPathIsEmpty()
- {
- $form = $this->factory->create('field', null, array('property_path' => ''));
-
- $this->assertNull($form->getAttribute('property_path'));
- }
-
- public function testGetPropertyPathPathIsFalse()
- {
- $form = $this->factory->create('field', null, array('property_path' => false));
-
- $this->assertNull($form->getAttribute('property_path'));
- }
-
- public function testGetPropertyPathPathIsNull()
- {
- $form = $this->factory->createNamed('field', 'title', null, array('property_path' => null));
-
- $this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
- }
-
- public function testPassRequiredAsOption()
- {
- $form = $this->factory->create('field', null, array('required' => false));
-
- $this->assertFalse($form->isRequired());
-
- $form = $this->factory->create('field', null, array('required' => true));
-
- $this->assertTrue($form->isRequired());
- }
-
- public function testPassDisabledAsOption()
- {
- $form = $this->factory->create('field', null, array('disabled' => true));
-
- $this->assertTrue($form->isDisabled());
- }
-
- public function testBoundDataIsTrimmedBeforeTransforming()
- {
- $form = $this->factory->createBuilder('field')
- ->appendClientTransformer(new FixedDataTransformer(array(
- null => '',
- 'reverse[a]' => 'a',
- )))
- ->getForm();
-
- $form->bind(' a ');
-
- $this->assertEquals('a', $form->getClientData());
- $this->assertEquals('reverse[a]', $form->getData());
- }
-
- public function testBoundDataIsNotTrimmedBeforeTransformingIfNoTrimming()
- {
- $form = $this->factory->createBuilder('field', null, array('trim' => false))
- ->appendClientTransformer(new FixedDataTransformer(array(
- null => '',
- 'reverse[ a ]' => ' a ',
- )))
- ->getForm();
-
- $form->bind(' a ');
-
- $this->assertEquals(' a ', $form->getClientData());
- $this->assertEquals('reverse[ a ]', $form->getData());
- }
-
- public function testPassIdAndNameToView()
- {
- $form = $this->factory->createNamed('field', 'name');
- $view = $form->createView();
-
- $this->assertEquals('name', $view->get('id'));
- $this->assertEquals('name', $view->get('name'));
- $this->assertEquals('name', $view->get('full_name'));
- }
-
- public function testStripLeadingUnderscoresAndDigitsFromId()
- {
- $form = $this->factory->createNamed('field', '_09name');
- $view = $form->createView();
-
- $this->assertEquals('name', $view->get('id'));
- $this->assertEquals('_09name', $view->get('name'));
- $this->assertEquals('_09name', $view->get('full_name'));
- }
-
- public function testPassIdAndNameToViewWithParent()
- {
- $parent = $this->factory->createNamed('field', 'parent');
- $parent->add($this->factory->createNamed('field', 'child'));
- $view = $parent->createView();
-
- $this->assertEquals('parent_child', $view['child']->get('id'));
- $this->assertEquals('child', $view['child']->get('name'));
- $this->assertEquals('parent[child]', $view['child']->get('full_name'));
- }
-
- public function testPassIdAndNameToViewWithGrandParent()
- {
- $parent = $this->factory->createNamed('field', 'parent');
- $parent->add($this->factory->createNamed('field', 'child'));
- $parent['child']->add($this->factory->createNamed('field', 'grand_child'));
- $view = $parent->createView();
-
- $this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->get('id'));
- $this->assertEquals('grand_child', $view['child']['grand_child']->get('name'));
- $this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->get('full_name'));
- }
-
- public function testNonReadOnlyFieldWithReadOnlyParentBeingReadOnly()
- {
- $parent = $this->factory->createNamed('field', 'parent', null, array('read_only' => true));
- $child = $this->factory->createNamed('field', 'child');
- $view = $parent->add($child)->createView();
-
- $this->assertTrue($view['child']->get('read_only'));
- }
-
- public function testReadOnlyFieldWithNonReadOnlyParentBeingReadOnly()
- {
- $parent = $this->factory->createNamed('field', 'parent');
- $child = $this->factory->createNamed('field', 'child', null, array('read_only' => true));
- $view = $parent->add($child)->createView();
-
- $this->assertTrue($view['child']->get('read_only'));
- }
-
- public function testNonReadOnlyFieldWithNonReadOnlyParentBeingNonReadOnly()
- {
- $parent = $this->factory->createNamed('field', 'parent');
- $child = $this->factory->createNamed('field', 'child');
- $view = $parent->add($child)->createView();
-
- $this->assertFalse($view['child']->get('read_only'));
- }
-
- public function testPassMaxLengthToView()
- {
- $form = $this->factory->create('field', null, array('max_length' => 10));
- $view = $form->createView();
-
- $this->assertSame(10, $view->get('max_length'));
- }
-
- public function testPassTranslationDomainToView()
- {
- $form = $this->factory->create('field', null, array('translation_domain' => 'test'));
- $view = $form->createView();
-
- $this->assertSame('test', $view->get('translation_domain'));
- }
-
- public function testPassDefaultLabelToView()
- {
- $form = $this->factory->createNamed('field', '__test___field');
- $view = $form->createView();
-
- $this->assertSame('Test field', $view->get('label'));
- }
-
- public function testPassLabelToView()
- {
- $form = $this->factory->createNamed('field', '__test___field', null, array('label' => 'My label'));
- $view = $form->createView();
-
- $this->assertSame('My label', $view->get('label'));
- }
-
- public function testDefaultTranslationDomain()
- {
- $form = $this->factory->create('field');
- $view = $form->createView();
-
- $this->assertSame('messages', $view->get('translation_domain'));
- }
-
- public function testBindWithEmptyDataCreatesObjectIfClassAvailable()
- {
- $form = $this->factory->create('form', null, array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'required' => false,
- ));
- $form->add($this->factory->createNamed('field', 'firstName'));
- $form->add($this->factory->createNamed('field', 'lastName'));
-
- $form->setData(null);
- // partially empty, still an object is created
- $form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
-
- $author = new Author();
- $author->firstName = 'Bernhard';
- $author->setLastName('');
-
- $this->assertEquals($author, $form->getData());
- }
-
- public function testBindWithEmptyDataCreatesObjectIfInitiallyBoundWithObject()
- {
- $form = $this->factory->create('form', null, array(
- // data class is inferred from the passed object
- 'data' => new Author(),
- 'required' => false,
- ));
- $form->add($this->factory->createNamed('field', 'firstName'));
- $form->add($this->factory->createNamed('field', 'lastName'));
-
- $form->setData(null);
- // partially empty, still an object is created
- $form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
-
- $author = new Author();
- $author->firstName = 'Bernhard';
- $author->setLastName('');
-
- $this->assertEquals($author, $form->getData());
- }
-
- public function testBindWithEmptyDataDoesNotCreateObjectIfDataClassIsNull()
- {
- $form = $this->factory->create('form', null, array(
- 'data' => new Author(),
- 'data_class' => null,
- 'required' => false,
- ));
- $form->add($this->factory->createNamed('field', 'firstName'));
-
- $form->setData(null);
- $form->bind(array('firstName' => 'Bernhard'));
-
- $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
- }
-
- public function testBindEmptyWithEmptyDataCreatesNoObjectIfNotRequired()
- {
- $form = $this->factory->create('form', null, array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'required' => false,
- ));
- $form->add($this->factory->createNamed('field', 'firstName'));
- $form->add($this->factory->createNamed('field', 'lastName'));
-
- $form->setData(null);
- $form->bind(array('firstName' => '', 'lastName' => ''));
-
- $this->assertNull($form->getData());
- }
-
- public function testBindEmptyWithEmptyDataCreatesObjectIfRequired()
- {
- $form = $this->factory->create('form', null, array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'required' => true,
- ));
- $form->add($this->factory->createNamed('field', 'firstName'));
- $form->add($this->factory->createNamed('field', 'lastName'));
-
- $form->setData(null);
- $form->bind(array('firstName' => '', 'lastName' => ''));
-
- $this->assertEquals(new Author(), $form->getData());
- }
-
- /*
- * We need something to write the field values into
- */
- public function testBindWithEmptyDataStoresArrayIfNoClassAvailable()
- {
- $form = $this->factory->create('form');
- $form->add($this->factory->createNamed('field', 'firstName'));
-
- $form->setData(null);
- $form->bind(array('firstName' => 'Bernhard'));
-
- $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
- }
-
- public function testBindWithEmptyDataUsesEmptyDataOption()
- {
- $author = new Author();
-
- $form = $this->factory->create('form', null, array(
- 'empty_data' => $author,
- ));
- $form->add($this->factory->createNamed('field', 'firstName'));
-
- $form->bind(array('firstName' => 'Bernhard'));
-
- $this->assertSame($author, $form->getData());
- $this->assertEquals('Bernhard', $author->firstName);
- }
-
- public function testGetAttributesIsEmpty()
- {
- $form = $this->factory->create('field', null, array('attr' => array()));
-
- $this->assertCount(0, $form->getAttribute('attr'));
- }
-
- /**
- * @see https://github.com/symfony/symfony/issues/1986
- */
- public function testSetDataThroughParamsWithZero()
- {
- $form = $this->factory->create('field', null, array('data' => 0));
- $view = $form->createView();
-
- $this->assertFalse($form->isEmpty());
-
- $this->assertSame('0', $view->get('value'));
- $this->assertSame('0', $form->getData());
-
- $form = $this->factory->create('field', null, array('data' => '0'));
- $view = $form->createView();
-
- $this->assertFalse($form->isEmpty());
-
- $this->assertSame('0', $view->get('value'));
- $this->assertSame('0', $form->getData());
-
- $form = $this->factory->create('field', null, array('data' => '00000'));
- $view = $form->createView();
-
- $this->assertFalse($form->isEmpty());
-
- $this->assertSame('00000', $view->get('value'));
- $this->assertSame('00000', $form->getData());
- }
-
- /**
- * @expectedException Symfony\Component\Form\Exception\FormException
- */
- public function testAttributesException()
- {
- $form = $this->factory->create('field', null, array('attr' => ''));
- }
-
- public function testNameCanBeEmptyString()
- {
- $form = $this->factory->createNamed('field', '');
-
- $this->assertEquals('', $form->getName());
- }
-}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php
index eff0719692..8275c61455 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php
@@ -11,9 +11,11 @@
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
+use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Tests\Fixtures\Author;
+use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
class FormTest_AuthorWithoutRefSetter
{
@@ -49,13 +51,388 @@ class FormTest_AuthorWithoutRefSetter
class FormTypeTest extends TypeTestCase
{
+ public function testGetPropertyPathDefaultPath()
+ {
+ $form = $this->factory->createNamed('form', 'title');
+
+ $this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
+ }
+
+ public function testGetPropertyPathPathIsZero()
+ {
+ $form = $this->factory->create('form', null, array('property_path' => '0'));
+
+ $this->assertEquals(new PropertyPath('0'), $form->getAttribute('property_path'));
+ }
+
+ public function testGetPropertyPathPathIsEmpty()
+ {
+ $form = $this->factory->create('form', null, array('property_path' => ''));
+
+ $this->assertNull($form->getAttribute('property_path'));
+ }
+
+ public function testGetPropertyPathPathIsFalse()
+ {
+ $form = $this->factory->create('form', null, array('property_path' => false));
+
+ $this->assertNull($form->getAttribute('property_path'));
+ }
+
+ public function testGetPropertyPathPathIsNull()
+ {
+ $form = $this->factory->createNamed('form', 'title', null, array('property_path' => null));
+
+ $this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
+ }
+
+ public function testPassRequiredAsOption()
+ {
+ $form = $this->factory->create('form', null, array('required' => false));
+
+ $this->assertFalse($form->isRequired());
+
+ $form = $this->factory->create('form', null, array('required' => true));
+
+ $this->assertTrue($form->isRequired());
+ }
+
+ public function testPassDisabledAsOption()
+ {
+ $form = $this->factory->create('form', null, array('disabled' => true));
+
+ $this->assertTrue($form->isDisabled());
+ }
+
+ public function testBoundDataIsTrimmedBeforeTransforming()
+ {
+ $form = $this->factory->createBuilder('form')
+ ->appendClientTransformer(new FixedDataTransformer(array(
+ null => '',
+ 'reverse[a]' => 'a',
+ )))
+ ->getForm();
+
+ $form->bind(' a ');
+
+ $this->assertEquals('a', $form->getClientData());
+ $this->assertEquals('reverse[a]', $form->getData());
+ }
+
+ public function testBoundDataIsNotTrimmedBeforeTransformingIfNoTrimming()
+ {
+ $form = $this->factory->createBuilder('form', null, array('trim' => false))
+ ->appendClientTransformer(new FixedDataTransformer(array(
+ null => '',
+ 'reverse[ a ]' => ' a ',
+ )))
+ ->getForm();
+
+ $form->bind(' a ');
+
+ $this->assertEquals(' a ', $form->getClientData());
+ $this->assertEquals('reverse[ a ]', $form->getData());
+ }
+
+ public function testPassIdAndNameToView()
+ {
+ $form = $this->factory->createNamed('form', 'name');
+ $view = $form->createView();
+
+ $this->assertEquals('name', $view->get('id'));
+ $this->assertEquals('name', $view->get('name'));
+ $this->assertEquals('name', $view->get('full_name'));
+ }
+
+ public function testStripLeadingUnderscoresAndDigitsFromId()
+ {
+ $form = $this->factory->createNamed('form', '_09name');
+ $view = $form->createView();
+
+ $this->assertEquals('name', $view->get('id'));
+ $this->assertEquals('_09name', $view->get('name'));
+ $this->assertEquals('_09name', $view->get('full_name'));
+ }
+
+ public function testPassIdAndNameToViewWithParent()
+ {
+ $parent = $this->factory->createNamed('form', 'parent');
+ $parent->add($this->factory->createNamed('form', 'child'));
+ $view = $parent->createView();
+
+ $this->assertEquals('parent_child', $view['child']->get('id'));
+ $this->assertEquals('child', $view['child']->get('name'));
+ $this->assertEquals('parent[child]', $view['child']->get('full_name'));
+ }
+
+ public function testPassIdAndNameToViewWithGrandParent()
+ {
+ $parent = $this->factory->createNamed('form', 'parent');
+ $parent->add($this->factory->createNamed('form', 'child'));
+ $parent['child']->add($this->factory->createNamed('form', 'grand_child'));
+ $view = $parent->createView();
+
+ $this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->get('id'));
+ $this->assertEquals('grand_child', $view['child']['grand_child']->get('name'));
+ $this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->get('full_name'));
+ }
+
+ public function testNonReadOnlyFormWithReadOnlyParentBeingReadOnly()
+ {
+ $parent = $this->factory->createNamed('form', 'parent', null, array('read_only' => true));
+ $child = $this->factory->createNamed('form', 'child');
+ $view = $parent->add($child)->createView();
+
+ $this->assertTrue($view['child']->get('read_only'));
+ }
+
+ public function testReadOnlyFormWithNonReadOnlyParentBeingReadOnly()
+ {
+ $parent = $this->factory->createNamed('form', 'parent');
+ $child = $this->factory->createNamed('form', 'child', null, array('read_only' => true));
+ $view = $parent->add($child)->createView();
+
+ $this->assertTrue($view['child']->get('read_only'));
+ }
+
+ public function testNonReadOnlyFormWithNonReadOnlyParentBeingNonReadOnly()
+ {
+ $parent = $this->factory->createNamed('form', 'parent');
+ $child = $this->factory->createNamed('form', 'child');
+ $view = $parent->add($child)->createView();
+
+ $this->assertFalse($view['child']->get('read_only'));
+ }
+
+ public function testPassMaxLengthToView()
+ {
+ $form = $this->factory->create('form', null, array('max_length' => 10));
+ $view = $form->createView();
+
+ $this->assertSame(10, $view->get('max_length'));
+ }
+
+ public function testPassTranslationDomainToView()
+ {
+ $form = $this->factory->create('form', null, array('translation_domain' => 'test'));
+ $view = $form->createView();
+
+ $this->assertSame('test', $view->get('translation_domain'));
+ }
+
+ public function testPassDefaultLabelToView()
+ {
+ $form = $this->factory->createNamed('form', '__test___field');
+ $view = $form->createView();
+
+ $this->assertSame('Test field', $view->get('label'));
+ }
+
+ public function testPassLabelToView()
+ {
+ $form = $this->factory->createNamed('form', '__test___field', null, array('label' => 'My label'));
+ $view = $form->createView();
+
+ $this->assertSame('My label', $view->get('label'));
+ }
+
+ public function testDefaultTranslationDomain()
+ {
+ $form = $this->factory->create('form');
+ $view = $form->createView();
+
+ $this->assertSame('messages', $view->get('translation_domain'));
+ }
+
+ public function testBindWithEmptyDataCreatesObjectIfClassAvailable()
+ {
+ $form = $this->factory->create('form', null, array(
+ 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
+ 'required' => false,
+ ));
+ $form->add($this->factory->createNamed('form', 'firstName'));
+ $form->add($this->factory->createNamed('form', 'lastName'));
+
+ $form->setData(null);
+ // partially empty, still an object is created
+ $form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
+
+ $author = new Author();
+ $author->firstName = 'Bernhard';
+ $author->setLastName('');
+
+ $this->assertEquals($author, $form->getData());
+ }
+
+ public function testBindWithEmptyDataCreatesObjectIfInitiallyBoundWithObject()
+ {
+ $form = $this->factory->create('form', null, array(
+ // data class is inferred from the passed object
+ 'data' => new Author(),
+ 'required' => false,
+ ));
+ $form->add($this->factory->createNamed('form', 'firstName'));
+ $form->add($this->factory->createNamed('form', 'lastName'));
+
+ $form->setData(null);
+ // partially empty, still an object is created
+ $form->bind(array('firstName' => 'Bernhard', 'lastName' => ''));
+
+ $author = new Author();
+ $author->firstName = 'Bernhard';
+ $author->setLastName('');
+
+ $this->assertEquals($author, $form->getData());
+ }
+
+ public function testBindWithEmptyDataDoesNotCreateObjectIfDataClassIsNull()
+ {
+ $form = $this->factory->create('form', null, array(
+ 'data' => new Author(),
+ 'data_class' => null,
+ 'required' => false,
+ ));
+ $form->add($this->factory->createNamed('form', 'firstName'));
+
+ $form->setData(null);
+ $form->bind(array('firstName' => 'Bernhard'));
+
+ $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
+ }
+
+ public function testBindEmptyWithEmptyDataCreatesNoObjectIfNotRequired()
+ {
+ $form = $this->factory->create('form', null, array(
+ 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
+ 'required' => false,
+ ));
+ $form->add($this->factory->createNamed('form', 'firstName'));
+ $form->add($this->factory->createNamed('form', 'lastName'));
+
+ $form->setData(null);
+ $form->bind(array('firstName' => '', 'lastName' => ''));
+
+ $this->assertNull($form->getData());
+ }
+
+ public function testBindEmptyWithEmptyDataCreatesObjectIfRequired()
+ {
+ $form = $this->factory->create('form', null, array(
+ 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
+ 'required' => true,
+ ));
+ $form->add($this->factory->createNamed('form', 'firstName'));
+ $form->add($this->factory->createNamed('form', 'lastName'));
+
+ $form->setData(null);
+ $form->bind(array('firstName' => '', 'lastName' => ''));
+
+ $this->assertEquals(new Author(), $form->getData());
+ }
+
+ /*
+ * We need something to write the field values into
+ */
+ public function testBindWithEmptyDataStoresArrayIfNoClassAvailable()
+ {
+ $form = $this->factory->create('form');
+ $form->add($this->factory->createNamed('form', 'firstName'));
+
+ $form->setData(null);
+ $form->bind(array('firstName' => 'Bernhard'));
+
+ $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
+ }
+
+ public function testBindWithEmptyDataPassesEmptyStringToTransformerIfNoChildren()
+ {
+ $form = $this->factory->createBuilder('form')
+ ->appendClientTransformer(new FixedDataTransformer(array(
+ // required for the initial, internal setData(null)
+ null => 'null',
+ // required to test that bind(null) is converted to ''
+ 'empty' => '',
+ )))
+ ->getForm();
+
+ $form->bind(null);
+
+ $this->assertSame('empty', $form->getData());
+ }
+
+ public function testBindWithEmptyDataUsesEmptyDataOption()
+ {
+ $author = new Author();
+
+ $form = $this->factory->create('form', null, array(
+ 'empty_data' => $author,
+ ));
+ $form->add($this->factory->createNamed('form', 'firstName'));
+
+ $form->bind(array('firstName' => 'Bernhard'));
+
+ $this->assertSame($author, $form->getData());
+ $this->assertEquals('Bernhard', $author->firstName);
+ }
+
+ public function testGetAttributesIsEmpty()
+ {
+ $form = $this->factory->create('form', null, array('attr' => array()));
+
+ $this->assertCount(0, $form->getAttribute('attr'));
+ }
+
+ /**
+ * @see https://github.com/symfony/symfony/issues/1986
+ */
+ public function testSetDataThroughParamsWithZero()
+ {
+ $form = $this->factory->create('form', null, array('data' => 0));
+ $view = $form->createView();
+
+ $this->assertFalse($form->isEmpty());
+
+ $this->assertSame('0', $view->get('value'));
+ $this->assertSame('0', $form->getData());
+
+ $form = $this->factory->create('form', null, array('data' => '0'));
+ $view = $form->createView();
+
+ $this->assertFalse($form->isEmpty());
+
+ $this->assertSame('0', $view->get('value'));
+ $this->assertSame('0', $form->getData());
+
+ $form = $this->factory->create('form', null, array('data' => '00000'));
+ $view = $form->createView();
+
+ $this->assertFalse($form->isEmpty());
+
+ $this->assertSame('00000', $view->get('value'));
+ $this->assertSame('00000', $form->getData());
+ }
+
+ /**
+ * @expectedException Symfony\Component\Form\Exception\FormException
+ */
+ public function testAttributesException()
+ {
+ $form = $this->factory->create('form', null, array('attr' => ''));
+ }
+
+ public function testNameCanBeEmptyString()
+ {
+ $form = $this->factory->createNamed('form', '');
+
+ $this->assertEquals('', $form->getName());
+ }
public function testSubformDoesntCallSetters()
{
$author = new FormTest_AuthorWithoutRefSetter(new Author());
$builder = $this->factory->createBuilder('form');
$builder->add('reference', 'form');
- $builder->get('reference')->add('firstName', 'field');
+ $builder->get('reference')->add('firstName', 'form');
$builder->setData($author);
$form = $builder->getForm();
@@ -77,7 +454,7 @@ class FormTypeTest extends TypeTestCase
$builder = $this->factory->createBuilder('form');
$builder->add('referenceCopy', 'form');
- $builder->get('referenceCopy')->add('firstName', 'field');
+ $builder->get('referenceCopy')->add('firstName', 'form');
$builder->setData($author);
$form = $builder->getForm();
@@ -99,7 +476,7 @@ class FormTypeTest extends TypeTestCase
$builder = $this->factory->createBuilder('form');
$builder->add('referenceCopy', 'form', array('by_reference' => false));
- $builder->get('referenceCopy')->add('firstName', 'field');
+ $builder->get('referenceCopy')->add('firstName', 'form');
$builder->setData($author);
$form = $builder->getForm();
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php
index df571ba9d8..6d9139633e 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php
@@ -21,7 +21,7 @@ class RepeatedTypeTest extends TypeTestCase
parent::setUp();
$this->form = $this->factory->create('repeated', null, array(
- 'type' => 'field',
+ 'type' => 'form',
));
$this->form->setData(null);
}
@@ -37,7 +37,7 @@ class RepeatedTypeTest extends TypeTestCase
public function testSetOptions()
{
$form = $this->factory->create('repeated', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'options' => array('label' => 'Global'),
));
@@ -47,11 +47,11 @@ class RepeatedTypeTest extends TypeTestCase
$this->assertTrue($form['second']->isRequired());
}
- public function testSetOptionsPerField()
+ public function testSetOptionsPerChild()
{
$form = $this->factory->create('repeated', null, array(
// the global required value cannot be overriden
- 'type' => 'field',
+ 'type' => 'form',
'first_options' => array('label' => 'Test', 'required' => false),
'second_options' => array('label' => 'Test2')
));
@@ -66,17 +66,17 @@ class RepeatedTypeTest extends TypeTestCase
{
$form = $this->factory->create('repeated', null, array(
'required' => false,
- 'type' => 'field',
+ 'type' => 'form',
));
$this->assertFalse($form['first']->isRequired());
$this->assertFalse($form['second']->isRequired());
}
- public function testSetOptionsPerFieldAndOverwrite()
+ public function testSetOptionsPerChildAndOverwrite()
{
$form = $this->factory->create('repeated', null, array(
- 'type' => 'field',
+ 'type' => 'form',
'options' => array('label' => 'Label'),
'second_options' => array('label' => 'Second label')
));
diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/EnsureCsrfFieldListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/EnsureCsrfFieldListenerTest.php
deleted file mode 100644
index 9b87717e5d..0000000000
--- a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/EnsureCsrfFieldListenerTest.php
+++ /dev/null
@@ -1,87 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener;
-
-use Symfony\Component\Form\Event\DataEvent;
-use Symfony\Component\Form\Extension\Csrf\EventListener\EnsureCsrfFieldListener;
-
-class EnsureCsrfFieldListenerTest extends \PHPUnit_Framework_TestCase
-{
- private $form;
- private $formFactory;
- private $field;
- private $event;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->formFactory = $this->getMock('Symfony\\Component\\Form\\FormFactoryInterface');
- $this->form = $this->getMock('Symfony\\Component\\Form\\Tests\\FormInterface');
- $this->field = $this->getMock('Symfony\\Component\\Form\\Tests\\FormInterface');
- $this->event = new DataEvent($this->form, array());
- }
-
- protected function tearDown()
- {
- $this->form = null;
- $this->formFactory = null;
- $this->field = null;
- $this->event = null;
- }
-
- public function testAddField()
- {
- $this->formFactory->expects($this->once())
- ->method('createNamed')
- ->with('csrf', '_token', null, array())
- ->will($this->returnValue($this->field));
- $this->form->expects($this->once())
- ->method('add')
- ->with($this->isInstanceOf('Symfony\\Component\\Form\\Tests\\FormInterface'));
-
- $listener = new EnsureCsrfFieldListener($this->formFactory, '_token');
- $listener->ensureCsrfField($this->event);
- }
-
- public function testIntention()
- {
- $this->formFactory->expects($this->once())
- ->method('createNamed')
- ->with('csrf', '_token', null, array('intention' => 'something'))
- ->will($this->returnValue($this->field));
- $this->form->expects($this->once())
- ->method('add')
- ->with($this->isInstanceOf('Symfony\\Component\\Form\\Tests\\FormInterface'));
-
- $listener = new EnsureCsrfFieldListener($this->formFactory, '_token', 'something');
- $listener->ensureCsrfField($this->event);
- }
-
- public function testProvider()
- {
- $provider = $this->getMock('Symfony\\Component\\Form\\Extension\\Csrf\\CsrfProvider\\CsrfProviderInterface');
-
- $this->formFactory->expects($this->once())
- ->method('createNamed')
- ->with('csrf', '_token', null, array('csrf_provider' => $provider))
- ->will($this->returnValue($this->field));
- $this->form->expects($this->once())
- ->method('add')
- ->with($this->isInstanceOf('Symfony\\Component\\Form\\Tests\\FormInterface'));
-
- $listener = new EnsureCsrfFieldListener($this->formFactory, '_token', null, $provider);
- $listener->ensureCsrfField($this->event);
- }
-}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/CsrfTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/CsrfTypeTest.php
deleted file mode 100644
index 4483e7f392..0000000000
--- a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/CsrfTypeTest.php
+++ /dev/null
@@ -1,112 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Csrf\Type;
-
-class CsrfTypeTest extends TypeTestCase
-{
- protected $provider;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->provider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->provider = null;
- }
-
- protected function getNonRootForm()
- {
- $form = $this->getMock('Symfony\Component\Form\Tests\FormInterface');
- $form->expects($this->any())
- ->method('isRoot')
- ->will($this->returnValue(false));
-
- return $form;
- }
-
- public function testGenerateCsrfToken()
- {
- $this->provider->expects($this->once())
- ->method('generateCsrfToken')
- ->with('%INTENTION%')
- ->will($this->returnValue('token'));
-
- $form = $this->factory->create('csrf', null, array(
- 'csrf_provider' => $this->provider,
- 'intention' => '%INTENTION%'
- ));
-
- $this->assertEquals('token', $form->getData());
- }
-
- public function testValidateTokenOnBind()
- {
- $this->provider->expects($this->once())
- ->method('isCsrfTokenValid')
- ->with('%INTENTION%', 'token')
- ->will($this->returnValue(true));
-
- $form = $this->factory->create('csrf', null, array(
- 'csrf_provider' => $this->provider,
- 'intention' => '%INTENTION%'
- ));
- $form->bind('token');
-
- $this->assertEquals('token', $form->getData());
- }
-
- public function testDontValidateTokenIfParentIsNotRoot()
- {
- $this->provider->expects($this->never())
- ->method('isCsrfTokenValid');
-
- $form = $this->factory->create('csrf', null, array(
- 'csrf_provider' => $this->provider,
- 'intention' => '%INTENTION%'
- ));
- $form->setParent($this->getNonRootForm());
- $form->bind('token');
- }
-
- public function testCsrfTokenIsRegeneratedIfValidationFails()
- {
- $this->provider->expects($this->at(0))
- ->method('generateCsrfToken')
- ->with('%INTENTION%')
- ->will($this->returnValue('token1'));
- $this->provider->expects($this->at(1))
- ->method('isCsrfTokenValid')
- ->with('%INTENTION%', 'invalid')
- ->will($this->returnValue(false));
-
- // The token is regenerated to avoid stalled tokens, for example when
- // the session ID changed
- $this->provider->expects($this->at(2))
- ->method('generateCsrfToken')
- ->with('%INTENTION%')
- ->will($this->returnValue('token2'));
-
- $form = $this->factory->create('csrf', null, array(
- 'csrf_provider' => $this->provider,
- 'intention' => '%INTENTION%'
- ));
- $form->bind('invalid');
-
- $this->assertEquals('token2', $form->getData());
- }
-}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php
index 20da376d79..9024002b52 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php
@@ -11,43 +11,188 @@
namespace Symfony\Component\Form\Tests\Extension\Csrf\Type;
+use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
+use Symfony\Component\Form\Tests\Extension\Core\Type\TypeTestCase;
+
class FormTypeCsrfExtensionTest extends TypeTestCase
{
- public function testCsrfProtectionByDefault()
- {
- $form = $this->factory->create('form', null, array(
- 'csrf_field_name' => 'csrf',
- ));
+ protected $csrfProvider;
- $this->assertTrue($form->has('csrf'));
+ protected function setUp()
+ {
+ $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
+
+ parent::setUp();
+ }
+
+ protected function tearDown()
+ {
+ $this->csrfProvider = null;
+
+ parent::tearDown();
+ }
+
+ protected function getExtensions()
+ {
+ return array_merge(parent::getExtensions(), array(
+ new CsrfExtension($this->csrfProvider),
+ ));
+ }
+
+ public function testCsrfProtectionByDefaultIfRootAndChildren()
+ {
+ $view = $this->factory
+ ->createBuilder('form', null, array(
+ 'csrf_field_name' => 'csrf',
+ ))
+ ->add($this->factory->createNamedBuilder('form', 'child'))
+ ->getForm()
+ ->createView();
+
+ $this->assertTrue($view->hasChild('csrf'));
+ }
+
+ public function testNoCsrfProtectionByDefaultIfChildrenButNotRoot()
+ {
+ $view = $this->factory
+ ->createNamedBuilder('form', 'root')
+ ->add($this->factory
+ ->createNamedBuilder('form', 'form', null, array(
+ 'csrf_field_name' => 'csrf',
+ ))
+ ->add($this->factory->createNamedBuilder('form', 'child'))
+ )
+ ->getForm()
+ ->get('form')
+ ->createView();
+
+ $this->assertFalse($view->hasChild('csrf'));
+ }
+
+ public function testNoCsrfProtectionByDefaultIfRootButNoChildren()
+ {
+ $view = $this->factory
+ ->createBuilder('form', null, array(
+ 'csrf_field_name' => 'csrf',
+ ))
+ ->getForm()
+ ->createView();
+
+ $this->assertFalse($view->hasChild('csrf'));
}
public function testCsrfProtectionCanBeDisabled()
{
- $form = $this->factory->create('form', null, array(
- 'csrf_protection' => false,
- ));
-
- $this->assertCount(0, $form);
- }
-
- public function testCsrfTokenIsOnlyIncludedInRootView()
- {
- $view =
- $this->factory->createBuilder('form', null, array(
+ $view = $this->factory
+ ->createBuilder('form', null, array(
'csrf_field_name' => 'csrf',
+ 'csrf_protection' => false,
))
- ->add('notCsrf', 'text')
- ->add(
- $this->factory->createNamedBuilder('form', 'child', null, array(
- 'csrf_field_name' => 'csrf',
- ))
- ->add('notCsrf', 'text')
- )
+ ->add($this->factory->createNamedBuilder('form', 'child'))
->getForm()
->createView();
- $this->assertEquals(array('csrf', 'notCsrf', 'child'), array_keys(iterator_to_array($view)));
- $this->assertEquals(array('notCsrf'), array_keys(iterator_to_array($view['child'])));
+ $this->assertFalse($view->hasChild('csrf'));
+ }
+
+ public function testGenerateCsrfToken()
+ {
+ $this->csrfProvider->expects($this->once())
+ ->method('generateCsrfToken')
+ ->with('%INTENTION%')
+ ->will($this->returnValue('token'));
+
+ $view = $this->factory
+ ->createBuilder('form', null, array(
+ 'csrf_field_name' => 'csrf',
+ 'csrf_provider' => $this->csrfProvider,
+ 'intention' => '%INTENTION%'
+ ))
+ ->add($this->factory->createNamedBuilder('form', 'child'))
+ ->getForm()
+ ->createView();
+
+ $this->assertEquals('token', $view->getChild('csrf')->get('value'));
+ }
+
+ public function provideBoolean()
+ {
+ return array(
+ array(true),
+ array(false),
+ );
+ }
+
+ /**
+ * @dataProvider provideBoolean
+ */
+ public function testValidateTokenOnBindIfRootAndChildren($valid)
+ {
+ $this->csrfProvider->expects($this->once())
+ ->method('isCsrfTokenValid')
+ ->with('%INTENTION%', 'token')
+ ->will($this->returnValue($valid));
+
+ $form = $this->factory
+ ->createBuilder('form', null, array(
+ 'csrf_field_name' => 'csrf',
+ 'csrf_provider' => $this->csrfProvider,
+ 'intention' => '%INTENTION%'
+ ))
+ ->add($this->factory->createNamedBuilder('form', 'child'))
+ ->getForm();
+
+ $form->bind(array(
+ 'child' => 'foobar',
+ 'csrf' => 'token',
+ ));
+
+ // Remove token from data
+ $this->assertSame(array('child' => 'foobar'), $form->getData());
+
+ // Validate accordingly
+ $this->assertSame($valid, $form->isValid());
+ }
+
+ public function testDontValidateTokenIfChildrenButNoRoot()
+ {
+ $this->csrfProvider->expects($this->never())
+ ->method('isCsrfTokenValid');
+
+ $form = $this->factory
+ ->createNamedBuilder('form', 'root')
+ ->add($this->factory
+ ->createNamedBuilder('form', 'form', null, array(
+ 'csrf_field_name' => 'csrf',
+ 'csrf_provider' => $this->csrfProvider,
+ 'intention' => '%INTENTION%'
+ ))
+ ->add($this->factory->createNamedBuilder('form', 'child'))
+ )
+ ->getForm()
+ ->get('form');
+
+ $form->bind(array(
+ 'child' => 'foobar',
+ 'csrf' => 'token',
+ ));
+ }
+
+ public function testDontValidateTokenIfRootButNoChildren()
+ {
+ $this->csrfProvider->expects($this->never())
+ ->method('isCsrfTokenValid');
+
+ $form = $this->factory
+ ->createBuilder('form', null, array(
+ 'csrf_field_name' => 'csrf',
+ 'csrf_provider' => $this->csrfProvider,
+ 'intention' => '%INTENTION%'
+ ))
+ ->getForm();
+
+ $form->bind(array(
+ 'csrf' => 'token',
+ ));
}
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/TypeTestCase.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/TypeTestCase.php
deleted file mode 100644
index 3b1ce91783..0000000000
--- a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/TypeTestCase.php
+++ /dev/null
@@ -1,41 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Csrf\Type;
-
-use Symfony\Component\Form\Tests\Extension\Core\Type\TypeTestCase as BaseTestCase;
-use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
-
-abstract class TypeTestCase extends BaseTestCase
-{
- protected $csrfProvider;
-
- protected function setUp()
- {
- $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
-
- parent::setUp();
- }
-
- protected function tearDown()
- {
- $this->csrfProvider = null;
-
- parent::tearDown();
- }
-
- protected function getExtensions()
- {
- return array_merge(parent::getExtensions(), array(
- new CsrfExtension($this->csrfProvider),
- ));
- }
-}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/DelegatingValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/DelegatingValidationListenerTest.php
index 0071b36fd7..187ce1a2b7 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/DelegatingValidationListenerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/DelegatingValidationListenerTest.php
@@ -93,6 +93,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$builder = new FormBuilder($name, $this->factory, $this->dispatcher);
$builder->setAttribute('property_path', new PropertyPath($propertyPath ?: $name));
$builder->setAttribute('error_mapping', array());
+ $builder->setErrorBubbling(false);
return $builder;
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FieldTypeValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
similarity index 79%
rename from src/Symfony/Component/Form/Tests/Extension/Validator/Type/FieldTypeValidatorExtensionTest.php
rename to src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
index fdf011d66a..5cd0ea753b 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FieldTypeValidatorExtensionTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
@@ -13,18 +13,18 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
use Symfony\Component\Form\FormInterface;
-class FieldTypeValidatorExtensionTest extends TypeTestCase
+class FormTypeValidatorExtensionTest extends TypeTestCase
{
public function testValidationGroupNullByDefault()
{
- $form = $this->factory->create('field');
+ $form = $this->factory->create('form');
$this->assertNull($form->getAttribute('validation_groups'));
}
public function testValidationGroupsCanBeSetToString()
{
- $form = $this->factory->create('field', null, array(
+ $form = $this->factory->create('form', null, array(
'validation_groups' => 'group',
));
@@ -33,7 +33,7 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testValidationGroupsCanBeSetToArray()
{
- $form = $this->factory->create('field', null, array(
+ $form = $this->factory->create('form', null, array(
'validation_groups' => array('group1', 'group2'),
));
@@ -42,7 +42,7 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testValidationGroupsCanBeSetToCallback()
{
- $form = $this->factory->create('field', null, array(
+ $form = $this->factory->create('form', null, array(
'validation_groups' => array($this, 'testValidationGroupsCanBeSetToCallback'),
));
@@ -51,7 +51,7 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testValidationGroupsCanBeSetToClosure()
{
- $form = $this->factory->create('field', null, array(
+ $form = $this->factory->create('form', null, array(
'validation_groups' => function(FormInterface $form){ return null; },
));
@@ -60,10 +60,10 @@ class FieldTypeValidatorExtensionTest extends TypeTestCase
public function testBindValidatesData()
{
- $builder = $this->factory->createBuilder('field', null, array(
+ $builder = $this->factory->createBuilder('form', null, array(
'validation_groups' => 'group',
));
- $builder->add('firstName', 'field');
+ $builder->add('firstName', 'form');
$form = $builder->getForm();
$this->validator->expects($this->once())
diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php
index f5276f322e..bbae7ee2dd 100644
--- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php
+++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php
@@ -71,7 +71,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
* Changing the name is not allowed, otherwise the name and property path
* are not synchronized anymore
*
- * @see FieldType::buildForm
+ * @see FormType::buildForm
*/
public function testNoSetName()
{
diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php
index 96ceea5532..49e53e8337 100644
--- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php
+++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php
@@ -346,7 +346,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo', $builder->getName());
}
- public function testCreateBuilderForPropertyCreatesFieldWithHighestConfidence()
+ public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence()
{
$this->guesser1->expects($this->once())
->method('guessType')
@@ -378,7 +378,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('builderInstance', $builder);
}
- public function testCreateBuilderCreatesTextFieldIfNoGuess()
+ public function testCreateBuilderCreatesTextFormIfNoGuess()
{
$this->guesser1->expects($this->once())
->method('guessType')
@@ -541,7 +541,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$factory->createNamedBuilder($type, "text", "value", array("unknown" => "opt"));
}
- public function testFieldTypeCreatesDefaultValueForEmptyDataOption()
+ public function testFormTypeCreatesDefaultValueForEmptyDataOption()
{
$factory = new FormFactory(array(new \Symfony\Component\Form\Extension\Core\CoreExtension()));
diff --git a/src/Symfony/Component/Form/Tests/FormTest.php b/src/Symfony/Component/Form/Tests/FormTest.php
index a5c20dcbcf..08ef363e4b 100644
--- a/src/Symfony/Component/Form/Tests/FormTest.php
+++ b/src/Symfony/Component/Form/Tests/FormTest.php
@@ -159,6 +159,35 @@ class FormTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(), $parent->getErrors());
}
+ public function testErrorsBubbleUpIfNullAndChildren()
+ {
+ $error = new FormError('Error!');
+ $parent = $this->form;
+ $form = $this->getBuilder()
+ ->setErrorBubbling(null)
+ ->add($this->getBuilder('child'))
+ ->getForm();
+
+ $form->setParent($parent);
+ $form->addError($error);
+
+ $this->assertEquals(array(), $form->getErrors());
+ $this->assertEquals(array($error), $parent->getErrors());
+ }
+
+ public function testErrorsDontBubbleUpIfNullAndNoChildren()
+ {
+ $error = new FormError('Error!');
+ $parent = $this->form;
+ $form = $this->getBuilder()->setErrorBubbling(null)->getForm();
+
+ $form->setParent($parent);
+ $form->addError($error);
+
+ $this->assertEquals(array($error), $form->getErrors());
+ $this->assertEquals(array(), $parent->getErrors());
+ }
+
public function testValidIfAllChildrenAreValid()
{
$this->form->add($this->getValidForm('firstName'));
@@ -1026,7 +1055,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
/**
* @dataProvider requestMethodProvider
*/
- public function testBindPostOrPutRequestWithSingleFieldForm($method)
+ public function testBindPostOrPutRequestWithSingleChildForm($method)
{
if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
$this->markTestSkipped('The "HttpFoundation" component is not available');
@@ -1063,7 +1092,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
/**
* @dataProvider requestMethodProvider
*/
- public function testBindPostOrPutRequestWithSingleFieldFormUploadedFile($method)
+ public function testBindPostOrPutRequestWithSingleChildFormUploadedFile($method)
{
if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
$this->markTestSkipped('The "HttpFoundation" component is not available');
@@ -1247,7 +1276,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
public function testCreateViewAcceptsParent()
{
- $parent = new FormView();
+ $parent = new FormView('form');
$form = $this->getBuilder()->getForm();
$view = $form->createView($parent);