Skip to content

Commit e113e7f

Browse files
committed
[Validator] Add a Length::$allowEmptyString option to reject empty strings
which defaults to `true` in 4.4 but will trigger a deprecation if not set explicitly in order to make the default `false` in 5.0.
1 parent 3bbf9da commit e113e7f

File tree

13 files changed

+89
-26
lines changed

13 files changed

+89
-26
lines changed

UPGRADE-4.4.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,7 @@ Validator
8787

8888
* Deprecated passing an `ExpressionLanguage` instance as the second argument of `ExpressionValidator::__construct()`.
8989
Pass it as the first argument instead.
90+
* The `Length` constraint expects the `allowEmptyString` option to be defined
91+
when the `min` option is used.
92+
Set it to `true` to keep the current behavior and `false` to reject empty strings.
93+
In 5.0, it'll become optional and will default to `false`.

src/Symfony/Bridge/Doctrine/Tests/Fixtures/BaseUser.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Symfony\Bridge\Doctrine\Tests\Fixtures;
44

5+
use Symfony\Component\Validator\Constraints as Assert;
6+
use Symfony\Component\Validator\Mapping\ClassMetadata;
7+
58
/**
69
* Class BaseUser.
710
*/
@@ -46,4 +49,15 @@ public function getUsername()
4649
{
4750
return $this->username;
4851
}
52+
53+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
54+
{
55+
$allowEmptyString = property_exists(Assert\Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
56+
57+
$metadata->addPropertyConstraint('username', new Assert\Length([
58+
'min' => 2,
59+
'max' => 120,
60+
'groups' => ['Registration'],
61+
] + $allowEmptyString));
62+
}
4963
}

src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Doctrine\ORM\Mapping as ORM;
1515
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
1616
use Symfony\Component\Validator\Constraints as Assert;
17+
use Symfony\Component\Validator\Mapping\ClassMetadata;
1718

1819
/**
1920
* @ORM\Entity
@@ -36,13 +37,11 @@ class DoctrineLoaderEntity extends DoctrineLoaderParentEntity
3637

3738
/**
3839
* @ORM\Column(length=20)
39-
* @Assert\Length(min=5)
4040
*/
4141
public $mergedMaxLength;
4242

4343
/**
4444
* @ORM\Column(length=20)
45-
* @Assert\Length(min=1, max=10)
4645
*/
4746
public $alreadyMappedMaxLength;
4847

@@ -69,4 +68,12 @@ class DoctrineLoaderEntity extends DoctrineLoaderParentEntity
6968

7069
/** @ORM\Column(type="simple_array", length=100) */
7170
public $simpleArrayField = [];
71+
72+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
73+
{
74+
$allowEmptyString = property_exists(Assert\Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
75+
76+
$metadata->addPropertyConstraint('mergedMaxLength', new Assert\Length(['min' => 5] + $allowEmptyString));
77+
$metadata->addPropertyConstraint('alreadyMappedMaxLength', new Assert\Length(['min' => 1, 'max' => 10] + $allowEmptyString));
78+
}
7279
}

src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@
99
<constraint name="NotBlank">
1010
<option name="groups">Registration</option>
1111
</constraint>
12-
<constraint name="Length">
13-
<option name="min">2</option>
14-
<option name="max">120</option>
15-
<option name="groups">Registration</option>
16-
</constraint>
1712
</property>
1813
</class>
1914
</constraint-mapping>

src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function testLoadClassMetadata()
4040
}
4141

4242
$validator = Validation::createValidatorBuilder()
43+
->addMethodMapping('loadValidatorMetadata')
4344
->enableAnnotationMapping()
4445
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}'))
4546
->getValidator()
@@ -142,6 +143,7 @@ public function testFieldMappingsConfiguration()
142143
}
143144

144145
$validator = Validation::createValidatorBuilder()
146+
->addMethodMapping('loadValidatorMetadata')
145147
->enableAnnotationMapping()
146148
->addXmlMappings([__DIR__.'/../Resources/validator/BaseUser.xml'])
147149
->addLoader(

src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,15 @@ public function testValidConstraint()
5757

5858
public function testGroupSequenceWithConstraintsOption()
5959
{
60+
$allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
61+
6062
$form = Forms::createFormFactoryBuilder()
6163
->addExtension(new ValidatorExtension(Validation::createValidator()))
6264
->getFormFactory()
6365
->create(FormTypeTest::TESTED_TYPE, null, (['validation_groups' => new GroupSequence(['First', 'Second'])]))
6466
->add('field', TextTypeTest::TESTED_TYPE, [
6567
'constraints' => [
66-
new Length(['min' => 10, 'groups' => ['First']]),
68+
new Length(['min' => 10, 'groups' => ['First']] + $allowEmptyString),
6769
new Email(['groups' => ['Second']]),
6870
],
6971
])

src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,13 @@ protected function setUp()
6161

6262
public function guessRequiredProvider()
6363
{
64+
$allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
65+
6466
return [
6567
[new NotNull(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)],
6668
[new NotBlank(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)],
6769
[new IsTrue(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)],
68-
[new Length(10), new ValueGuess(false, Guess::LOW_CONFIDENCE)],
70+
[new Length(['min' => 10, 'max' => 10] + $allowEmptyString), new ValueGuess(false, Guess::LOW_CONFIDENCE)],
6971
[new Range(['min' => 1, 'max' => 20]), new ValueGuess(false, Guess::LOW_CONFIDENCE)],
7072
];
7173
}
@@ -101,7 +103,9 @@ public function testGuessMaxLengthForConstraintWithMaxValue()
101103

102104
public function testGuessMaxLengthForConstraintWithMinValue()
103105
{
104-
$constraint = new Length(['min' => '2']);
106+
$allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
107+
108+
$constraint = new Length(['min' => '2'] + $allowEmptyString);
105109

106110
$result = $this->guesser->guessMaxLengthForConstraint($constraint);
107111
$this->assertNull($result);

src/Symfony/Component/Validator/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* added the `compared_value_path` parameter in violations when using any
99
comparison constraint with the `propertyPath` option.
1010
* added support for checking an array of types in `TypeValidator`
11+
* added a new `allowEmptyString` option to the `Length` constraint to allow rejecting empty strings when `min` is set, by setting it to `false`.
1112

1213
4.3.0
1314
-----

src/Symfony/Component/Validator/Constraints/Length.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class Length extends Constraint
4141
public $min;
4242
public $charset = 'UTF-8';
4343
public $normalizer;
44+
public $allowEmptyString;
4445

4546
public function __construct($options = null)
4647
{
@@ -56,6 +57,13 @@ public function __construct($options = null)
5657

5758
parent::__construct($options);
5859

60+
if (null === $this->allowEmptyString) {
61+
$this->allowEmptyString = true;
62+
if (null !== $this->min) {
63+
@trigger_error(sprintf('Using the "%s" constraint with the "min" option without setting the "allowEmptyString" one is deprecated and defaults to true. In 5.0, it will become optional and default to false.', self::class), E_USER_DEPRECATED);
64+
}
65+
}
66+
5967
if (null === $this->min && null === $this->max) {
6068
throw new MissingOptionsException(sprintf('Either option "min" or "max" must be given for constraint %s', __CLASS__), ['min', 'max']);
6169
}

src/Symfony/Component/Validator/Constraints/LengthValidator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function validate($value, Constraint $constraint)
3030
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Length');
3131
}
3232

33-
if (null === $value || '' === $value) {
33+
if (null === $value || ('' === $value && $constraint->allowEmptyString)) {
3434
return;
3535
}
3636

0 commit comments

Comments
 (0)