diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index f47aeb95c4..92ee978311 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -113,6 +113,12 @@ class FormBuilder private $currentLoadingType; + /** + * The parent of this builder + * @var FormBuilder + */ + private $parent; + /** * Constructor. * @@ -532,6 +538,7 @@ class FormBuilder public function add($child, $type = null, array $options = array()) { if ($child instanceof self) { + $child->setParent($this); $this->children[$child->getName()] = $child; return $this; @@ -573,10 +580,10 @@ class FormBuilder } if (null !== $type) { - return $this->getFormFactory()->createNamedBuilder($type, $name, null, $options); + return $this->getFormFactory()->createNamedBuilder($type, $name, null, $options, $this); } - return $this->getFormFactory()->createBuilderForProperty($this->dataClass, $name, null, $options); + return $this->getFormFactory()->createBuilderForProperty($this->dataClass, $name, null, $options, $this); } /** @@ -615,6 +622,9 @@ class FormBuilder public function remove($name) { if (isset($this->children[$name])) { + if ($this->children[$name] instanceof self) { + $this->children[$name]->setParent(null); + } unset($this->children[$name]); } @@ -671,6 +681,30 @@ class FormBuilder $this->currentLoadingType = $type; } + /** + * Returns the parent builder. + * + * @return FormBuilder The parent builder + */ + public function getParent() + { + return $this->parent; + } + + /** + * Sets the parent builder. + * + * @param FormBuilder $parent The parent builder + * + * @return FormBuilder The current builder + */ + public function setParent(FormBuilder $parent = null) + { + $this->parent = $parent; + + return $this; + } + /** * Returns the event dispatcher. * diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index 152aa8794f..1f658303e8 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -128,14 +128,15 @@ class FormFactory implements FormFactoryInterface * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return Form The form named after the type * * @throws FormException if any given option is not applicable to the given type */ - public function create($type, $data = null, array $options = array()) + public function create($type, $data = null, array $options = array(), FormBuilder $parent = null) { - return $this->createBuilder($type, $data, $options)->getForm(); + return $this->createBuilder($type, $data, $options, $parent)->getForm(); } /** @@ -147,14 +148,15 @@ class FormFactory implements FormFactoryInterface * @param string $name The name of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return Form The form * * @throws FormException if any given option is not applicable to the given type */ - public function createNamed($type, $name, $data = null, array $options = array()) + public function createNamed($type, $name, $data = null, array $options = array(), FormBuilder $parent = null) { - return $this->createNamedBuilder($type, $name, $data, $options)->getForm(); + return $this->createNamedBuilder($type, $name, $data, $options, $parent)->getForm(); } /** @@ -162,18 +164,19 @@ class FormFactory implements FormFactoryInterface * * @see createBuilderForProperty() * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param mixed $data The initial data - * @param array $options The options for the builder + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param mixed $data The initial data + * @param array $options The options for the builder + * @param FormBuilder $parent The parent builder * * @return Form The form named after the property * * @throws FormException if any given option is not applicable to the form type */ - public function createForProperty($class, $property, $data = null, array $options = array()) + public function createForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null) { - return $this->createBuilderForProperty($class, $property, $data, $options)->getForm(); + return $this->createBuilderForProperty($class, $property, $data, $options, $parent)->getForm(); } /** @@ -182,16 +185,17 @@ class FormFactory implements FormFactoryInterface * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return FormBuilder The form builder * * @throws FormException if any given option is not applicable to the given type */ - public function createBuilder($type, $data = null, array $options = array()) + public function createBuilder($type, $data = null, array $options = array(), FormBuilder $parent = null) { $name = is_object($type) ? $type->getName() : $type; - return $this->createNamedBuilder($type, $name, $data, $options); + return $this->createNamedBuilder($type, $name, $data, $options, $parent); } /** @@ -201,12 +205,13 @@ class FormFactory implements FormFactoryInterface * @param string $name The name of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return FormBuilder The form builder * * @throws FormException if any given option is not applicable to the given type */ - public function createNamedBuilder($type, $name, $data = null, array $options = array()) + public function createNamedBuilder($type, $name, $data = null, array $options = array(), FormBuilder $parent = null) { $builder = null; $types = array(); @@ -278,6 +283,7 @@ class FormFactory implements FormFactoryInterface $builder->setTypes($types); $builder->setCurrentLoadingType($type->getName()); + $builder->setParent($parent); foreach ($types as $type) { $type->buildForm($builder, $options); @@ -297,16 +303,17 @@ class FormFactory implements FormFactoryInterface * If any of the 'max_length', 'required' and type options can be guessed, * and are not provided in the options argument, the guessed value is used. * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param mixed $data The initial data - * @param array $options The options for the builder + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param mixed $data The initial data + * @param array $options The options for the builder + * @param FormBuilder $parent The parent builder * * @return FormBuilder The form builder named after the property * * @throws FormException if any given option is not applicable to the form type */ - public function createBuilderForProperty($class, $property, $data = null, array $options = array()) + public function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null) { if (!$this->guesser) { $this->loadGuesser(); @@ -340,7 +347,7 @@ class FormFactory implements FormFactoryInterface $options = array_merge($typeGuess->getOptions(), $options); } - return $this->createNamedBuilder($type, $property, $data, $options); + return $this->createNamedBuilder($type, $property, $data, $options, $parent); } /** diff --git a/src/Symfony/Component/Form/FormFactoryInterface.php b/src/Symfony/Component/Form/FormFactoryInterface.php index 38ccd94bbc..13e1b69e5d 100644 --- a/src/Symfony/Component/Form/FormFactoryInterface.php +++ b/src/Symfony/Component/Form/FormFactoryInterface.php @@ -21,12 +21,13 @@ interface FormFactoryInterface * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return Form The form named after the type * * @throws FormException if any given option is not applicable to the given type */ - function create($type, $data = null, array $options = array()); + function create($type, $data = null, array $options = array(), FormBuilder $parent = null); /** * Returns a form. @@ -35,26 +36,28 @@ interface FormFactoryInterface * @param string $name The name of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return Form The form * * @throws FormException if any given option is not applicable to the given type */ - function createNamed($type, $name, $data = null, array $options = array()); + function createNamed($type, $name, $data = null, array $options = array(), FormBuilder $parent = null); /** * Returns a form for a property of a class. * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param mixed $data The initial data - * @param array $options The options for the builder + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param mixed $data The initial data + * @param array $options The options for the builder + * @param FormBuilder $parent The parent builder * * @return Form The form named after the property * * @throws FormException if any given option is not applicable to the form type */ - function createForProperty($class, $property, $data = null, array $options = array()); + function createForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null); /** * Returns a form builder @@ -62,12 +65,13 @@ interface FormFactoryInterface * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return FormBuilder The form builder * * @throws FormException if any given option is not applicable to the given type */ - function createBuilder($type, $data = null, array $options = array()); + function createBuilder($type, $data = null, array $options = array(), FormBuilder $parent = null); /** * Returns a form builder. @@ -76,12 +80,13 @@ interface FormFactoryInterface * @param string $name The name of the form * @param mixed $data The initial data * @param array $options The options + * @param FormBuilder $parent The parent builder * * @return FormBuilder The form builder * * @throws FormException if any given option is not applicable to the given type */ - function createNamedBuilder($type, $name, $data = null, array $options = array()); + function createNamedBuilder($type, $name, $data = null, array $options = array(), FormBuilder $parent = null); /** * Returns a form builder for a property of a class. @@ -89,16 +94,17 @@ interface FormFactoryInterface * If any of the 'max_length', 'required' and type options can be guessed, * and are not provided in the options argument, the guessed value is used. * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param mixed $data The initial data - * @param array $options The options for the builder + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param mixed $data The initial data + * @param array $options The options for the builder + * @param FormBuilder $parent The parent builder * * @return FormBuilder The form builder named after the property * * @throws FormException if any given option is not applicable to the form type */ - function createBuilderForProperty($class, $property, $data = null, array $options = array()); + function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilder $parent = null); function getType($name); diff --git a/tests/Symfony/Tests/Component/Form/FormBuilderTest.php b/tests/Symfony/Tests/Component/Form/FormBuilderTest.php index 505022d32a..6f0d0823dc 100644 --- a/tests/Symfony/Tests/Component/Form/FormBuilderTest.php +++ b/tests/Symfony/Tests/Component/Form/FormBuilderTest.php @@ -180,6 +180,45 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $this->assertNotSame($builder, $this->builder); } + public function testGetParent() + { + $this->assertNull($this->builder->getParent()); + } + + public function testGetParentForAddedBuilder() + { + $builder = new FormBuilder('name', $this->factory, $this->dispatcher); + $this->builder->add($builder); + $this->assertSame($this->builder, $builder->getParent()); + } + + public function testGetParentForRemovedBuilder() + { + $builder = new FormBuilder('name', $this->factory, $this->dispatcher); + $this->builder->add($builder); + $this->builder->remove('name'); + $this->assertNull($builder->getParent()); + } + + public function testGetParentForCreatedBuilder() + { + $this->builder = new FormBuilder('name', $this->factory, $this->dispatcher, 'stdClass'); + $this->factory + ->expects($this->once()) + ->method('createNamedBuilder') + ->with('text', 'bar', null, array(), $this->builder) + ; + + $this->factory + ->expects($this->once()) + ->method('createBuilderForProperty') + ->with('stdClass', 'foo', null, array(), $this->builder) + ; + + $this->builder->create('foo'); + $this->builder->create('bar', 'text'); + } + private function getFormBuilder() { return $this->getMockBuilder('Symfony\Component\Form\FormBuilder') diff --git a/tests/Symfony/Tests/Component/Form/FormFactoryTest.php b/tests/Symfony/Tests/Component/Form/FormFactoryTest.php index 6f36e5c4c0..932cf0b38f 100644 --- a/tests/Symfony/Tests/Component/Form/FormFactoryTest.php +++ b/tests/Symfony/Tests/Component/Form/FormFactoryTest.php @@ -116,6 +116,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $this->assertTrue($builder instanceof FormBuilder); $this->assertEquals('bar', $builder->getName()); + $this->assertEquals(null, $builder->getParent()); } public function testCreateNamedBuilderCallsBuildFormMethods() @@ -484,6 +485,22 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $this->assertEquals('builderInstance', $builder); } + public function testCreateNamedBuilderFromParentBuilder() + { + $type = new FooType(); + $this->extension1->addType($type); + + $parentBuilder = $this->getMockBuilder('Symfony\Component\Form\FormBuilder') + ->setConstructorArgs(array('name', $this->factory, $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'))) + ->getMock() + ; + + $builder = $this->factory->createNamedBuilder('foo', 'bar', null, array(), $parentBuilder); + + $this->assertNotEquals($builder, $builder->getParent()); + $this->assertEquals($parentBuilder, $builder->getParent()); + } + public function testUnknownOptions() { $type = new \Symfony\Component\Form\Extension\Core\Type\TextType();