Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0226851

Browse filesBrowse files
committed
[Form] Add "is empty callback" to form config
1 parent b350c80 commit 0226851
Copy full SHA for 0226851

16 files changed

+147
-0
lines changed

‎UPGRADE-5.1.md

Copy file name to clipboardExpand all lines: UPGRADE-5.1.md
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ EventDispatcher
66

77
* Deprecated `LegacyEventDispatcherProxy`. Use the event dispatcher without the proxy.
88

9+
Form
10+
----
11+
12+
* Implementing the `FormConfigInterface` without implementing the `getIsEmptyCallback()` method
13+
is deprecated. The method will be added to the interface in 6.0.
14+
* Implementing the `FormConfigBuilderInterface` without implementing the `setIsEmptyCallback()` method
15+
is deprecated. The method will be added to the interface in 6.0.
16+
917
FrameworkBundle
1018
---------------
1119

‎UPGRADE-6.0.md

Copy file name to clipboardExpand all lines: UPGRADE-6.0.md
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ EventDispatcher
66

77
* Removed `LegacyEventDispatcherProxy`. Use the event dispatcher without the proxy.
88

9+
Form
10+
----
11+
12+
* Added the `getIsEmptyCallback()` method to the `FormConfigInterface`.
13+
* Added the `setIsEmptyCallback()` method to the `FormConfigBuilderInterface`.
14+
915
FrameworkBundle
1016
---------------
1117

‎src/Symfony/Component/Form/ButtonBuilder.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/ButtonBuilder.php
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,16 @@ public function getFormConfig()
466466
return $config;
467467
}
468468

469+
/**
470+
* Unsupported method.
471+
*
472+
* @throws BadMethodCallException
473+
*/
474+
public function setIsEmptyCallback(?callable $isEmptyCallback)
475+
{
476+
throw new BadMethodCallException('Buttons do not support "is empty" callback.');
477+
}
478+
469479
/**
470480
* Unsupported method.
471481
*/
@@ -738,6 +748,16 @@ public function getOption(string $name, $default = null)
738748
return \array_key_exists($name, $this->options) ? $this->options[$name] : $default;
739749
}
740750

