From 50e6218b4b8f5ab1d6443a0ea267e7a2de380513 Mon Sep 17 00:00:00 2001 From: Bart van den Burg Date: Tue, 6 Mar 2012 11:14:53 +0100 Subject: [PATCH] made sure the child type default options are passed to the parent when calling the parent's getParent() method --- .../Doctrine/Form/Type/DoctrineType.php | 1 + src/Symfony/Component/Form/FormFactory.php | 17 ++++++++---- .../Component/Form/Fixtures/FooChildType.php | 26 +++++++++++++++++++ .../Component/Form/Fixtures/FooParentType.php | 19 ++++++++++++++ .../Tests/Component/Form/Fixtures/FooType.php | 3 ++- .../Tests/Component/Form/FormFactoryTest.php | 12 +++++++++ 6 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 tests/Symfony/Tests/Component/Form/Fixtures/FooChildType.php create mode 100644 tests/Symfony/Tests/Component/Form/Fixtures/FooParentType.php diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index 2b9161477e24d..39576caf5ee58 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -51,6 +51,7 @@ public function getDefaultOptions(array $options) 'query_builder' => null, 'loader' => null, 'group_by' => null, + 'choices' => null, ); $options = array_replace($defaultOptions, $options); diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index e82e0567ed7c2..26629a7e4eb8c 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -222,6 +222,7 @@ public function createNamedBuilder($type, $name, $data = null, array $options = $defaultOptions = array(); $optionValues = array(); $passedOptions = $options; + $parentOptions = $options; // Bottom-up determination of the type hierarchy // Start with the actual type and look for the parent type @@ -229,10 +230,6 @@ public function createNamedBuilder($type, $name, $data = null, array $options = // the root and the last entry being the leaf (the concrete type) while (null !== $type) { if ($type instanceof FormTypeInterface) { - if ($type->getName() == $type->getParent($options)) { - throw new FormException(sprintf('The form type name "%s" for class "%s" cannot be the same as the parent type.', $type->getName(), get_class($type))); - } - $this->addType($type); } elseif (is_string($type)) { $type = $this->getType($type); @@ -240,13 +237,23 @@ public function createNamedBuilder($type, $name, $data = null, array $options = throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface'); } + $parentOptions = array_replace($type->getDefaultOptions($parentOptions), $parentOptions); + foreach ($type->getExtensions() as $typeExtension) { + $parentOptions = array_replace($typeExtension->getDefaultOptions($parentOptions), $parentOptions); + } + + $parentType = $type->getParent($parentOptions); + if ($type->getName() == $parentType) { + throw new FormException(sprintf('The form type name "%s" for class "%s" cannot be the same as the parent type.', $type->getName(), get_class($type))); + } + array_unshift($types, $type); // getParent() cannot see default options set by this type nor // default options set by parent types // As a result, the options always have to be checked for // existence with isset() before using them in this method. - $type = $type->getParent($options); + $type = $parentType; } // Top-down determination of the options and default options diff --git a/tests/Symfony/Tests/Component/Form/Fixtures/FooChildType.php b/tests/Symfony/Tests/Component/Form/Fixtures/FooChildType.php new file mode 100644 index 0000000000000..46197788e9330 --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Fixtures/FooChildType.php @@ -0,0 +1,26 @@ + new FooParentType() + ); + } +} diff --git a/tests/Symfony/Tests/Component/Form/Fixtures/FooParentType.php b/tests/Symfony/Tests/Component/Form/Fixtures/FooParentType.php new file mode 100644 index 0000000000000..b92b334ce0c41 --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Fixtures/FooParentType.php @@ -0,0 +1,19 @@ + false, 'max_length' => null, 'a_or_b' => 'a', + 'parent' => null ); } @@ -44,6 +45,6 @@ public function getAllowedOptionValues(array $options) public function getParent(array $options) { - return null; + return $options['parent']; } } diff --git a/tests/Symfony/Tests/Component/Form/FormFactoryTest.php b/tests/Symfony/Tests/Component/Form/FormFactoryTest.php index 932cf0b38f841..faac4bfd2ab27 100644 --- a/tests/Symfony/Tests/Component/Form/FormFactoryTest.php +++ b/tests/Symfony/Tests/Component/Form/FormFactoryTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Form\Guess\TypeGuess; use Symfony\Tests\Component\Form\Fixtures\TestExtension; use Symfony\Tests\Component\Form\Fixtures\FooType; +use Symfony\Tests\Component\Form\Fixtures\FooChildType; use Symfony\Tests\Component\Form\Fixtures\FooTypeBarExtension; use Symfony\Tests\Component\Form\Fixtures\FooTypeBazExtension; @@ -530,6 +531,17 @@ public function testUnknownOption() ); $factory->createNamedBuilder($type, "text", "value", array("unknown" => "opt")); } + + public function testChildDefaultOptionIsPassedToChildsGetParentMethod() + { + $type = new FooChildType(); + + $builder = $this->factory->createNamedBuilder($type, 'foo_child'); + $this->assertEquals(3, count($builder->getTypes())); + + $builder = $this->factory->createNamedBuilder($type, 'foo_child', null, array('parent'=>null)); + $this->assertEquals(2, count($builder->getTypes())); + } private function createMockFactory(array $methods = array()) {