From 0b44d7492a76711f2ba0c6ce811f167dd745babf Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Sat, 22 Sep 2012 22:57:25 -0500 Subject: [PATCH 1/9] Added "partial" option to Form Defaults to "false". Bound data should bind all children. --- .../Form/Extension/Core/Type/FormType.php | 3 +++ .../Component/Form/FormConfigBuilder.php | 27 +++++++++++++++++++ .../Form/FormConfigBuilderInterface.php | 11 ++++++++ 3 files changed, 41 insertions(+) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 9dfa8af2717c7..fe2861ec471ae 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -41,6 +41,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) ->setByReference($options['by_reference']) ->setVirtual($options['virtual']) ->setCompound($options['compound']) + ->setPartial($options['partial']) ->setData(isset($options['data']) ? $options['data'] : null) ->setDataLocked(isset($options['data'])) ->setDataMapper($options['compound'] ? new PropertyPathMapper() : null) @@ -125,6 +126,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) 'attr' => $options['attr'], 'label_attr' => $options['label_attr'], 'compound' => $form->getConfig()->getCompound(), + 'partial' => $form->getConfig()->getPartial(), 'block_prefixes' => $blockPrefixes, 'unique_block_prefix' => $uniqueBlockPrefix, 'translation_domain' => $translationDomain, @@ -216,6 +218,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) 'label_attr' => array(), 'virtual' => false, 'compound' => true, + 'partial' => false, 'translation_domain' => null, )); diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index 9a21df464212d..4c4f4a58151b0 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -66,6 +66,11 @@ class FormConfigBuilder implements FormConfigBuilderInterface */ private $compound = false; + /** + * @var Boolean + */ + private $partial = false; + /** * @var ResolvedFormTypeInterface */ @@ -445,6 +450,14 @@ public function getCompound() return $this->compound; } + /** + * {@inheritdoc} + */ + public function getPartial() + { + return $this->partial; + } + /** * {@inheritdoc} */ @@ -787,6 +800,20 @@ public function setCompound($compound) return $this; } + /** + * {@inheritdoc} + */ + public function setPartial($partial) + { + if ($this->locked) { + throw new FormException('The config builder cannot be modified anymore.'); + } + + $this->partial = $partial; + + return $this; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/FormConfigBuilderInterface.php b/src/Symfony/Component/Form/FormConfigBuilderInterface.php index 35eff8790bd29..49d89492384a3 100644 --- a/src/Symfony/Component/Form/FormConfigBuilderInterface.php +++ b/src/Symfony/Component/Form/FormConfigBuilderInterface.php @@ -210,6 +210,17 @@ public function setVirtual($virtual); */ public function setCompound($compound); + /** + * Sets whether the form should support partial binding. + * + * @param Boolean $partial Whether the form should support partial binding. + * + * @return self The configuration object. + * + * @see FormConfigInterface::getPartial() + */ + public function setPartial($partial); + /** * Set the types. * From aa7d7950cc7eee133041061da57913cbcd4a7c93 Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Thu, 27 Sep 2012 13:33:26 -0700 Subject: [PATCH 2/9] Partial bind with null uses view data --- src/Symfony/Component/Form/Form.php | 2 ++ .../Component/Form/Tests/SimpleFormTest.php | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index ec3d5393a8382..e4b5cc7c876c2 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -509,6 +509,8 @@ public function bind($submittedData) // and radio buttons with empty values. if (is_scalar($submittedData)) { $submittedData = (string) $submittedData; + } elseif ($this->config->getPartial() && is_null($submittedData)) { + $submittedData = $this->getViewData(); } // Initialize errors in the very beginning so that we don't lose any diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 3a590b7509af3..b06f1f1a2d61a 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -89,6 +89,30 @@ public function testBindIsIgnoredIfDisabled() $this->assertTrue($form->isBound()); } + public function testPartialBindUsesViewDataIfNull() + { + $form = $this->getBuilder('name', new EventDispatcher()) + ->setPartial(true) + ->addViewTransformer(new FixedDataTransformer(array( + '' => '', + 'norm' => 'client', + ))) + ->addModelTransformer(new FixedDataTransformer(array( + '' => '', + 'app' => 'norm', + ))) + ->getForm() + ; + + $form->setData('app'); + + $form->bind(null); + + $this->assertEquals('app', $form->getData()); + $this->assertEquals('norm', $form->getNormData()); + $this->assertEquals('client', $form->getClientData()); + } + public function testNeverRequiredIfParentNotRequired() { $parent = $this->getBuilder()->setRequired(false)->getForm(); From f14d7530245277d105a12f088e834183bd130999 Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Fri, 28 Sep 2012 09:28:13 -0700 Subject: [PATCH 3/9] Renamed partial to ignore_missing --- .../Component/Form/Extension/Core/Type/FormType.php | 6 +++--- src/Symfony/Component/Form/FormConfigBuilder.php | 10 +++++----- .../Component/Form/FormConfigBuilderInterface.php | 4 ++-- src/Symfony/Component/Form/Tests/SimpleFormTest.php | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index fe2861ec471ae..cdc011be9ed28 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -41,7 +41,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) ->setByReference($options['by_reference']) ->setVirtual($options['virtual']) ->setCompound($options['compound']) - ->setPartial($options['partial']) + ->setIgnoreMissing($options['ignore_missing']) ->setData(isset($options['data']) ? $options['data'] : null) ->setDataLocked(isset($options['data'])) ->setDataMapper($options['compound'] ? new PropertyPathMapper() : null) @@ -126,7 +126,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) 'attr' => $options['attr'], 'label_attr' => $options['label_attr'], 'compound' => $form->getConfig()->getCompound(), - 'partial' => $form->getConfig()->getPartial(), + 'ignore_missing' => $form->getConfig()->getIgnoreMissing(), 'block_prefixes' => $blockPrefixes, 'unique_block_prefix' => $uniqueBlockPrefix, 'translation_domain' => $translationDomain, @@ -218,7 +218,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) 'label_attr' => array(), 'virtual' => false, 'compound' => true, - 'partial' => false, + 'ignore_missing' => null, 'translation_domain' => null, )); diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index 4c4f4a58151b0..96ab1c6d28997 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -69,7 +69,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface /** * @var Boolean */ - private $partial = false; + private $ignoreMissing = false; /** * @var ResolvedFormTypeInterface @@ -453,9 +453,9 @@ public function getCompound() /** * {@inheritdoc} */ - public function getPartial() + public function getIgnoreMissing() { - return $this->partial; + return $this->ignoreMissing; } /** @@ -803,13 +803,13 @@ public function setCompound($compound) /** * {@inheritdoc} */ - public function setPartial($partial) + public function setIgnoreMissing($ignoreMissing) { if ($this->locked) { throw new FormException('The config builder cannot be modified anymore.'); } - $this->partial = $partial; + $this->ignoreMissing = (Boolean) $ignoreMissing; return $this; } diff --git a/src/Symfony/Component/Form/FormConfigBuilderInterface.php b/src/Symfony/Component/Form/FormConfigBuilderInterface.php index 49d89492384a3..bccf58ec51158 100644 --- a/src/Symfony/Component/Form/FormConfigBuilderInterface.php +++ b/src/Symfony/Component/Form/FormConfigBuilderInterface.php @@ -213,13 +213,13 @@ public function setCompound($compound); /** * Sets whether the form should support partial binding. * - * @param Boolean $partial Whether the form should support partial binding. + * @param Boolean $ignoreMissing Whether the form should support partial binding. * * @return self The configuration object. * * @see FormConfigInterface::getPartial() */ - public function setPartial($partial); + public function setIgnoreMissing($ignoreMissing); /** * Set the types. diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index b06f1f1a2d61a..dce4d47b0e835 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -89,10 +89,10 @@ public function testBindIsIgnoredIfDisabled() $this->assertTrue($form->isBound()); } - public function testPartialBindUsesViewDataIfNull() + public function testBindUsesViewDataIfNullAndIgnoreMissing() { $form = $this->getBuilder('name', new EventDispatcher()) - ->setPartial(true) + ->setIgnoreMissing(true) ->addViewTransformer(new FixedDataTransformer(array( '' => '', 'norm' => 'client', From 8ca97522865d39ec0652fb061007f056cfbf55ce Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Sat, 13 Oct 2012 18:38:44 -0500 Subject: [PATCH 4/9] Form#getIgnoreMissing returns parent setting if not defined --- src/Symfony/Component/Form/Form.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index e4b5cc7c876c2..6ac3e542ef71a 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -180,6 +180,15 @@ public function getName() return $this->config->getName(); } + public function getIgnoreMissing() + { + if ($this->parent && null === $this->config->getIgnoreMissing()) { + return $this->parent->getIgnoreMissing(); + } + + return $this->config->getIgnoreMissing(); + } + /** * {@inheritdoc} */ From 216b94ab0c203e887e40148ce4211ca350804c0d Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Sat, 13 Oct 2012 18:39:35 -0500 Subject: [PATCH 5/9] ignoreMissing supports NULL and passes its value explicitly --- src/Symfony/Component/Form/FormConfigBuilder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index 96ab1c6d28997..a0fc51b34c7d7 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -69,7 +69,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface /** * @var Boolean */ - private $ignoreMissing = false; + private $ignoreMissing = null; /** * @var ResolvedFormTypeInterface @@ -809,7 +809,7 @@ public function setIgnoreMissing($ignoreMissing) throw new FormException('The config builder cannot be modified anymore.'); } - $this->ignoreMissing = (Boolean) $ignoreMissing; + $this->ignoreMissing = $ignoreMissing; return $this; } From c9c34b05db8cf23aae33850c423baa14a536b384 Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Sat, 13 Oct 2012 18:40:07 -0500 Subject: [PATCH 6/9] Testing Form#getIgnoreMissing & FormConfig#ignoreMissing --- .../Component/Form/Tests/SimpleFormTest.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index dce4d47b0e835..cfc1c3540e5b2 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -113,6 +113,39 @@ public function testBindUsesViewDataIfNullAndIgnoreMissing() $this->assertEquals('client', $form->getClientData()); } + public function testIgnoreMissingUsesParentSettingByDefault() + { + $parent = $this->getBuilder()->setIgnoreMissing(true)->getForm(); + $child = $this->getBuilder()->getForm(); + + $child->setParent($parent); + + $this->assertTrue($child->getIgnoreMissing()); + } + + public function testIgnoreMissingDefaultsToNull() + { + $form = $this->getBuilder()->getForm(); + $this->assertNull($form->getIgnoreMissing()); + } + + public function testIgnoreMissingUsesSetValue() + { + $parent = $this->getBuilder()->setIgnoreMissing(false)->getForm(); + $child = $this->getBuilder()->setIgnoreMissing(true)->getForm(); + + $child->setParent($parent); + + $this->assertTrue($child->getIgnoreMissing()); + + $parent = $this->getBuilder()->setIgnoreMissing(true)->getForm(); + $child = $this->getBuilder()->setIgnoreMissing(false)->getForm(); + + $child->setParent($parent); + + $this->assertFalse($child->getIgnoreMissing()); + } + public function testNeverRequiredIfParentNotRequired() { $parent = $this->getBuilder()->setRequired(false)->getForm(); From cbf92367c4439b7a9a783035cede87a6e7b3126d Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Sat, 13 Oct 2012 19:08:36 -0500 Subject: [PATCH 7/9] Form#bind checks Form#ignoreMissing instead of FormConfig --- src/Symfony/Component/Form/Form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 6ac3e542ef71a..979d7dc9a80ab 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -518,7 +518,7 @@ public function bind($submittedData) // and radio buttons with empty values. if (is_scalar($submittedData)) { $submittedData = (string) $submittedData; - } elseif ($this->config->getPartial() && is_null($submittedData)) { + } elseif ($this->getIgnoreMissing() && null === $submittedData) { $submittedData = $this->getViewData(); } From 81c8cbf194df9888f652aa185d589b42ee8293a6 Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Sat, 13 Oct 2012 20:56:59 -0500 Subject: [PATCH 8/9] Added FormConfigInterface#getIgnoreMissing --- src/Symfony/Component/Form/FormConfigInterface.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Symfony/Component/Form/FormConfigInterface.php b/src/Symfony/Component/Form/FormConfigInterface.php index 364d6a60b0a09..d89074df5607f 100644 --- a/src/Symfony/Component/Form/FormConfigInterface.php +++ b/src/Symfony/Component/Form/FormConfigInterface.php @@ -76,6 +76,16 @@ public function getVirtual(); */ public function getCompound(); + /** + * Returns whether the form explicitly supports missing children + * + * When enabled, missing child data uses pre-existing model data + * rather than defaulting to `null`. + * + * @return null|Boolean Whether the form explicitly supports missing children + */ + public function getIgnoreMissing(); + /** * Returns the form types used to construct the form. * From 55bcfd6902cb9a73061faa11406080fb23457897 Mon Sep 17 00:00:00 2001 From: Eric Clemmons Date: Sat, 13 Oct 2012 21:10:42 -0500 Subject: [PATCH 9/9] Removed implied null --- src/Symfony/Component/Form/FormConfigBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index a0fc51b34c7d7..8ddf84b08829f 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -69,7 +69,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface /** * @var Boolean */ - private $ignoreMissing = null; + private $ignoreMissing; /** * @var ResolvedFormTypeInterface