751+
/**
752+
* Unsupported method.
753+
*
754+
* @throws BadMethodCallException
755+
*/
756+
public function getIsEmptyCallback(): ?callable
757+
{
758+
throw new BadMethodCallException('Buttons do not support "is empty" callback.');
759+
}
760+
741761
/**
742762
* Unsupported method.
743763
*

‎src/Symfony/Component/Form/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/CHANGELOG.md
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ CHANGELOG
66

77
* The `view_timezone` option defaults to the `model_timezone` if no `reference_date` is configured.
88
* Added default `inputmode` attribute to Search, Email and Tel form types.
9+
* Implementing the `FormConfigInterface` without implementing the `getIsEmptyCallback()` method
10+
is deprecated. The method will be added to the interface in 6.0.
11+
* Implementing the `FormConfigBuilderInterface` without implementing the `setIsEmptyCallback()` method
12+
is deprecated. The method will be added to the interface in 6.0.
913

1014
5.0.0
1115
-----

‎src/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public function configureOptions(OptionsResolver $resolver)
6060
'empty_data' => $emptyData,
6161
'compound' => false,
6262
'false_values' => [null],
63+
'is_empty_callback' => static function ($modelData): bool {
64+
return false === $modelData;
65+
},
6366
]);
6467

6568
$resolver->setAllowedTypes('false_values', 'array');

‎src/Symfony/Component/Form/Extension/Core/Type/FormType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
1616
use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
1717
use Symfony\Component\Form\FormBuilderInterface;
18+
use Symfony\Component\Form\FormConfigBuilderInterface;
1819
use Symfony\Component\Form\FormInterface;
1920
use Symfony\Component\Form\FormView;
2021
use Symfony\Component\OptionsResolver\Options;
@@ -58,6 +59,14 @@ public function buildForm(FormBuilderInterface $builder, array $options)
5859
if ($options['trim']) {
5960
$builder->addEventSubscriber(new TrimListener());
6061
}
62+
63+
if (!method_exists($builder, 'setIsEmptyCallback')) {
64+
@trigger_error(sprintf('Not implementing the "%s::setIsEmptyCallback()" method in "%s" is deprecated since Symfony 5.1.', FormConfigBuilderInterface::class, \get_class($builder)), E_USER_DEPRECATED);
65+
66+
return;
67+
}
68+
69+
$builder->setIsEmptyCallback($options['is_empty_callback']);
6170
}
6271

6372
/**
@@ -190,13 +199,15 @@ public function configureOptions(OptionsResolver $resolver)
190199
'help_attr' => [],
191200
'help_html' => false,
192201
'help_translation_parameters' => [],
202+
'is_empty_callback' => null,
193203
]);
194204

195205
$resolver->setAllowedTypes('label_attr', 'array');
196206
$resolver->setAllowedTypes('upload_max_size_message', ['callable']);
197207
$resolver->setAllowedTypes('help', ['string', 'null']);
198208
$resolver->setAllowedTypes('help_attr', 'array');
199209
$resolver->setAllowedTypes('help_html', 'bool');
210+
$resolver->setAllowedTypes('is_empty_callback', ['null', 'callable']);
200211
}
201212

202213
/**

‎src/Symfony/Component/Form/Form.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Form.php
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,18 @@ public function isEmpty()
726726
}
727727
}
728728

729+
if (!method_exists($this->config, 'getIsEmptyCallback')) {
730+
@trigger_error(sprintf('Not implementing the "%s::getIsEmptyCallback()" method in "%s" is deprecated since Symfony 5.1.', FormConfigInterface::class, \get_class($this->config)), E_USER_DEPRECATED);
731+
732+
$isEmptyCallback = null;
733+
} else {
734+
$isEmptyCallback = $this->config->getIsEmptyCallback();
735+
}
736+
737+
if (null !== $isEmptyCallback) {
738+
return $isEmptyCallback($this->modelData);
739+
}
740+
729741
return FormUtil::isEmpty($this->modelData) ||
730742
// arrays, countables
731743
((\is_array($this->modelData) || $this->modelData instanceof \Countable) && 0 === \count($this->modelData)) ||

‎src/Symfony/Component/Form/FormConfigBuilder.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/FormConfigBuilder.php
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
102102

103103
private $autoInitialize = false;
104104
private $options;
105+
private $isEmptyCallback;
105106

106107
/**
107108
* Creates an empty form configuration.
@@ -461,6 +462,14 @@ public function getOption(string $name, $default = null)
461462
return \array_key_exists($name, $this->options) ? $this->options[$name] : $default;
462463
}
463464

465+
/**
466+
* {@inheritdoc}
467+
*/
468+
public function getIsEmptyCallback(): ?callable
469+
{
470+
return $this->isEmptyCallback;
471+
}
472+
464473
/**
465474
* {@inheritdoc}
466475
*/
@@ -761,6 +770,16 @@ public function getFormConfig()
761770
return $config;
762771
}
763772

