From d6e1f39d09cbd90c5ca58bac87c393637c60dd17 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Fri, 6 Jul 2012 17:32:57 +0200 Subject: [PATCH] [Form] Fixed FormBuilder to maintain order of its children --- src/Symfony/Component/Form/CHANGELOG.md | 1 + src/Symfony/Component/Form/FormBuilder.php | 2 + .../Component/Form/Tests/FormBuilderTest.php | 56 +++++++++++++------ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 2d0e527291..a064a9e90c 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -139,3 +139,4 @@ CHANGELOG * deprecated `getChildren` in Form and FormBuilder in favor of `all` * deprecated `hasChildren` in Form and FormBuilder in favor of `count` * FormBuilder now implements \IteratorAggregate + * FormBuilder now maintains the order when explicitely adding form builders as children diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index fb6f5d6dc8..cc759f65fb 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -103,6 +103,8 @@ class FormBuilder extends FormConfig implements \IteratorAggregate, FormBuilderI throw new CircularReferenceException(is_string($type) ? $this->getFormFactory()->getType($type) : $type); } + // Add to "children" to maintain order + $this->children[$child] = null; $this->unresolvedChildren[$child] = array( 'type' => $type, 'options' => $options, diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php index 3101541b79..52dcebc46f 100644 --- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php @@ -100,6 +100,20 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('foo', $children); } + /* + * https://github.com/symfony/symfony/issues/4693 + */ + public function testMaintainOrderOfLazyAndExplicitChildren() + { + $this->builder->add('foo', 'text'); + $this->builder->add($this->getFormBuilder('bar')); + $this->builder->add('baz', 'text'); + + $children = $this->builder->all(); + + $this->assertSame(array('foo', 'bar', 'baz'), array_keys($children)); + } + public function testAddFormType() { $this->assertFalse($this->builder->has('foo')); @@ -120,14 +134,14 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $this->assertFalse($this->builder->has('foo')); } - public function testCreateNoTypeNoDataClass() + public function testCreateNoTypeNo() { $this->factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('foo', 'text', null, array()) + ->method('createNamedBuilder') + ->with('foo', 'text', null, array()) ; - $builder = $this->builder->create('foo'); + $this->builder->create('foo'); } public function testGetUnknown() @@ -136,16 +150,16 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $this->builder->get('foo'); } - public function testGetTyped() + public function testGetExplicitType() { $expectedType = 'text'; $expectedName = 'foo'; $expectedOptions = array('bar' => 'baz'); $this->factory->expects($this->once()) - ->method('createNamedBuilder') - ->with($expectedName, $expectedType, null, $expectedOptions) - ->will($this->returnValue($this->getFormBuilder())); + ->method('createNamedBuilder') + ->with($expectedName, $expectedType, null, $expectedOptions) + ->will($this->returnValue($this->getFormBuilder())); $this->builder->add($expectedName, $expectedType, $expectedOptions); $builder = $this->builder->get($expectedName); @@ -153,15 +167,15 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $this->assertNotSame($builder, $this->builder); } - public function testGetGuessed() + public function testGetGuessedType() { $expectedName = 'foo'; $expectedOptions = array('bar' => 'baz'); $this->factory->expects($this->once()) - ->method('createBuilderForProperty') - ->with('stdClass', $expectedName, null, $expectedOptions) - ->will($this->returnValue($this->getFormBuilder())); + ->method('createBuilderForProperty') + ->with('stdClass', $expectedName, null, $expectedOptions) + ->will($this->returnValue($this->getFormBuilder())); $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory); $this->builder->add($expectedName, null, $expectedOptions); @@ -195,24 +209,30 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory); $this->factory ->expects($this->once()) - ->method('createNamedBuilder') - ->with('bar', 'text', null, array(), $this->builder) + ->method('createNamedBuilder') + ->with('bar', 'text', null, array(), $this->builder) ; $this->factory ->expects($this->once()) - ->method('createBuilderForProperty') - ->with('stdClass', 'foo', null, array(), $this->builder) + ->method('createBuilderForProperty') + ->with('stdClass', 'foo', null, array(), $this->builder) ; $this->builder->create('foo'); $this->builder->create('bar', 'text'); } - private function getFormBuilder() + private function getFormBuilder($name = 'name') { - return $this->getMockBuilder('Symfony\Component\Form\FormBuilder') + $mock = $this->getMockBuilder('Symfony\Component\Form\FormBuilder') ->disableOriginalConstructor() ->getMock(); + + $mock->expects($this->any()) + ->method('getName') + ->will($this->returnValue($name)); + + return $mock; } }