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 f4d1c75

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

16 files changed

+152
-1
lines changed

‎UPGRADE-5.1.md

Copy file name to clipboard
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
UPGRADE FROM 5.0 to 5.1
2+
=======================
3+
4+
Form
5+
----
6+
7+
* Implementing the `FormConfigInterface` without implementing the `getIsEmptyCallback()` method
8+
is deprecated. The method will be added to the interface in 6.0.
9+
* Implementing the `FormConfigBuilderInterface` without implementing the `setIsEmptyCallback()` method
10+
is deprecated. The method will be added to the interface in 6.0.

‎UPGRADE-6.0.md

Copy file name to clipboard
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
UPGRADE FROM 5.x to 6.0
2+
=======================
3+
4+
Form
5+
----
6+
7+
* Added the `getIsEmptyCallback()` method to the `FormConfigInterface`.
8+
* Added the `setIsEmptyCallback()` method to the `FormConfigBuilderInterface`.

‎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
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
CHANGELOG
22
=========
33

4+
5.1.0
5+
-----
6+
7+
* Implementing the `FormConfigInterface` without implementing the `getIsEmptyCallback()` method
8+
is deprecated. The method will be added to the interface in 6.0.
9+
* Implementing the `FormConfigBuilderInterface` without implementing the `setIsEmptyCallback()` method
10+
is deprecated. The method will be added to the interface in 6.0.
11+
412
5.0.0
513
-----
614

‎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
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
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\FormConfigBuilder;
19+
use Symfony\Component\Form\FormConfigBuilderInterface;
1820
use Symfony\Component\Form\FormInterface;
1921
use Symfony\Component\Form\FormView;
2022
use Symfony\Component\OptionsResolver\Options;
@@ -58,6 +60,14 @@ public function buildForm(FormBuilderInterface $builder, array $options)
5860
if ($options['trim']) {
5961
$builder->addEventSubscriber(new TrimListener());
6062
}
63+
64+
if (!method_exists($builder, 'setIsEmptyCallback')) {
65+
@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);
66+
67+
return;
68+
}
69+
70+
$builder->setIsEmptyCallback($options['is_empty_callback']);
6171
}
6272

6373
/**
@@ -190,13 +200,15 @@ public function configureOptions(OptionsResolver $resolver)
190200
'help_attr' => [],
191201
'help_html' => false,
192202
'help_translation_parameters' => [],
203+
'is_empty_callback' => null,
193204
]);
194205

195206
$resolver->setAllowedTypes('label_attr', 'array');
196207
$resolver->setAllowedTypes('upload_max_size_message', ['callable']);
197208
$resolver->setAllowedTypes('help', ['string', 'null']);
198209
$resolver->setAllowedTypes('help_attr', 'array');
199210
$resolver->setAllowedTypes('help_html', 'bool');
211+
$resolver->setAllowedTypes('is_empty_callback', ['null', 'callable']);
200212
}
201213

202214
/**

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Form.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,15 @@ public function isEmpty()
726726
}
727727
}
728728

729-
return FormUtil::isEmpty($this->modelData) ||
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+
return $isEmptyCallback ? $isEmptyCallback($this->modelData) : FormUtil::isEmpty($this->modelData) ||
730738
// arrays, countables
731739
((\is_array($this->modelData) || $this->modelData instanceof \Countable) && 0 === \count($this->modelData)) ||
732740
// traversables that are not countable

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/FormConfigBuilder.php
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
1717
use Symfony\Component\Form\Exception\BadMethodCallException;
1818
use Symfony\Component\Form\Exception\InvalidArgumentException;
19+
use Symfony\Component\Form\Util\FormUtil;
1920
use Symfony\Component\PropertyAccess\PropertyPath;
2021
use Symfony\Component\PropertyAccess\PropertyPathInterface;
2122

@@ -103,6 +104,8 @@ class FormConfigBuilder implements FormConfigBuilderInterface
103104
private $autoInitialize = false;
104105
private $options;
105106

107+
private $isEmptyCallback;
108+
106109
/**
107110
* Creates an empty form configuration.
108111
*
@@ -461,6 +464,11 @@ public function getOption(string $name, $default = null)
461464
return \array_key_exists($name, $this->options) ? $this->options[$name] : $default;
462465
}
463466

467+
public function getIsEmptyCallback(): ?callable
468+
{
469+
return $this->isEmptyCallback;
470+
}
471+
464472
/**
465473
* {@inheritdoc}
466474
*/
@@ -761,6 +769,16 @@ public function getFormConfig()
761769
return $config;
762770
}
763771

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

‎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.