Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 98df4f2

Browse files
committed
[Form] Is empty callback
1 parent f830226 commit 98df4f2

11 files changed

+137
-5
lines changed

UPGRADE-4.4.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ Form
7575
* Using different values for the "model_timezone" and "view_timezone" options of the `TimeType` without configuring a
7676
reference date is deprecated.
7777
* Using `int` or `float` as data for the `NumberType` when the `input` option is set to `string` is deprecated.
78+
* Added `getIsEmptyCallback()` method to `FormConfigInterface`.
79+
* Added `setIsEmptyCallback()` method to `FormConfigBuilderInterface`.
7880

7981
FrameworkBundle
8082
---------------

UPGRADE-5.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ Form
211211
```
212212

213213
* The `regions` option was removed from the `TimezoneType`.
214+
* Added the `getIsEmptyCallback()` method to `FormConfigInterface`.
215+
* Added the `setIsEmptyCallback()` method to `FormConfigBuilderInterface`.
214216

215217
FrameworkBundle
216218
---------------

src/Symfony/Component/Form/ButtonBuilder.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,16 @@ public function getFormConfig()
521521
return $config;
522522
}
523523

524+
/**
525+
* Unsupported method.
526+
*
527+
* @throws BadMethodCallException
528+
*/
529+
public function setIsEmptyCallback(callable $isEmptyCallback)
530+
{
531+
throw new BadMethodCallException('Buttons do not support "is empty" callback.');
532+
}
533+
524534
/**
525535
* Unsupported method.
526536
*/
@@ -799,6 +809,16 @@ public function getOption($name, $default = null)
799809
return \array_key_exists($name, $this->options) ? $this->options[$name] : $default;
800810
}
801811

812+
/**
813+
* Unsupported method.
814+
*
815+
* @throws BadMethodCallException
816+
*/
817+
public function getIsEmptyCallback(): callable
818+
{
819+
throw new BadMethodCallException('Buttons do not support "is empty" callback.');
820+
}
821+
802822
/**
803823
* Unsupported method.
804824
*

src/Symfony/Component/Form/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ CHANGELOG
99
* preferred choices are repeated in the list of all choices
1010
* deprecated using `int` or `float` as data for the `NumberType` when the `input` option is set to `string`
1111
* The type guesser guesses the HTML accept attribute when a mime type is configured in the File or Image constraint.
12+
* added the `getIsEmptyCallback()` method to `FormConfigInterface`
13+
* added the `setIsEmptyCallback()` method to `FormConfigBuilderInterface`
1214

1315
4.3.0
1416
-----

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Form\AbstractType;
1515
use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer;
1616
use Symfony\Component\Form\FormBuilderInterface;
17+
use Symfony\Component\Form\FormConfigBuilderInterface;
1718
use Symfony\Component\Form\FormInterface;
1819
use Symfony\Component\Form\FormView;
1920
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -33,6 +34,16 @@ public function buildForm(FormBuilderInterface $builder, array $options)
3334
// doing so also calls setDataLocked(true).
3435
$builder->setData(isset($options['data']) ? $options['data'] : false);
3536
$builder->addViewTransformer(new BooleanToStringTransformer($options['value'], $options['false_values']));
37+
38+
if (!method_exists($builder, 'setIsEmptyCallback')) {
39+
@trigger_error(sprintf('Not implementing the "%s::setIsEmptyCallback()" method in "%s" is deprecated since Symfony 4.4.', FormConfigBuilderInterface::class, \get_class($builder)), E_USER_DEPRECATED);
40+
41+
return;
42+
}
43+
44+
$builder->setIsEmptyCallback(static function ($modelData): bool {
45+
return false === $modelData;
46+
});
3647
}
3748

3849
/**

src/Symfony/Component/Form/Form.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -727,11 +727,13 @@ public function isEmpty()
727727
}
728728
}
729729

730-
return FormUtil::isEmpty($this->modelData) ||
731-
// arrays, countables
732-
((\is_array($this->modelData) || $this->modelData instanceof \Countable) && 0 === \count($this->modelData)) ||
733-
// traversables that are not countable
734-
($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData));
730+
if (!method_exists($this->config, 'getIsEmptyCallback')) {
731+
@trigger_error(sprintf('Not implementing the "%s::getIsEmptyCallback()" method in "%s" is deprecated since Symfony 4.4.', FormConfigInterface::class, \get_class($this->config)), E_USER_DEPRECATED);
732+
733+
return FormConfigBuilder::isEmpty($this->modelData);
734+
}
735+
736+
return $this->config->getIsEmptyCallback()($this->modelData);
735737
}
736738

737739
/**

src/Symfony/Component/Form/FormConfigBuilder.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Form\Exception\BadMethodCallException;
1818
use Symfony\Component\Form\Exception\InvalidArgumentException;
1919
use Symfony\Component\Form\Exception\UnexpectedTypeException;
20+
use Symfony\Component\Form\Util\FormUtil;
2021
use Symfony\Component\PropertyAccess\PropertyPath;
2122
use Symfony\Component\PropertyAccess\PropertyPathInterface;
2223

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

108+
private $isEmptyCallback = [__CLASS__, 'isEmpty'];
109+
107110
/**
108111
* Creates an empty form configuration.
109112
*
@@ -462,6 +465,14 @@ public function getOption($name, $default = null)
462465
return \array_key_exists($name, $this->options) ? $this->options[$name] : $default;
463466
}
464467

468+
/**
469+
* {@inheritdoc}
470+
*/
471+
public function getIsEmptyCallback(): callable
472+
{
473+
return $this->isEmptyCallback;
474+
}
475+
465476
/**
466477
* {@inheritdoc}
467478
*/
@@ -762,6 +773,16 @@ public function getFormConfig()
762773
return $config;
763774
}
764775

776+
/**
777+
* {@inheritdoc}
778+
*/
779+
public function setIsEmptyCallback(callable $isEmptyCallback)
780+
{
781+
$this->isEmptyCallback = $isEmptyCallback;
782+
783+
return $this;
784+
}
785+
765786
/**
766787
* Validates whether the given variable is a valid form name.
767788
*
@@ -799,4 +820,16 @@ public static function isValidName(?string $name): bool
799820
{
800821
return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
801822
}
823+
824+
/**
825+
* @internal
826+
*/
827+
public static function isEmpty($modelData): bool
828+
{
829+
return FormUtil::isEmpty($modelData) ||
830+
// arrays, countables
831+
((\is_array($modelData) || $modelData instanceof \Countable) && 0 === \count($modelData)) ||
832+
// traversables that are not countable
833+
($modelData instanceof \Traversable && 0 === iterator_count($modelData));
834+
}
802835
}

src/Symfony/Component/Form/FormConfigBuilderInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
/**
1818
* @author Bernhard Schussek <[email protected]>
19+
*
20+
* @method $this setIsEmptyCallback(callable $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 4.4
1921
*/
2022
interface FormConfigBuilderInterface extends FormConfigInterface
2123
{

src/Symfony/Component/Form/FormConfigInterface.php

Lines 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 <[email protected]>
21+
*
22+
* @method callable 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 4.4
2123
*/
2224
interface FormConfigInterface
2325
{

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,4 +2056,45 @@ public function provideTrimCases()
20562056
'Multiple expanded' => [true, true],
20572057
];
20582058
}
2059+
2060+
/**
2061+
* @dataProvider expandedIsEmptyWhenNoRealChoiceIsSelectedProvider
2062+
*/
2063+
public function testExpandedIsEmptyWhenNoRealChoiceIsSelected(bool $expected, $submittedData, bool $multiple, bool $required, $placeholder)
2064+
{
2065+
$options = [
2066+
'expanded' => true,
2067+
'choices' => [
2068+
'foo' => 'bar',
2069+
],
2070+
'multiple' => $multiple,
2071+
'required' => $required,
2072+
];
2073+
2074+
if (!$multiple) {
2075+
$options['placeholder'] = $placeholder;
2076+
}
2077+
2078+
$form = $this->factory->create(static::TESTED_TYPE, null, $options);
2079+
2080+
$form->submit($submittedData);
2081+
2082+
$this->assertSame($expected, $form->isEmpty());
2083+
}
2084+
2085+
public function expandedIsEmptyWhenNoRealChoiceIsSelectedProvider()
2086+
{
2087+
// Some invalid cases are voluntarily not tested:
2088+
// - multiple with placeholder
2089+
// - required with placeholder
2090+
return [
2091+
'Nothing submitted / single / not required / without a placeholder -> should be empty' => [true, null, false, false, null],
2092+
'Nothing submitted / single / not required / with a placeholder -> should not be empty' => [false, null, false, false, 'ccc'], // It falls back on the placeholder
2093+
'Nothing submitted / single / required / without a placeholder -> should be empty' => [true, null, false, true, null],
2094+
'Nothing submitted / single / required / with a placeholder -> should be empty' => [true, null, false, true, 'ccc'],
2095+
'Nothing submitted / multiple / not required / without a placeholder -> should be empty' => [true, null, true, false, null],
2096+
'Nothing submitted / multiple / required / without a placeholder -> should be empty' => [true, null, true, true, null],
2097+
'Placeholder submitted / single / not required / with a placeholder -> should not be empty' => [false, '', false, false, 'ccc'], // The placeholder is a selected value
2098+
];
2099+
}
20592100
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,21 @@ public function testCannotCallGetViewDataInPreSetDataListener()
11261126
$form->setData('foo');
11271127
}
11281128

1129+
public function testIsEmptyCallback()
1130+
{
1131+
$config = new FormConfigBuilder('foo', null, $this->dispatcher);
1132+
1133+
$config->setIsEmptyCallback(function ($modelData): bool { return 'ccc' === $modelData; });
1134+
$form = new Form($config);
1135+
$form->setData('ccc');
1136+
$this->assertTrue($form->isEmpty());
1137+
1138+
$config->setIsEmptyCallback(function (): bool { return false; });
1139+
$form = new Form($config);
1140+
$form->setData(null);
1141+
$this->assertFalse($form->isEmpty());
1142+
}
1143+
11291144
protected function createForm()
11301145
{
11311146
return $this->getBuilder()->getForm();

0 commit comments

Comments
 (0)