From 56d78eda563330d68444f3d6d6363df53a581ad7 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 17 Sep 2013 11:39:17 +0200 Subject: [PATCH] [Form] Decoupled methods of ResolvedFormType so that they can be overridden individually by decorators --- src/Symfony/Component/Form/Button.php | 11 +- src/Symfony/Component/Form/Form.php | 18 +- src/Symfony/Component/Form/FormFactory.php | 8 +- .../Component/Form/ResolvedFormType.php | 33 +- .../Component/Form/Tests/AbstractFormTest.php | 4 +- .../Component/Form/Tests/CompoundFormTest.php | 60 ++++ .../Component/Form/Tests/FormFactoryTest.php | 172 ++++++--- .../Form/Tests/ResolvedFormTypeTest.php | 327 +++++++++++------- 8 files changed, 437 insertions(+), 196 deletions(-) diff --git a/src/Symfony/Component/Form/Button.php b/src/Symfony/Component/Form/Button.php index aecbabaebe..cecf27b696 100644 --- a/src/Symfony/Component/Form/Button.php +++ b/src/Symfony/Component/Form/Button.php @@ -412,7 +412,16 @@ class Button implements \IteratorAggregate, FormInterface $parent = $this->parent->createView(); } - return $this->config->getType()->createView($this, $parent); + + $type = $this->config->getType(); + $options = $this->config->getOptions(); + + $view = $type->createView($this, $parent); + + $type->buildView($view, $this, $options); + $type->finishView($view, $this, $options); + + return $view; } /** diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index f3324986c8..e03e329ff8 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -969,7 +969,23 @@ class Form implements \IteratorAggregate, FormInterface $parent = $this->parent->createView(); } - return $this->config->getType()->createView($this, $parent); + $type = $this->config->getType(); + $options = $this->config->getOptions(); + + // The methods createView(), buildView() and finishView() are called + // explicitly here in order to be able to override either of them + // in a custom resolved form type. + $view = $type->createView($this, $parent); + + $type->buildView($view, $this, $options); + + foreach ($this->children as $name => $child) { + $view->children[$name] = $child->createView($view); + } + + $type->finishView($view, $this, $options); + + return $view; } /** diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index a5fd9cc0c6..d76e73101b 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -84,7 +84,13 @@ class FormFactory implements FormFactoryInterface throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface'); } - return $type->createBuilder($this, $name, $options); + $builder = $type->createBuilder($this, $name, $options); + + // Explicitly call buildForm() in order to be able to override either + // createBuilder() or buildForm() in the resolved form type + $type->buildForm($builder, $builder->getOptions()); + + return $builder; } /** diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index 47d43553cd..c2fed95859 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -114,8 +114,6 @@ class ResolvedFormType implements ResolvedFormTypeInterface $builder = $this->newBuilder($name, $dataClass, $factory, $options); $builder->setType($this); - $this->buildForm($builder, $options); - return $builder; } @@ -124,28 +122,12 @@ class ResolvedFormType implements ResolvedFormTypeInterface */ public function createView(FormInterface $form, FormView $parent = null) { - $options = $form->getConfig()->getOptions(); - - $view = $this->newView($parent); - - $this->buildView($view, $form, $options); - - foreach ($form as $name => $child) { - /* @var FormInterface $child */ - $view->children[$name] = $child->createView($view); - } - - $this->finishView($view, $form, $options); - - return $view; + return $this->newView($parent); } /** * Configures a form builder for the type hierarchy. * - * This method is protected in order to allow implementing classes - * to change or call it in re-implementations of {@link createBuilder()}. - * * @param FormBuilderInterface $builder The builder to configure. * @param array $options The options used for the configuration. */ @@ -166,10 +148,7 @@ class ResolvedFormType implements ResolvedFormTypeInterface /** * Configures a form view for the type hierarchy. * - * This method is protected in order to allow implementing classes - * to change or call it in re-implementations of {@link createView()}. - * - * It is called before the children of the view are built. + * This method is called before the children of the view are built. * * @param FormView $view The form view to configure. * @param FormInterface $form The form corresponding to the view. @@ -192,10 +171,7 @@ class ResolvedFormType implements ResolvedFormTypeInterface /** * Finishes a form view for the type hierarchy. * - * This method is protected in order to allow implementing classes - * to change or call it in re-implementations of {@link createView()}. - * - * It is called after the children of the view have been built. + * This method is called after the children of the view have been built. * * @param FormView $view The form view to configure. * @param FormInterface $form The form corresponding to the view. @@ -218,9 +194,6 @@ class ResolvedFormType implements ResolvedFormTypeInterface /** * Returns the configured options resolver used for this type. * - * This method is protected in order to allow implementing classes - * to change or call it in re-implementations of {@link createBuilder()}. - * * @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver. */ public function getOptionsResolver() diff --git a/src/Symfony/Component/Form/Tests/AbstractFormTest.php b/src/Symfony/Component/Form/Tests/AbstractFormTest.php index 28f0e389e5..083176e670 100644 --- a/src/Symfony/Component/Form/Tests/AbstractFormTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractFormTest.php @@ -60,9 +60,9 @@ abstract class AbstractFormTest extends \PHPUnit_Framework_TestCase * * @return FormBuilder */ - protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null) + protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null, array $options = array()) { - return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory); + return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory, $options); } /** diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php index 7d9126a988..225cc93391 100644 --- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php +++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; use Symfony\Component\Form\FormError; use Symfony\Component\Form\Forms; +use Symfony\Component\Form\FormView; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; @@ -806,6 +807,65 @@ class CompoundFormTest extends AbstractFormTest $this->assertEquals("name:\n ERROR: Error!\nfoo:\n No errors\n", $parent->getErrorsAsString()); } + // Basic cases are covered in SimpleFormTest + public function testCreateViewWithChildren() + { + $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface'); + $options = array('a' => 'Foo', 'b' => 'Bar'); + $field1 = $this->getMockForm('foo'); + $field2 = $this->getMockForm('bar'); + $view = new FormView(); + $field1View = new FormView(); + $field2View = new FormView(); + + $this->form = $this->getBuilder('form', null, null, $options) + ->setCompound(true) + ->setDataMapper($this->getDataMapper()) + ->setType($type) + ->getForm(); + $this->form->add($field1); + $this->form->add($field2); + + $test = $this; + + $assertChildViewsEqual = function (array $childViews) use ($test) { + return function (FormView $view) use ($test, $childViews) { + /* @var \PHPUnit_Framework_TestCase $test */ + $test->assertSame($childViews, $view->children); + }; + }; + + // First create the view + $type->expects($this->once()) + ->method('createView') + ->will($this->returnValue($view)); + + // Then build it for the form itself + $type->expects($this->once()) + ->method('buildView') + ->with($view, $this->form, $options) + ->will($this->returnCallback($assertChildViewsEqual(array()))); + + // Then add the first child form + $field1->expects($this->once()) + ->method('createView') + ->will($this->returnValue($field1View)); + + // Then the second child form + $field2->expects($this->once()) + ->method('createView') + ->will($this->returnValue($field2View)); + + // Again build the view for the form itself. This time the child views + // exist. + $type->expects($this->once()) + ->method('finishView') + ->with($view, $this->form, $options) + ->will($this->returnCallback($assertChildViewsEqual(array('foo' => $field1View, 'bar' => $field2View)))); + + $this->assertSame($view, $this->form->createView()); + } + protected function createForm() { return $this->getBuilder() diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index bb24079450..cdd06e1594 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -46,6 +46,11 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase */ private $resolvedTypeFactory; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $builder; + /** * @var FormFactory */ @@ -57,6 +62,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface'); $this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface'); $this->registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface'); + $this->builder = $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface'); $this->factory = new FormFactory($this->registry, $this->resolvedTypeFactory); $this->registry->expects($this->any()) @@ -70,6 +76,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase public function testCreateNamedBuilderWithTypeName() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); $this->registry->expects($this->once()) @@ -80,14 +87,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $options) - ->will($this->returnValue('BUILDER')); + ->will($this->returnValue($this->builder)); - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', null, $options)); + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', null, $options)); } public function testCreateNamedBuilderWithTypeInstance() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $type = new FooType(); $resolvedType = $this->getMockResolvedType(); @@ -99,14 +115,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $options) - ->will($this->returnValue('BUILDER')); + ->will($this->returnValue($this->builder)); - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options)); + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $type, null, $options)); } public function testCreateNamedBuilderWithTypeInstanceWithParentType() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $type = new FooSubType(); $resolvedType = $this->getMockResolvedType(); $parentResolvedType = $this->getMockResolvedType(); @@ -124,14 +149,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $options) - ->will($this->returnValue('BUILDER')); + ->will($this->returnValue($this->builder)); - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options)); + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $type, null, $options)); } public function testCreateNamedBuilderWithTypeInstanceWithParentTypeInstance() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $type = new FooSubTypeWithParentInstance(); $resolvedType = $this->getMockResolvedType(); $parentResolvedType = $this->getMockResolvedType(); @@ -149,28 +183,46 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $options) - ->will($this->returnValue('BUILDER')); + ->will($this->returnValue($this->builder)); - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options)); + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $type, null, $options)); } public function testCreateNamedBuilderWithResolvedTypeInstance() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $options) - ->will($this->returnValue('BUILDER')); + ->will($this->returnValue($this->builder)); - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $resolvedType, null, $options)); + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $resolvedType, null, $options)); } public function testCreateNamedBuilderFillsDataOption() { $givenOptions = array('a' => '1', 'b' => '2'); $expectedOptions = array_merge($givenOptions, array('data' => 'DATA')); + $resolvedOptions = array('a' => '2', 'b' => '3', 'data' => 'DATA'); $resolvedType = $this->getMockResolvedType(); $this->registry->expects($this->once()) @@ -181,14 +233,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $expectedOptions) - ->will($this->returnValue('BUILDER')); + ->will($this->returnValue($this->builder)); - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $givenOptions)); + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', 'DATA', $givenOptions)); } public function testCreateNamedBuilderDoesNotOverrideExistingDataOption() { $options = array('a' => '1', 'b' => '2', 'data' => 'CUSTOM'); + $resolvedOptions = array('a' => '2', 'b' => '3', 'data' => 'CUSTOM'); $resolvedType = $this->getMockResolvedType(); $this->registry->expects($this->once()) @@ -199,9 +260,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $options) - ->will($this->returnValue('BUILDER')); + ->will($this->returnValue($this->builder)); - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $options)); + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', 'DATA', $options)); } /** @@ -216,8 +285,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase public function testCreateUsesTypeNameIfTypeGivenAsString() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $builder = $this->getMockFormBuilder(); $this->registry->expects($this->once()) ->method('getType') @@ -227,9 +296,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'TYPE', $options) - ->will($this->returnValue($builder)); + ->will($this->returnValue($this->builder)); - $builder->expects($this->once()) + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->builder->expects($this->once()) ->method('getForm') ->will($this->returnValue('FORM')); @@ -239,8 +316,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase public function testCreateUsesTypeNameIfTypeGivenAsObject() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $builder = $this->getMockFormBuilder(); $resolvedType->expects($this->once()) ->method('getName') @@ -249,9 +326,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'TYPE', $options) - ->will($this->returnValue($builder)); + ->will($this->returnValue($this->builder)); - $builder->expects($this->once()) + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->builder->expects($this->once()) ->method('getForm') ->will($this->returnValue('FORM')); @@ -261,8 +346,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase public function testCreateNamed() { $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $builder = $this->getMockFormBuilder(); $this->registry->expects($this->once()) ->method('getType') @@ -272,9 +357,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $resolvedType->expects($this->once()) ->method('createBuilder') ->with($this->factory, 'name', $options) - ->will($this->returnValue($builder)); + ->will($this->returnValue($this->builder)); - $builder->expects($this->once()) + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->builder->expects($this->once()) ->method('getForm') ->will($this->returnValue('FORM')); @@ -294,9 +387,9 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->with('firstName', 'text', null, array()) ->will($this->returnValue('builderInstance')); - $builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); + $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertEquals('builderInstance', $builder); + $this->assertEquals('builderInstance', $this->builder); } public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence() @@ -326,9 +419,9 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->with('firstName', 'password', null, array('max_length' => 7)) ->will($this->returnValue('builderInstance')); - $builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); + $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertEquals('builderInstance', $builder); + $this->assertEquals('builderInstance', $this->builder); } public function testCreateBuilderCreatesTextFormIfNoGuess() @@ -345,9 +438,9 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->with('firstName', 'text') ->will($this->returnValue('builderInstance')); - $builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); + $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertEquals('builderInstance', $builder); + $this->assertEquals('builderInstance', $this->builder); } public function testOptionsCanBeOverridden() @@ -368,14 +461,14 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->with('firstName', 'text', null, array('max_length' => 11)) ->will($this->returnValue('builderInstance')); - $builder = $factory->createBuilderForProperty( + $this->builder = $factory->createBuilderForProperty( 'Application\Author', 'firstName', null, array('max_length' => 11) ); - $this->assertEquals('builderInstance', $builder); + $this->assertEquals('builderInstance', $this->builder); } public function testCreateBuilderUsesMaxLengthIfFound() @@ -403,12 +496,12 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->with('firstName', 'text', null, array('max_length' => 20)) ->will($this->returnValue('builderInstance')); - $builder = $factory->createBuilderForProperty( + $this->builder = $factory->createBuilderForProperty( 'Application\Author', 'firstName' ); - $this->assertEquals('builderInstance', $builder); + $this->assertEquals('builderInstance', $this->builder); } public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() @@ -436,12 +529,12 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->with('firstName', 'text', null, array('required' => false)) ->will($this->returnValue('builderInstance')); - $builder = $factory->createBuilderForProperty( + $this->builder = $factory->createBuilderForProperty( 'Application\Author', 'firstName' ); - $this->assertEquals('builderInstance', $builder); + $this->assertEquals('builderInstance', $this->builder); } public function testCreateBuilderUsesPatternIfFound() @@ -469,12 +562,12 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->with('firstName', 'text', null, array('pattern' => '[a-zA-Z]')) ->will($this->returnValue('builderInstance')); - $builder = $factory->createBuilderForProperty( + $this->builder = $factory->createBuilderForProperty( 'Application\Author', 'firstName' ); - $this->assertEquals('builderInstance', $builder); + $this->assertEquals('builderInstance', $this->builder); } private function getMockFactory(array $methods = array()) @@ -494,9 +587,4 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase { return $this->getMock('Symfony\Component\Form\FormTypeInterface'); } - - private function getMockFormBuilder() - { - return $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface'); - } } diff --git a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php index de19e9783e..cf2275f8d4 100644 --- a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php @@ -36,12 +36,71 @@ class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase * @var \PHPUnit_Framework_MockObject_MockObject */ private $dataMapper; + private $parentType; + private $type; + private $extension1; + private $extension2; + private $parentResolvedType; + private $resolvedType; protected function setUp() { $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface'); $this->dataMapper = $this->getMock('Symfony\Component\Form\DataMapperInterface'); + $this->parentType = $this->getMockFormType(); + $this->type = $this->getMockFormType(); + $this->extension1 = $this->getMockFormTypeExtension(); + $this->extension2 = $this->getMockFormTypeExtension(); + $this->parentResolvedType = new ResolvedFormType($this->parentType); + $this->resolvedType = new ResolvedFormType($this->type, array($this->extension1, $this->extension2), $this->parentResolvedType); + } + + public function testGetOptionsResolver() + { + if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) { + $this->markTestSkipped('This test requires PHPUnit 3.7.'); + } + + $test = $this; + $i = 0; + + $assertIndexAndAddOption = function ($index, $option, $default) use (&$i, $test) { + return function (OptionsResolverInterface $resolver) use (&$i, $test, $index, $option, $default) { + /* @var \PHPUnit_Framework_TestCase $test */ + $test->assertEquals($index, $i, 'Executed at index '.$index); + + ++$i; + + $resolver->setDefaults(array($option => $default)); + }; + }; + + // First the default options are generated for the super type + $this->parentType->expects($this->once()) + ->method('setDefaultOptions') + ->will($this->returnCallback($assertIndexAndAddOption(0, 'a', 'a_default'))); + + // The form type itself + $this->type->expects($this->once()) + ->method('setDefaultOptions') + ->will($this->returnCallback($assertIndexAndAddOption(1, 'b', 'b_default'))); + + // And its extensions + $this->extension1->expects($this->once()) + ->method('setDefaultOptions') + ->will($this->returnCallback($assertIndexAndAddOption(2, 'c', 'c_default'))); + + $this->extension2->expects($this->once()) + ->method('setDefaultOptions') + ->will($this->returnCallback($assertIndexAndAddOption(3, 'd', 'd_default'))); + + $givenOptions = array('a' => 'a_custom', 'c' => 'c_custom'); + $resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default'); + + $resolver = $this->resolvedType->getOptionsResolver(); + + $this->assertEquals($resolvedOptions, $resolver->resolve($givenOptions)); } public function testCreateBuilder() @@ -50,13 +109,70 @@ class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase $this->markTestSkipped('This test requires PHPUnit 3.7.'); } - $parentType = $this->getMockFormType(); - $type = $this->getMockFormType(); - $extension1 = $this->getMockFormTypeExtension(); - $extension2 = $this->getMockFormTypeExtension(); + $givenOptions = array('a' => 'a_custom', 'c' => 'c_custom'); + $resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default'); + $optionsResolver = $this->getMock('Symfony\Component\OptionsResolver\OptionsResolverInterface'); - $parentResolvedType = new ResolvedFormType($parentType); - $resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType); + $this->resolvedType = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormType') + ->setConstructorArgs(array($this->type, array($this->extension1, $this->extension2), $this->parentResolvedType)) + ->setMethods(array('getOptionsResolver')) + ->getMock(); + + $this->resolvedType->expects($this->once()) + ->method('getOptionsResolver') + ->will($this->returnValue($optionsResolver)); + + $optionsResolver->expects($this->once()) + ->method('resolve') + ->with($givenOptions) + ->will($this->returnValue($resolvedOptions)); + + $factory = $this->getMockFormFactory(); + $builder = $this->resolvedType->createBuilder($factory, 'name', $givenOptions); + + $this->assertSame($this->resolvedType, $builder->getType()); + $this->assertSame($resolvedOptions, $builder->getOptions()); + $this->assertNull($builder->getDataClass()); + } + + public function testCreateBuilderWithDataClassOption() + { + if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) { + $this->markTestSkipped('This test requires PHPUnit 3.7.'); + } + + $givenOptions = array('data_class' => 'Foo'); + $resolvedOptions = array('data_class' => '\stdClass'); + $optionsResolver = $this->getMock('Symfony\Component\OptionsResolver\OptionsResolverInterface'); + + $this->resolvedType = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormType') + ->setConstructorArgs(array($this->type, array($this->extension1, $this->extension2), $this->parentResolvedType)) + ->setMethods(array('getOptionsResolver')) + ->getMock(); + + $this->resolvedType->expects($this->once()) + ->method('getOptionsResolver') + ->will($this->returnValue($optionsResolver)); + + $optionsResolver->expects($this->once()) + ->method('resolve') + ->with($givenOptions) + ->will($this->returnValue($resolvedOptions)); + + $factory = $this->getMockFormFactory(); + $builder = $this->resolvedType->createBuilder($factory, 'name', $givenOptions); + + $this->assertSame($this->resolvedType, $builder->getType()); + $this->assertSame($resolvedOptions, $builder->getOptions()); + $this->assertSame('\stdClass', $builder->getDataClass()); + } + + + public function testBuildForm() + { + if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) { + $this->markTestSkipped('This test requires PHPUnit 3.7.'); + } $test = $this; $i = 0; @@ -70,169 +186,142 @@ class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase }; }; - $assertIndexAndAddOption = function ($index, $option, $default) use ($assertIndex) { - $assertIndex = $assertIndex($index); + $options = array('a' => 'Foo', 'b' => 'Bar'); + $builder = $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface'); - return function (OptionsResolverInterface $resolver) use ($assertIndex, $index, $option, $default) { - $assertIndex(); - - $resolver->setDefaults(array($option => $default)); - }; - }; - - // First the default options are generated for the super type - $parentType->expects($this->once()) - ->method('setDefaultOptions') - ->will($this->returnCallback($assertIndexAndAddOption(0, 'a', 'a_default'))); - - // The form type itself - $type->expects($this->once()) - ->method('setDefaultOptions') - ->will($this->returnCallback($assertIndexAndAddOption(1, 'b', 'b_default'))); - - // And its extensions - $extension1->expects($this->once()) - ->method('setDefaultOptions') - ->will($this->returnCallback($assertIndexAndAddOption(2, 'c', 'c_default'))); - - $extension2->expects($this->once()) - ->method('setDefaultOptions') - ->will($this->returnCallback($assertIndexAndAddOption(3, 'd', 'd_default'))); - - $givenOptions = array('a' => 'a_custom', 'c' => 'c_custom'); - $resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default'); - - // Then the form is built for the super type - $parentType->expects($this->once()) + // First the form is built for the super type + $this->parentType->expects($this->once()) ->method('buildForm') - ->with($this->anything(), $resolvedOptions) - ->will($this->returnCallback($assertIndex(4))); + ->with($builder, $options) + ->will($this->returnCallback($assertIndex(0))); // Then the type itself - $type->expects($this->once()) + $this->type->expects($this->once()) ->method('buildForm') - ->with($this->anything(), $resolvedOptions) - ->will($this->returnCallback($assertIndex(5))); + ->with($builder, $options) + ->will($this->returnCallback($assertIndex(1))); // Then its extensions - $extension1->expects($this->once()) + $this->extension1->expects($this->once()) ->method('buildForm') - ->with($this->anything(), $resolvedOptions) - ->will($this->returnCallback($assertIndex(6))); + ->with($builder, $options) + ->will($this->returnCallback($assertIndex(2))); - $extension2->expects($this->once()) + $this->extension2->expects($this->once()) ->method('buildForm') - ->with($this->anything(), $resolvedOptions) - ->will($this->returnCallback($assertIndex(7))); + ->with($builder, $options) + ->will($this->returnCallback($assertIndex(3))); - $factory = $this->getMockFormFactory(); - $builder = $resolvedType->createBuilder($factory, 'name', $givenOptions); - - $this->assertSame($resolvedType, $builder->getType()); + $this->resolvedType->buildForm($builder, $options); } public function testCreateView() { - $parentType = $this->getMockFormType(); - $type = $this->getMockFormType(); - $field1Type = $this->getMockFormType(); - $field2Type = $this->getMockFormType(); - $extension1 = $this->getMockFormTypeExtension(); - $extension2 = $this->getMockFormTypeExtension(); + $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $parentResolvedType = new ResolvedFormType($parentType); - $resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType); - $field1ResolvedType = new ResolvedFormType($field1Type); - $field2ResolvedType = new ResolvedFormType($field2Type); + $view = $this->resolvedType->createView($form); + $this->assertInstanceOf('Symfony\Component\Form\FormView', $view); + $this->assertNull($view->parent); + } + + public function testCreateViewWithParent() + { + $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); + $parentView = $this->getMock('Symfony\Component\Form\FormView'); + + $view = $this->resolvedType->createView($form, $parentView); + + $this->assertInstanceOf('Symfony\Component\Form\FormView', $view); + $this->assertSame($parentView, $view->parent); + } + + public function testBuildView() + { $options = array('a' => '1', 'b' => '2'); - $form = $this->getBuilder('name', $options) - ->setCompound(true) - ->setDataMapper($this->dataMapper) - ->setType($resolvedType) - ->add($this->getBuilder('foo')->setType($field1ResolvedType)) - ->add($this->getBuilder('bar')->setType($field2ResolvedType)) - ->getForm(); + $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); + $view = $this->getMock('Symfony\Component\Form\FormView'); $test = $this; $i = 0; - $assertIndexAndNbOfChildViews = function ($index, $nbOfChildViews) use (&$i, $test) { - return function (FormView $view) use (&$i, $test, $index, $nbOfChildViews) { + $assertIndex = function ($index) use (&$i, $test) { + return function () use (&$i, $test, $index) { /* @var \PHPUnit_Framework_TestCase $test */ $test->assertEquals($index, $i, 'Executed at index '.$index); - $test->assertCount($nbOfChildViews, $view); ++$i; }; }; // First the super type - $parentType->expects($this->once()) + $this->parentType->expects($this->once()) ->method('buildView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(0, 0))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(0))); // Then the type itself - $type->expects($this->once()) + $this->type->expects($this->once()) ->method('buildView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(1, 0))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(1))); // Then its extensions - $extension1->expects($this->once()) + $this->extension1->expects($this->once()) ->method('buildView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(2, 0))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(2))); - $extension2->expects($this->once()) + $this->extension2->expects($this->once()) ->method('buildView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(3, 0))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(3))); - // Now the first child form - $field1Type->expects($this->once()) - ->method('buildView') - ->will($this->returnCallback($assertIndexAndNbOfChildViews(4, 0))); - $field1Type->expects($this->once()) + $this->resolvedType->buildView($view, $form, $options); + } + + public function testFinishView() + { + $options = array('a' => '1', 'b' => '2'); + $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); + $view = $this->getMock('Symfony\Component\Form\FormView'); + + $test = $this; + $i = 0; + + $assertIndex = function ($index) use (&$i, $test) { + return function () use (&$i, $test, $index) { + /* @var \PHPUnit_Framework_TestCase $test */ + $test->assertEquals($index, $i, 'Executed at index '.$index); + + ++$i; + }; + }; + + // First the super type + $this->parentType->expects($this->once()) ->method('finishView') - ->will($this->returnCallback($assertIndexAndNbOfChildViews(5, 0))); - - // And the second child form - $field2Type->expects($this->once()) - ->method('buildView') - ->will($this->returnCallback($assertIndexAndNbOfChildViews(6, 0))); - $field2Type->expects($this->once()) - ->method('finishView') - ->will($this->returnCallback($assertIndexAndNbOfChildViews(7, 0))); - - // Again first the parent - $parentType->expects($this->once()) - ->method('finishView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(8, 2))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(0))); // Then the type itself - $type->expects($this->once()) + $this->type->expects($this->once()) ->method('finishView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(9, 2))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(1))); // Then its extensions - $extension1->expects($this->once()) + $this->extension1->expects($this->once()) ->method('finishView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(10, 2))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(2))); - $extension2->expects($this->once()) + $this->extension2->expects($this->once()) ->method('finishView') - ->with($this->anything(), $form, $options) - ->will($this->returnCallback($assertIndexAndNbOfChildViews(11, 2))); + ->with($view, $form, $options) + ->will($this->returnCallback($assertIndex(3))); - $parentView = new FormView(); - $view = $resolvedType->createView($form, $parentView); - - $this->assertSame($parentView, $view->parent); + $this->resolvedType->finishView($view, $form, $options); } /**