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

Skip to content

Commit 601a517

Browse files
committed
[Form] Is empty callback
1 parent f6e93de commit 601a517

File tree

10 files changed

+131
-5
lines changed

10 files changed

+131
-5
lines changed

UPGRADE-4.4.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Form
7373
----
7474

7575
* Using `int` or `float` as data for the `NumberType` when the `input` option is set to `string` is deprecated.
76+
* Added `getIsEmptyCallback()` method to `FormConfigInterface`.
77+
* Added `setIsEmptyCallback()` method to `FormConfigBuilderInterface`.
7678

7779
FrameworkBundle
7880
---------------

src/Symfony/Component/Form/ButtonBuilder.php

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

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

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

src/Symfony/Component/Form/CHANGELOG.md

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

1113
4.3.0
1214
-----

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 setIsEmptyCallback() method in %s which implements %s is deprecated since Symfony 4.4.', \get_class($builder), FormConfigBuilderInterface::class), 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 getIsEmptyCallback() method in %s which implements %s is deprecated since Symfony 4.4.', \get_class($this->config), FormConfigInterface::class), 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: 29 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;
109+
107110
/**
108111
* Creates an empty form configuration.
109112
*
@@ -127,6 +130,8 @@ public function __construct(?string $name, ?string $dataClass, EventDispatcherIn
127130
$this->dataClass = $dataClass;
128131
$this->dispatcher = $dispatcher;
129132
$this->options = $options;
133+
134+
$this->isEmptyCallback = [__CLASS__, 'isEmpty'];
130135
}
131136

132137
/**
@@ -464,6 +469,11 @@ public function getOption($name, $default = null)
464469
return \array_key_exists($name, $this->options) ? $this->options[$name] : $default;
465470
}
466471

472+
public function getIsEmptyCallback(): callable
473+
{
474+
return $this->isEmptyCallback;
475+
}
476+
467477
/**
468478
* {@inheritdoc}
469479
*/
@@ -764,6 +774,13 @@ public function getFormConfig()
764774
return $config;
765775
}
766776

777+
public function setIsEmptyCallback(callable $isEmptyCallback)
778+
{
779+
$this->isEmptyCallback = $isEmptyCallback;
780+
781+
return $this;
782+
}
783+
767784
/**
768785
* Validates whether the given variable is a valid form name.
769786
*
@@ -801,4 +818,16 @@ public static function isValidName(?string $name): bool
801818
{
802819
return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
803820
}
821+
822+
/**
823+
* @internal
824+
*/
825+
public static function isEmpty($modelData): bool
826+
{
827+
return FormUtil::isEmpty($modelData) ||
828+
// arrays, countables
829+
((\is_array($modelData) || $modelData instanceof \Countable) && 0 === \count($modelData)) ||
830+
// traversables that are not countable
831+
($modelData instanceof \Traversable && 0 === iterator_count($modelData));
832+
}
804833
}

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
@@ -2053,4 +2053,45 @@ public function provideTrimCases()
20532053
'Multiple expanded' => [true, true],
20542054
];
20552055
}
2056+
2057+
/**
2058+
* @dataProvider expandedIsEmptyWhenNoRealChoiceIsSelectedProvider
2059+
*/
2060+
public function testExpandedIsEmptyWhenNoRealChoiceIsSelected(bool $expected, $submittedData, bool $multiple, bool $required, $placeholder)
2061+
{
2062+
$options = [
2063+
'expanded' => true,
2064+
'choices' => [
2065+
'foo' => 'bar',
2066+
],
2067+
'multiple' => $multiple,
2068+
'required' => $required,
2069+
];
2070+
2071+
if (!$multiple) {
2072+
$options['placeholder'] = $placeholder;
2073+
}
2074+
2075+
$form = $this->factory->create(static::TESTED_TYPE, null, $options);
2076+
2077+
$form->submit($submittedData);
2078+
2079+
$this->assertSame($expected, $form->isEmpty());
2080+
}
2081+
2082+
public function expandedIsEmptyWhenNoRealChoiceIsSelectedProvider()
2083+
{
2084+
// Some invalid cases are voluntarily not tested :
2085+
// - multiple with placeholder
2086+
// - required with placeholder
2087+
return [
2088+
'Nothing submitted / single / not required / without a placeholder -> should be empty' => [true, null, false, false, null],
2089+
'Nothing submitted / single / not required / with a placeholder -> should not be empty' => [false, null, false, false, 'ccc'], // It falls back on the placeholder
2090+
'Nothing submitted / single / required / without a placeholder -> should be empty' => [true, null, false, true, null],
2091+
'Nothing submitted / single / required / with a placeholder -> should be empty' => [true, null, false, true, 'ccc'],
2092+
'Nothing submitted / multiple / not required / without a placeholder -> should be empty' => [true, null, true, false, null],
2093+
'Nothing submitted / multiple / required / without a placeholder -> should be empty' => [true, null, true, true, null],
2094+
'Placeholder submitted / single / not required / with a placeholder -> should not be empty' => [false, '', false, false, 'ccc'], // The placeholder is a selected value
2095+
];
2096+
}
20562097
}

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)