diff --git a/UPGRADE-5.2.md b/UPGRADE-5.2.md
new file mode 100644
index 0000000000000..f3a204fcce333
--- /dev/null
+++ b/UPGRADE-5.2.md
@@ -0,0 +1,30 @@
+UPGRADE FROM 5.1 to 5.2
+=======================
+
+Validator
+---------
+
+ * Deprecated the `allowEmptyString` option of the `Length` constraint.
+
+ Before:
+
+ ```php
+ use Symfony\Component\Validator\Constraints as Assert;
+
+ /**
+ * @Assert\Length(min=5, allowEmptyString=true)
+ */
+ ```
+
+ After:
+
+ ```php
+ use Symfony\Component\Validator\Constraints as Assert;
+
+ /**
+ * @Assert\AtLeastOneOf({
+ * @Assert\Blank(),
+ * @Assert\Length(min=5)
+ * })
+ */
+ ```
diff --git a/UPGRADE-6.0.md b/UPGRADE-6.0.md
index 1d8243eff7d8a..0e3449d80bb9b 100644
--- a/UPGRADE-6.0.md
+++ b/UPGRADE-6.0.md
@@ -115,6 +115,34 @@ Security
* Removed `DefaultLogoutSuccessHandler` in favor of `DefaultLogoutListener`.
* Added a `logout(Request $request, Response $response, TokenInterface $token)` method to the `RememberMeServicesInterface`.
+Validator
+---------
+
+ * Removed the `allowEmptyString` option from the `Length` constraint.
+
+ Before:
+
+ ```php
+ use Symfony\Component\Validator\Constraints as Assert;
+
+ /**
+ * @Assert\Length(min=5, allowEmptyString=true)
+ */
+ ```
+
+ After:
+
+ ```php
+ use Symfony\Component\Validator\Constraints as Assert;
+
+ /**
+ * @Assert\AtLeastOneOf({
+ * @Assert\Blank(),
+ * @Assert\Length(min=5)
+ * })
+ */
+ ```
+
Yaml
----
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php
index 8c0b348e3bf3a..d6aee2d18b0b1 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php
@@ -36,13 +36,13 @@ class DoctrineLoaderEntity extends DoctrineLoaderParentEntity
/**
* @ORM\Column(length=20)
- * @Assert\Length(min=5, allowEmptyString=true)
+ * @Assert\Length(min=5)
*/
public $mergedMaxLength;
/**
* @ORM\Column(length=20)
- * @Assert\Length(min=1, max=10, allowEmptyString=true)
+ * @Assert\Length(min=1, max=10)
*/
public $alreadyMappedMaxLength;
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml b/src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml
index 40b7a138d437b..bf64b92ca484d 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml
+++ b/src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml
@@ -13,7 +13,6 @@
-
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
index 598687e1a2607..4c90cc6316db8 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
@@ -67,7 +67,7 @@ public function testGroupSequenceWithConstraintsOption()
->create(FormTypeTest::TESTED_TYPE, null, (['validation_groups' => new GroupSequence(['First', 'Second'])]))
->add('field', TextTypeTest::TESTED_TYPE, [
'constraints' => [
- new Length(['min' => 10, 'allowEmptyString' => true, 'groups' => ['First']]),
+ new Length(['min' => 10, 'groups' => ['First']]),
new NotBlank(['groups' => ['Second']]),
],
])
@@ -83,8 +83,6 @@ public function testGroupSequenceWithConstraintsOption()
public function testManyFieldsGroupSequenceWithConstraintsOption()
{
- $allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
-
$formMetadata = new ClassMetadata(Form::class);
$authorMetadata = (new ClassMetadata(Author::class))
->addPropertyConstraint('firstName', new NotBlank(['groups' => 'Second']))
@@ -116,7 +114,7 @@ public function testManyFieldsGroupSequenceWithConstraintsOption()
->add('firstName', TextTypeTest::TESTED_TYPE)
->add('lastName', TextTypeTest::TESTED_TYPE, [
'constraints' => [
- new Length(['min' => 10, 'groups' => ['First']] + $allowEmptyString),
+ new Length(['min' => 10, 'groups' => ['First']]),
],
])
->add('australian', TextTypeTest::TESTED_TYPE, [
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php
index 383b7556d51b8..cb9b93abdbf61 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php
@@ -94,13 +94,11 @@ public function testFieldConstraintsInvalidateFormIfFieldIsSubmitted()
public function testFieldsValidateInSequence()
{
- $allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
-
$form = $this->createForm(FormType::class, null, [
'validation_groups' => new GroupSequence(['group1', 'group2']),
])
->add('foo', TextType::class, [
- 'constraints' => [new Length(['min' => 10, 'groups' => ['group1']] + $allowEmptyString)],
+ 'constraints' => [new Length(['min' => 10, 'groups' => ['group1']])],
])
->add('bar', TextType::class, [
'constraints' => [new NotBlank(['groups' => ['group2']])],
@@ -117,16 +115,14 @@ public function testFieldsValidateInSequence()
public function testFieldsValidateInSequenceWithNestedGroupsArray()
{
- $allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
-
$form = $this->createForm(FormType::class, null, [
'validation_groups' => new GroupSequence([['group1', 'group2'], 'group3']),
])
->add('foo', TextType::class, [
- 'constraints' => [new Length(['min' => 10, 'groups' => ['group1']] + $allowEmptyString)],
+ 'constraints' => [new Length(['min' => 10, 'groups' => ['group1']])],
])
->add('bar', TextType::class, [
- 'constraints' => [new Length(['min' => 10, 'groups' => ['group2']] + $allowEmptyString)],
+ 'constraints' => [new Length(['min' => 10, 'groups' => ['group2']])],
])
->add('baz', TextType::class, [
'constraints' => [new NotBlank(['groups' => ['group3']])],
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php
index e96c8b60c3929..2b50c7cc2f063 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php
@@ -66,7 +66,7 @@ public function guessRequiredProvider()
[new NotNull(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)],
[new NotBlank(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)],
[new IsTrue(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)],
- [new Length(['min' => 10, 'max' => 10, 'allowEmptyString' => true]), new ValueGuess(false, Guess::LOW_CONFIDENCE)],
+ [new Length(['min' => 10, 'max' => 10]), new ValueGuess(false, Guess::LOW_CONFIDENCE)],
[new Range(['min' => 1, 'max' => 20]), new ValueGuess(false, Guess::LOW_CONFIDENCE)],
];
}
@@ -102,7 +102,7 @@ public function testGuessMaxLengthForConstraintWithMaxValue()
public function testGuessMaxLengthForConstraintWithMinValue()
{
- $constraint = new Length(['min' => '2', 'allowEmptyString' => true]);
+ $constraint = new Length(['min' => '2']);
$result = $this->guesser->guessMaxLengthForConstraint($constraint);
$this->assertNull($result);
diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md
index 9921ef6d4b495..df48d15b3ffe4 100644
--- a/src/Symfony/Component/Validator/CHANGELOG.md
+++ b/src/Symfony/Component/Validator/CHANGELOG.md
@@ -1,6 +1,34 @@
CHANGELOG
=========
+5.2.0
+-----
+
+ * deprecated the `allowEmptyString` option of the `Length` constraint
+
+ Before:
+
+ ```php
+ use Symfony\Component\Validator\Constraints as Assert;
+
+ /**
+ * @Assert\Length(min=5, allowEmptyString=true)
+ */
+ ```
+
+ After:
+
+ ```php
+ use Symfony\Component\Validator\Constraints as Assert;
+
+ /**
+ * @Assert\AtLeastOneOf({
+ * @Assert\Blank(),
+ * @Assert\Length(min=5)
+ * })
+ */
+ ```
+
5.1.0
-----
diff --git a/src/Symfony/Component/Validator/Constraints/Length.php b/src/Symfony/Component/Validator/Constraints/Length.php
index d3404277bef05..3daebf8ff1985 100644
--- a/src/Symfony/Component/Validator/Constraints/Length.php
+++ b/src/Symfony/Component/Validator/Constraints/Length.php
@@ -64,5 +64,9 @@ public function __construct($options = null)
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', get_debug_type($this->normalizer)));
}
+
+ if (isset($options['allowEmptyString'])) {
+ trigger_deprecation('symfony/validator', '5.2', sprintf('The "allowEmptyString" option of the "%s" constraint is deprecated.', self::class));
+ }
}
}
diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LengthTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LengthTest.php
index b0caef17c9e31..c1c9d60d8bbad 100644
--- a/src/Symfony/Component/Validator/Tests/Constraints/LengthTest.php
+++ b/src/Symfony/Component/Validator/Tests/Constraints/LengthTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Validator\Tests\Constraints;
use PHPUnit\Framework\TestCase;
+use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Validator\Constraints\Length;
/**
@@ -19,6 +20,8 @@
*/
class LengthTest extends TestCase
{
+ use ExpectDeprecationTrait;
+
public function testNormalizerCanBeSet()
{
$length = new Length(['min' => 0, 'max' => 10, 'normalizer' => 'trim']);
@@ -39,4 +42,23 @@ public function testInvalidNormalizerObjectThrowsException()
$this->expectExceptionMessage('The "normalizer" option must be a valid callable ("stdClass" given).');
new Length(['min' => 0, 'max' => 10, 'normalizer' => new \stdClass()]);
}
+
+ /**
+ * @group legacy
+ * @dataProvider allowEmptyStringOptionData
+ */
+ public function testDeprecatedAllowEmptyStringOption(bool $value)
+ {
+ $this->expectDeprecation('Since symfony/validator 5.2: The "allowEmptyString" option of the "Symfony\Component\Validator\Constraints\Length" constraint is deprecated.');
+
+ new Length(['allowEmptyString' => $value, 'max' => 5]);
+ }
+
+ public function allowEmptyStringOptionData()
+ {
+ return [
+ [true],
+ [false],
+ ];
+ }
}
diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php
index d7969afc565e4..584f1e4ae3c8a 100644
--- a/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php
+++ b/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php
@@ -29,6 +29,9 @@ public function testNullIsValid()
$this->assertNoViolation();
}
+ /**
+ * @group legacy
+ */
public function testAllowEmptyString()
{
$this->validator->validate('', new Length(['value' => 6, 'allowEmptyString' => true]));
diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json
index ad9a81eaba8ae..9e2a5f752bd55 100644
--- a/src/Symfony/Component/Validator/composer.json
+++ b/src/Symfony/Component/Validator/composer.json
@@ -17,6 +17,7 @@
],
"require": {
"php": ">=7.2.5",
+ "symfony/deprecation-contracts": "^2.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "^1.15",