773+
/**
774+
* {@inheritdoc}
775+
*/
776+
public function setIsEmptyCallback(?callable $isEmptyCallback)
777+
{
778+
$this->isEmptyCallback = $isEmptyCallback;
779+
780+
return $this;
781+
}
782+
764783
/**
765784
* Validates whether the given variable is a valid form name.
766785
*

‎src/Symfony/Component/Form/FormConfigBuilderInterface.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/FormConfigBuilderInterface.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
/**
1818
* @author Bernhard Schussek <bschussek@gmail.com>
19+
*
20+
* @method $this setIsEmptyCallback(callable|null $isEmptyCallback) Sets the callback that will be called to determine if the model data of the form is empty or not - not implementing it is deprecated since Symfony 5.1
1921
*/
2022
interface FormConfigBuilderInterface extends FormConfigInterface
2123
{

‎src/Symfony/Component/Form/FormConfigInterface.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/FormConfigInterface.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
* The configuration of a {@link Form} object.
1919
*
2020
* @author Bernhard Schussek <bschussek@gmail.com>
21+
*
22+
* @method callable|null getIsEmptyCallback() Returns a callable that takes the model data as argument and that returns if it is empty or not - not implementing it is deprecated since Symfony 5.1
2123
*/
2224
interface FormConfigInterface
2325
{

‎src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
+41Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,4 +2049,45 @@ public function provideTrimCases()
20492049
'Multiple expanded' => [true, true],
20502050
];
20512051
}
2052+
2053+
/**
2054+
* @dataProvider expandedIsEmptyWhenNoRealChoiceIsSelectedProvider
2055+
*/
2056+
public function testExpandedIsEmptyWhenNoRealChoiceIsSelected(bool $expected, $submittedData, bool $multiple, bool $required, $placeholder)
2057+
{
2058+
$options = [
2059+
'expanded' => true,
2060+
'choices' => [
2061+
'foo' => 'bar',
2062+
],
2063+
'multiple' => $multiple,
2064+
'required' => $required,
2065+
];
2066+
2067+
if (!$multiple) {
2068+
$options['placeholder'] = $placeholder;
2069+
}
2070+
2071+
$form = $this->factory->create(static::TESTED_TYPE, null, $options);
2072+
2073+
$form->submit($submittedData);
2074+
2075+
$this->assertSame($expected, $form->isEmpty());
2076+
}
2077+
2078+
public function expandedIsEmptyWhenNoRealChoiceIsSelectedProvider()
2079+
{
2080+
// Some invalid cases are voluntarily not tested:
2081+
// - multiple with placeholder
2082+
// - required with placeholder
2083+
return [
2084+
'Nothing submitted / single / not required / without a placeholder -> should be empty' => [true, null, false, false, null],
2085+
'Nothing submitted / single / not required / with a placeholder -> should not be empty' => [false, null, false, false, 'ccc'], // It falls back on the placeholder
2086+
'Nothing submitted / single / required / without a placeholder -> should be empty' => [true, null, false, true, null],
2087+
'Nothing submitted / single / required / with a placeholder -> should be empty' => [true, null, false, true, 'ccc'],
2088+
'Nothing submitted / multiple / not required / without a placeholder -> should be empty' => [true, null, true, false, null],
2089+
'Nothing submitted / multiple / required / without a placeholder -> should be empty' => [true, null, true, true, null],
2090+
'Placeholder submitted / single / not required / with a placeholder -> should not be empty' => [false, '', false, false, 'ccc'], // The placeholder is a selected value
2091+
];
2092+
}
20522093
}

‎src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"help_html",
4343
"help_translation_parameters",
4444
"inherit_data",
45+
"is_empty_callback",
4546
"label",
4647
"label_attr",
4748
"label_format",

‎src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
2222
help_html
2323
help_translation_parameters
2424
inherit_data
25+
is_empty_callback
2526
label
2627
label_attr
2728
label_format

‎src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"help_html",
2323
"help_translation_parameters",
2424
"inherit_data",
25+
"is_empty_callback",
2526
"label",
2627
"label_attr",
2728
"label_format",

‎src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
2424
help_html
2525
help_translation_parameters
2626
inherit_data
27+
is_empty_callback
2728
label
2829
label_attr
2930
label_format

‎src/Symfony/Component/Form/Tests/SimpleFormTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/SimpleFormTest.php
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,21 @@ public function testCannotCallGetViewDataInPreSetDataListener()
10971097
$form->setData('foo');
10981098
}
10991099

1100+
public function testIsEmptyCallback()
1101+
{
1102+
$config = new FormConfigBuilder('foo', null, $this->dispatcher);
1103+
1104+
$config->setIsEmptyCallback(function ($modelData): bool { return 'ccc' === $modelData; });
1105+
$form = new Form($config);
1106+
$form->setData('ccc');
1107+
$this->assertTrue($form->isEmpty());
1108+
1109+
$config->setIsEmptyCallback(function (): bool { return false; });
1110+
$form = new Form($config);
1111+
$form->setData(null);
1112+
$this->assertFalse($form->isEmpty());
1113+
}
1114+
11001115
protected function createForm(): FormInterface
11011116
{
11021117
return $this->getBuilder()->getForm();

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.