[Form] *_SET_DATA events are now guaranteed to be fired *after* the initial children were added

This commit is contained in:
Bernhard Schussek 2013-04-29 17:31:30 +02:00
parent 84d759d3d5
commit 441222eda7
20 changed files with 374 additions and 105 deletions

View File

@ -110,6 +110,66 @@ Form
}
```
* The *_SET_DATA events are now guaranteed to be fired *after* the children
were added by the FormBuilder (unless setData() is called manually). Before,
the *_SET_DATA events were sometimes thrown before adding child forms,
which made it impossible to remove child forms dynamically.
A consequence of this change is that you need to set the "auto_initialize"
option to `false` for `FormInterface` instances that you pass to
`FormInterface::add()`:
Before:
```
$form = $factory->create('form');
$form->add($factory->createNamed('field', 'text'));
```
This code will now throw an exception with the following message:
Automatic initialization is only supported on root forms. You should set the
"auto_initialize" option to false on the field "field".
Consequently, you need to set the "auto_initialize" option:
After (Alternative 1):
```
$form = $factory->create('form');
$form->add($factory->createNamed('field', 'text', array(
'auto_initialize' => false,
)));
```
The problem also disappears if you work with `FormBuilder` instances instead
of `Form` instances:
After (Alternative 2):
```
$builder = $factory->createBuilder('form');
$builder->add($factory->createBuilder('field', 'text'));
$form = $builder->getForm();
```
The best solution is in most cases to let `add()` handle the field creation:
After (Alternative 3):
```
$form = $factory->create('form');
$form->add('field', 'text');
```
After (Alternative 4):
```
$builder = $factory->createBuilder('form');
$builder->add('field', 'text');
$form = $builder->getForm();
```
PropertyAccess
--------------

View File

@ -343,6 +343,16 @@ class Button implements \IteratorAggregate, FormInterface
return true;
}
/**
* Unsupported method.
*
* @throws BadMethodCallException
*/
public function initialize()
{
throw new BadMethodCallException('Buttons cannot be initialized. Call initialized() on the root form instead.');
}
/**
* Unsupported method.
*
@ -352,7 +362,7 @@ class Button implements \IteratorAggregate, FormInterface
*/
public function handleRequest($request = null)
{
throw new BadMethodCallException('Buttons cannot be processed. Call process() on the root form instead.');
throw new BadMethodCallException('Buttons cannot handle requests. Call handleRequest() on the root form instead.');
}
/**

View File

@ -492,6 +492,22 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
throw new BadMethodCallException('Buttons do not support form processors.');
}
/**
* Unsupported method.
*
* @param Boolean $initialize
*
* @throws BadMethodCallException
*/
public function setAutoInitialize($initialize)
{
if (true === $initialize) {
throw new BadMethodCallException('Buttons do not support automatic initialization.');
}
return $this;
}
/**
* Unsupported method.
*
@ -771,6 +787,16 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
return null;
}
/**
* Unsupported method.
*
* @return null Always returns null.
*/
public function getAutoInitialize()
{
return null;
}
/**
* Unsupported method.
*

View File

@ -25,6 +25,12 @@ CHANGELOG
* deprecated bind() and isBound() in Form
* deprecated AlreadyBoundException in favor of AlreadySubmittedException
* added support for PATCH requests
* [BC BREAK] added initialize() to FormInterface
* [BC BREAK] added getAutoInitialize() to FormConfigInterface
* [BC BREAK] added setAutoInitialize() to FormConfigBuilderInterface
* [BC BREAK] initialization for Form instances added to a form tree must be manually disabled
* PRE_SET_DATA is now guaranteed to be called after children were added by the form builder,
unless FormInterface::setData() is called manually
2.2.0
-----

View File

@ -55,6 +55,7 @@ class FormType extends BaseType
->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
->setMethod($options['method'])
->setAction($options['action'])
->setAutoInitialize($options['auto_initialize'])
;
if ($options['trim']) {
@ -188,6 +189,7 @@ class FormType extends BaseType
// According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
// section 4.2., empty URIs are considered same-document references
'action' => '',
'auto_initialize' => true,
));
$resolver->setAllowedTypes(array(

View File

@ -451,6 +451,25 @@ class Form implements \IteratorAggregate, FormInterface
return $this->extraData;
}
/**
* {@inheritdoc}
*/
public function initialize()
{
if (null !== $this->parent) {
throw new RuntimeException('Only root forms should be initialized.');
}
// Guarantee that the *_SET_DATA events have been triggered once the
// form is initialized. This makes sure that dynamically added or
// removed fields are already visible after initialization.
if (!$this->defaultDataSet) {
$this->setData($this->config->getData());
}
return $this;
}
/**
* {@inheritdoc}
*/
@ -774,7 +793,11 @@ class Form implements \IteratorAggregate, FormInterface
// * getViewData() is called
// * setData() is called since the form is not initialized yet
// * ... endless recursion ...
if (!$this->lockSetData && !$this->config->getInheritData()) {
//
// Also skip data mapping if setData() has not been called yet.
// setData() will be called upon form initialization and data mapping
// will take place by then.
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
$viewData = $this->getViewData();
}
@ -787,18 +810,27 @@ class Form implements \IteratorAggregate, FormInterface
throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
}
// Never initialize child forms automatically
$options['auto_initialize'] = false;
if (null === $type) {
$child = $this->config->getFormFactory()->createForProperty($this->config->getDataClass(), $child, null, $options);
} else {
$child = $this->config->getFormFactory()->createNamed($child, $type, null, $options);
}
} elseif ($child->getConfig()->getAutoInitialize()) {
throw new RuntimeException(sprintf(
'Automatic initialization is only supported on root forms. You '.
'should set the "auto_initialize" option to false on the field "%s".',
$child->getName()
));
}
$this->children[$child->getName()] = $child;
$child->setParent($this);
if (!$this->lockSetData && !$this->config->getInheritData()) {
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
$childrenIterator = new InheritDataAwareIterator(array($child));
$childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);

View File

@ -26,7 +26,7 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
/**
* The children of the form builder.
*
* @var array
* @var FormBuilderInterface[]
*/
private $children = array();
@ -220,7 +220,13 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
$form = new Form($this->getFormConfig());
foreach ($this->children as $child) {
$form->add($child->getForm());
// Automatic initialization is only supported on root forms
$form->add($child->setAutoInitialize(false)->getForm());
}
if ($this->getAutoInitialize()) {
// Automatically initialize the form if it is configured so
$form->initialize();
}
return $form;

View File

@ -107,11 +107,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface
*/
private $dataMapper;
/**
* @var array
*/
private $validators = array();
/**
* @var Boolean
*/
@ -172,6 +167,11 @@ class FormConfigBuilder implements FormConfigBuilderInterface
*/
private $requestHandler;
/**
* @var Boolean
*/
private $autoInitialize = false;
/**
* @var array
*/
@ -521,6 +521,14 @@ class FormConfigBuilder implements FormConfigBuilderInterface
return $this->requestHandler;
}
/**
* {@inheritdoc}
*/
public function getAutoInitialize()
{
return $this->autoInitialize;
}
/**
* {@inheritdoc}
*/
@ -843,6 +851,16 @@ class FormConfigBuilder implements FormConfigBuilderInterface
return $this;
}
/**
* {@inheritdoc}
*/
public function setAutoInitialize($initialize)
{
$this->autoInitialize = (Boolean) $initialize;
return $this;
}
/**
* {@inheritdoc}
*/

View File

@ -256,12 +256,28 @@ interface FormConfigBuilderInterface extends FormConfigInterface
public function setMethod($method);
/**
* Sets the request handler used by the form.
*
* @param RequestHandlerInterface $requestHandler
*
* @return self The configuration object.
*/
public function setRequestHandler(RequestHandlerInterface $requestHandler);
/**
* Sets whether the form should be initialized automatically.
*
* Should be set to true only for root forms.
*
* @param Boolean $initialize True to initialize the form automatically,
* false to suppress automatic initialization.
* In the second case, you need to call
* {@link FormInterface::initialize()} manually.
*
* @return self The configuration object.
*/
public function setAutoInitialize($initialize);
/**
* Builds and returns the form configuration.
*

View File

@ -201,10 +201,20 @@ interface FormConfigInterface
public function getMethod();
/**
* @return RequestHandlerInterface The form processor.
* Returns the request handler used by the form.
*
* @return RequestHandlerInterface The request handler.
*/
public function getRequestHandler();
/**
* Returns whether the form should be initialized upon creation.
*
* @return Boolean Returns true if the form should be initialized
* when created, false otherwise.
*/
public function getAutoInitialize();
/**
* Returns all options passed during the construction of the form.
*

View File

@ -227,13 +227,23 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
public function isSynchronized();
/**
* Processes the given request and calls {@link submit()} if it was submitted.
* Initializes the form tree.
*
* Internally, the request is forwarded to a {@link RequestHandlerInterface}
* instance. This instance determines the allowed value of the
* $request parameter.
* Should be called on the root form after constructing the tree.
*
* @param mixed $request The request to check.
* @return FormInterface The form instance.
*/
public function initialize();
/**
* Inspects the given request and calls {@link submit()} if the form was
* submitted.
*
* Internally, the request is forwarded to the configured
* {@link RequestHandlerInterface} instance, which determines whether to
* submit the form or not.
*
* @param mixed $request The request to handle.
*
* @return FormInterface The form instance.
*/

View File

@ -143,18 +143,16 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
{
$child1 = $this->factory->createNamedBuilder('child1', 'form')
->add('field1', 'text')
->add('field2', 'text')
->getForm();
->add('field2', 'text');
$child2 = $this->factory->createNamedBuilder('child2', 'form')
->add('field1', 'text')
->add('field2', 'text')
->getForm();
->add('field2', 'text');
$view = $this->factory->createNamedBuilder('parent', 'form')
->getForm()
->add($child1)
->add($child2)
->getForm()
->createView();
// Render child1.field1 row
@ -627,13 +625,12 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testThemeInheritance($parentTheme, $childTheme)
{
$child = $this->factory->createNamedBuilder('child', 'form')
->add('field', 'text')
->getForm();
->add('field', 'text');
$view = $this->factory->createNamedBuilder('parent', 'form')
->add('field', 'text')
->getForm()
->add($child)
->getForm()
->createView()
;

View File

@ -77,10 +77,14 @@ abstract class AbstractFormTest extends \PHPUnit_Framework_TestCase
protected function getMockForm($name = 'name')
{
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
$config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
$form->expects($this->any())
->method('getName')
->will($this->returnValue($name));
$form->expects($this->any())
->method('getConfig')
->will($this->returnValue($config));
return $form;
}

View File

@ -1152,9 +1152,10 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
public function testDateErrorBubbling()
{
$child = $this->factory->createNamed('date', 'date');
$form = $this->factory->createNamed('form', 'form')->add($child);
$child->addError(new FormError('[trans]Error![/trans]'));
$form = $this->factory->createNamedBuilder('form', 'form')
->add('date', 'date')
->getForm();
$form->get('date')->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));
@ -1678,9 +1679,10 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
public function testTimeErrorBubbling()
{
$child = $this->factory->createNamed('time', 'time');
$form = $this->factory->createNamed('form', 'form')->add($child);
$child->addError(new FormError('[trans]Error![/trans]'));
$form = $this->factory->createNamedBuilder('form', 'form')
->add('time', 'time')
->getForm();
$form->get('time')->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));

View File

@ -154,7 +154,10 @@ class CompoundFormTest extends AbstractFormTest
$this->factory->expects($this->once())
->method('createNamed')
->with('foo', 'text', null, array('bar' => 'baz'))
->with('foo', 'text', null, array(
'bar' => 'baz',
'auto_initialize' => false,
))
->will($this->returnValue($child));
$this->form->add('foo', 'text', array('bar' => 'baz'));
@ -170,7 +173,10 @@ class CompoundFormTest extends AbstractFormTest
$this->factory->expects($this->once())
->method('createNamed')
->with('0', 'text', null, array('bar' => 'baz'))
->with('0', 'text', null, array(
'bar' => 'baz',
'auto_initialize' => false,
))
->will($this->returnValue($child));
// in order to make casting unnecessary
@ -213,7 +219,10 @@ class CompoundFormTest extends AbstractFormTest
$this->factory->expects($this->once())
->method('createForProperty')
->with('\stdClass', 'foo', null, array('bar' => 'baz'))
->with('\stdClass', 'foo', null, array(
'bar' => 'baz',
'auto_initialize' => false,
))
->will($this->returnValue($child));
$this->form->add('foo', null, array('bar' => 'baz'));
@ -287,7 +296,7 @@ class CompoundFormTest extends AbstractFormTest
$this->assertSame($this->form->all(), iterator_to_array($this->form));
}
public function testAddMapsViewDataToForm()
public function testAddMapsViewDataToFormIfInitialized()
{
$test = $this;
$mapper = $this->getDataMapper();
@ -310,6 +319,22 @@ class CompoundFormTest extends AbstractFormTest
$test->assertSame(array($child), iterator_to_array($iterator));
}));
$form->initialize();
$form->add($child);
}
public function testAddDoesNotMapViewDataToFormIfNotInitialized()
{
$mapper = $this->getDataMapper();
$form = $this->getBuilder()
->setCompound(true)
->setDataMapper($mapper)
->getForm();
$child = $this->getBuilder()->getForm();
$mapper->expects($this->never())
->method('mapDataToForms');
$form->add($child);
}
@ -326,6 +351,7 @@ class CompoundFormTest extends AbstractFormTest
$mapper->expects($this->never())
->method('mapDataToForms');
$form->initialize();
$form->add($child);
}

View File

@ -72,11 +72,11 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$this->factory->expects($this->at(0))
->method('createNamed')
->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10))
->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10, 'auto_initialize' => false))
->will($this->returnValue($this->getForm('1')));
$this->factory->expects($this->at(1))
->method('createNamed')
->with(2, 'text', null, array('property_path' => '[2]', 'max_length' => 10))
->with(2, 'text', null, array('property_path' => '[2]', 'max_length' => 10, 'auto_initialize' => false))
->will($this->returnValue($this->getForm('2')));
$data = array(1 => 'string', 2 => 'string');
@ -116,7 +116,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$this->factory->expects($this->once())
->method('createNamed')
->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10))
->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10, 'auto_initialize' => false))
->will($this->returnValue($this->getForm('1')));
$data = array(0 => 'string', 1 => 'string');

View File

@ -25,8 +25,8 @@ abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
public function testPassIdAndNameToView()
{
$form = $this->factory->createNamed('name', $this->getTestedType());
$view = $form->createView();
$view = $this->factory->createNamed('name', $this->getTestedType())
->createView();
$this->assertEquals('name', $view->vars['id']);
$this->assertEquals('name', $view->vars['name']);
@ -35,8 +35,8 @@ abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
public function testStripLeadingUnderscoresAndDigitsFromId()
{
$form = $this->factory->createNamed('_09name', $this->getTestedType());
$view = $form->createView();
$view = $this->factory->createNamed('_09name', $this->getTestedType())
->createView();
$this->assertEquals('name', $view->vars['id']);
$this->assertEquals('_09name', $view->vars['name']);
@ -45,9 +45,10 @@ abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
public function testPassIdAndNameToViewWithParent()
{
$parent = $this->factory->createNamed('parent', 'form');
$parent->add($this->factory->createNamed('child', $this->getTestedType()));
$view = $parent->createView();
$view = $this->factory->createNamedBuilder('parent', 'form')
->add('child', $this->getTestedType())
->getForm()
->createView();
$this->assertEquals('parent_child', $view['child']->vars['id']);
$this->assertEquals('child', $view['child']->vars['name']);
@ -56,10 +57,10 @@ abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
public function testPassIdAndNameToViewWithGrandParent()
{
$parent = $this->factory->createNamed('parent', 'form');
$parent->add($this->factory->createNamed('child', 'form'));
$parent['child']->add($this->factory->createNamed('grand_child', $this->getTestedType()));
$view = $parent->createView();
$builder = $this->factory->createNamedBuilder('parent', 'form')
->add('child', 'form');
$builder->get('child')->add('grand_child', $this->getTestedType());
$view = $builder->getForm()->createView();
$this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']);
$this->assertEquals('grand_child', $view['child']['grand_child']->vars['name']);
@ -78,33 +79,38 @@ abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
public function testInheritTranslationDomainFromParent()
{
$parent = $this->factory->createNamed('parent', 'form', null, array(
'translation_domain' => 'domain',
));
$child = $this->factory->createNamed('child', $this->getTestedType());
$view = $parent->add($child)->createView();
$view = $this->factory
->createNamedBuilder('parent', 'form', null, array(
'translation_domain' => 'domain',
))
->add('child', $this->getTestedType())
->getForm()
->createView();
$this->assertEquals('domain', $view['child']->vars['translation_domain']);
}
public function testPreferOwnTranslationDomain()
{
$parent = $this->factory->createNamed('parent', 'form', null, array(
'translation_domain' => 'parent_domain',
));
$child = $this->factory->createNamed('child', $this->getTestedType(), null, array(
'translation_domain' => 'domain',
));
$view = $parent->add($child)->createView();
$view = $this->factory
->createNamedBuilder('parent', 'form', null, array(
'translation_domain' => 'parent_domain',
))
->add('child', $this->getTestedType(), array(
'translation_domain' => 'domain',
))
->getForm()
->createView();
$this->assertEquals('domain', $view['child']->vars['translation_domain']);
}
public function testDefaultTranslationDomain()
{
$parent = $this->factory->createNamed('parent', 'form');
$child = $this->factory->createNamed('child', $this->getTestedType());
$view = $parent->add($child)->createView();
$view = $this->factory->createNamedBuilder('parent', 'form')
->add('child', $this->getTestedType())
->getForm()
->createView();
$this->assertEquals('messages', $view['child']->vars['translation_domain']);
}

View File

@ -100,29 +100,32 @@ class FormTypeTest extends BaseTypeTest
$this->assertEquals('reverse[ a ]', $form->getData());
}
public function testNonReadOnlyFormWithReadOnlyParentBeingReadOnly()
public function testNonReadOnlyFormWithReadOnlyParentIsReadOnly()
{
$parent = $this->factory->createNamed('parent', 'form', null, array('read_only' => true));
$child = $this->factory->createNamed('child', 'form');
$view = $parent->add($child)->createView();
$view = $this->factory->createNamedBuilder('parent', 'form', null, array('read_only' => true))
->add('child', 'form')
->getForm()
->createView();
$this->assertTrue($view['child']->vars['read_only']);
}
public function testReadOnlyFormWithNonReadOnlyParentBeingReadOnly()
public function testReadOnlyFormWithNonReadOnlyParentIsReadOnly()
{
$parent = $this->factory->createNamed('parent', 'form');
$child = $this->factory->createNamed('child', 'form', null, array('read_only' => true));
$view = $parent->add($child)->createView();
$view = $this->factory->createNamedBuilder('parent', 'form')
->add('child', 'form', array('read_only' => true))
->getForm()
->createView();
$this->assertTrue($view['child']->vars['read_only']);
}
public function testNonReadOnlyFormWithNonReadOnlyParentBeingNonReadOnly()
public function testNonReadOnlyFormWithNonReadOnlyParentIsNotReadOnly()
{
$parent = $this->factory->createNamed('parent', 'form');
$child = $this->factory->createNamed('child', 'form');
$view = $parent->add($child)->createView();
$view = $this->factory->createNamedBuilder('parent', 'form')
->add('child', 'form')
->getForm()
->createView();
$this->assertFalse($view['child']->vars['read_only']);
}
@ -137,12 +140,13 @@ class FormTypeTest extends BaseTypeTest
public function testSubmitWithEmptyDataCreatesObjectIfClassAvailable()
{
$form = $this->factory->create('form', null, array(
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => false,
));
$form->add($this->factory->createNamed('firstName', 'text'));
$form->add($this->factory->createNamed('lastName', 'text'));
$builder->add('firstName', 'text');
$builder->add('lastName', 'text');
$form = $builder->getForm();
$form->setData(null);
// partially empty, still an object is created
@ -157,13 +161,14 @@ class FormTypeTest extends BaseTypeTest
public function testSubmitWithEmptyDataCreatesObjectIfInitiallySubmittedWithObject()
{
$form = $this->factory->create('form', null, array(
$builder = $this->factory->createBuilder('form', null, array(
// data class is inferred from the passed object
'data' => new Author(),
'required' => false,
));
$form->add($this->factory->createNamed('firstName', 'text'));
$form->add($this->factory->createNamed('lastName', 'text'));
$builder->add('firstName', 'text');
$builder->add('lastName', 'text');
$form = $builder->getForm();
$form->setData(null);
// partially empty, still an object is created
@ -178,11 +183,12 @@ class FormTypeTest extends BaseTypeTest
public function testSubmitWithEmptyDataCreatesArrayIfDataClassIsNull()
{
$form = $this->factory->create('form', null, array(
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => null,
'required' => false,
));
$form->add($this->factory->createNamed('firstName', 'text'));
$builder->add('firstName', 'text');
$form = $builder->getForm();
$form->setData(null);
$form->submit(array('firstName' => 'Bernhard'));
@ -192,12 +198,13 @@ class FormTypeTest extends BaseTypeTest
public function testSubmitEmptyWithEmptyDataCreatesNoObjectIfNotRequired()
{
$form = $this->factory->create('form', null, array(
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => false,
));
$form->add($this->factory->createNamed('firstName', 'text'));
$form->add($this->factory->createNamed('lastName', 'text'));
$builder->add('firstName', 'text');
$builder->add('lastName', 'text');
$form = $builder->getForm();
$form->setData(null);
$form->submit(array('firstName' => '', 'lastName' => ''));
@ -207,12 +214,13 @@ class FormTypeTest extends BaseTypeTest
public function testSubmitEmptyWithEmptyDataCreatesObjectIfRequired()
{
$form = $this->factory->create('form', null, array(
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'required' => true,
));
$form->add($this->factory->createNamed('firstName', 'text'));
$form->add($this->factory->createNamed('lastName', 'text'));
$builder->add('firstName', 'text');
$builder->add('lastName', 'text');
$form = $builder->getForm();
$form->setData(null);
$form->submit(array('firstName' => '', 'lastName' => ''));
@ -225,8 +233,9 @@ class FormTypeTest extends BaseTypeTest
*/
public function testSubmitWithEmptyDataStoresArrayIfNoClassAvailable()
{
$form = $this->factory->create('form');
$form->add($this->factory->createNamed('firstName', 'text'));
$form = $this->factory->createBuilder('form')
->add('firstName', 'text')
->getForm();
$form->setData(null);
$form->submit(array('firstName' => 'Bernhard'));
@ -255,11 +264,12 @@ class FormTypeTest extends BaseTypeTest
{
$author = new Author();
$form = $this->factory->create('form', null, array(
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'empty_data' => $author,
));
$form->add($this->factory->createNamed('firstName', 'text'));
$builder->add('firstName', 'text');
$form = $builder->getForm();
$form->submit(array('firstName' => 'Bernhard'));
@ -430,19 +440,21 @@ class FormTypeTest extends BaseTypeTest
public function testPassMultipartTrueIfAnyChildIsMultipartToView()
{
$form = $this->factory->create('form');
$form->add($this->factory->create('text'));
$form->add($this->factory->create('file'));
$view = $form->createView();
$view = $this->factory->createBuilder('form')
->add('foo', 'text')
->add('bar', 'file')
->getForm()
->createView();
$this->assertTrue($view->vars['multipart']);
}
public function testCreateViewDoNoMarkItAsRendered()
public function testViewIsNotRenderedByDefault()
{
$form = $this->factory->create('form');
$form->add($this->factory->create('form'));
$view = $form->createView();
$view = $this->factory->createBuilder('form')
->add('foo', 'form')
->getForm()
->createView();
$this->assertFalse($view->isRendered());
}

View File

@ -16,7 +16,7 @@ class AlternatingRowType extends AbstractType
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formFactory) {
$form = $event->getForm();
$type = $form->getName() % 2 === 0 ? 'text' : 'textarea';
$form->add($formFactory->createNamed('title', $type));
$form->add('title', $type);
});
}

View File

@ -902,13 +902,13 @@ class SimpleFormTest extends AbstractFormTest
public function testHandleRequestForwardsToRequestHandler()
{
$processor = $this->getMock('Symfony\Component\Form\RequestHandlerInterface');
$handler = $this->getMock('Symfony\Component\Form\RequestHandlerInterface');
$form = $this->getBuilder()
->setRequestHandler($processor)
->setRequestHandler($handler)
->getForm();
$processor->expects($this->once())
$handler->expects($this->once())
->method('handleRequest')
->with($this->identicalTo($form), 'REQUEST');
@ -1012,6 +1012,32 @@ class SimpleFormTest extends AbstractFormTest
$form->submit('foo');
}
public function testInitializeSetsDefaultData()
{
$config = $this->getBuilder()->setData('DEFAULT')->getFormConfig();
$form = $this->getMock('Symfony\Component\Form\Form', array('setData'), array($config));
$form->expects($this->once())
->method('setData')
->with($this->identicalTo('DEFAULT'));
/* @var Form $form */
$form->initialize();
}
/**
* @expectedException \Symfony\Component\Form\Exception\RuntimeException
*/
public function testInitializeFailsIfParent()
{
$parent = $this->getBuilder()->setRequired(false)->getForm();
$child = $this->getBuilder()->setRequired(true)->getForm();
$child->setParent($parent);
$child->initialize();
}
protected function createForm()
{
return $this->getBuilder()->getForm();