diff --git a/UPGRADE-6.2.md b/UPGRADE-6.2.md new file mode 100644 index 0000000000000..892f19c24a289 --- /dev/null +++ b/UPGRADE-6.2.md @@ -0,0 +1,7 @@ +UPGRADE FROM 6.1 to 6.2 +======================= + +Validator +--------- + + * Deprecate the "loose" e-mail validation mode, use "html5" instead diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 8e06d5873506a..64c1600bc9aae 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.2 +--- + + * Deprecate the "loose" e-mail validation mode, use "html5" instead + 6.1 --- diff --git a/src/Symfony/Component/Validator/Constraints/Email.php b/src/Symfony/Component/Validator/Constraints/Email.php index a0b7a2e9c3f88..4340e7a7217da 100644 --- a/src/Symfony/Component/Validator/Constraints/Email.php +++ b/src/Symfony/Component/Validator/Constraints/Email.php @@ -27,6 +27,9 @@ class Email extends Constraint { public const VALIDATION_MODE_HTML5 = 'html5'; public const VALIDATION_MODE_STRICT = 'strict'; + /** + * @deprecated since Symfony 6.2 + */ public const VALIDATION_MODE_LOOSE = 'loose'; public const INVALID_FORMAT_ERROR = 'bd79c0ab-ddba-46cc-a703-a7a4b08de310'; @@ -68,6 +71,10 @@ public function __construct( $this->mode = $mode ?? $this->mode; $this->normalizer = $normalizer ?? $this->normalizer; + if (self::VALIDATION_MODE_LOOSE === $this->mode) { + trigger_deprecation('symfony/validator', '6.2', 'The "%s" mode is deprecated. The default mode will be changed to "%s" in 7.0.', self::VALIDATION_MODE_LOOSE, self::VALIDATION_MODE_HTML5); + } + if (self::VALIDATION_MODE_STRICT === $this->mode && !class_exists(StrictEmailValidator::class)) { throw new LogicException(sprintf('The "egulias/email-validator" component is required to use the "%s" constraint in strict mode.', __CLASS__)); } diff --git a/src/Symfony/Component/Validator/Constraints/EmailValidator.php b/src/Symfony/Component/Validator/Constraints/EmailValidator.php index 82c7caea0bff9..d995af1bb48e6 100644 --- a/src/Symfony/Component/Validator/Constraints/EmailValidator.php +++ b/src/Symfony/Component/Validator/Constraints/EmailValidator.php @@ -40,6 +40,10 @@ public function __construct(string $defaultMode = Email::VALIDATION_MODE_LOOSE) throw new \InvalidArgumentException('The "defaultMode" parameter value is not valid.'); } + if (Email::VALIDATION_MODE_LOOSE === $defaultMode) { + trigger_deprecation('symfony/validator', '6.2', 'The "%s" mode is deprecated. The default mode will be changed to "%s" in 7.0.', Email::VALIDATION_MODE_LOOSE, Email::VALIDATION_MODE_HTML5); + } + $this->defaultMode = $defaultMode; } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php index 5f61311e1ea1b..1ee7712ad7781 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Validator\Tests\Constraints; +use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\EmailValidator; use Symfony\Component\Validator\Exception\UnexpectedValueException; @@ -21,9 +22,11 @@ */ class EmailValidatorTest extends ConstraintValidatorTestCase { + use ExpectDeprecationTrait; + protected function createValidator() { - return new EmailValidator(Email::VALIDATION_MODE_LOOSE); + return new EmailValidator(Email::VALIDATION_MODE_HTML5); } public function testUnknownDefaultModeTriggerException() @@ -76,6 +79,24 @@ public function getValidEmails() ['fabien@symfony.com'], ['example@example.co.uk'], ['fabien_potencier@example.fr'], + ]; + } + + /** + * @group legacy + * @dataProvider getValidEmails + * @dataProvider getEmailsOnlyValidInLooseMode + */ + public function testValidInLooseModeEmails($email) + { + $this->validator->validate($email, new Email(['mode' => Email::VALIDATION_MODE_LOOSE])); + + $this->assertNoViolation(); + } + + public function getEmailsOnlyValidInLooseMode() + { + return [ ['example@example.co..uk'], ['{}~!@!@£$%%^&*().!@£$%^&*()'], ['example@example.co..uk'], @@ -98,11 +119,29 @@ public function getValidEmailsWithWhitespaces() { return [ ["\x20example@example.co.uk\x20"], + ["example@example.com\x0B\x0B"], + ]; + } + + /** + * @group legacy + * @dataProvider getValidEmailsWithWhitespaces + * @dataProvider getEmailsWithWhitespacesOnlyValidInLooseMode + */ + public function testValidNormalizedEmailsInLooseMode($email) + { + $this->validator->validate($email, new Email(['mode' => Email::VALIDATION_MODE_LOOSE, 'normalizer' => 'trim'])); + + $this->assertNoViolation(); + } + + public function getEmailsWithWhitespacesOnlyValidInLooseMode() + { + return [ ["\x09\x09example@example.co..uk\x09\x09"], ["\x0A{}~!@!@£$%%^&*().!@£$%^&*()\x0A"], ["\x0D\x0Dexample@example.co..uk\x0D\x0D"], ["\x00example@-example.com"], - ["example@example.com\x0B\x0B"], ]; } @@ -214,8 +253,13 @@ public function testModeHtml5() ->assertRaised(); } + /** + * @group legacy + */ public function testModeLoose() { + $this->expectDeprecation('Since symfony/validator 6.2: The "loose" mode is deprecated. The default mode will be changed to "html5" in 7.0.'); + $constraint = new Email(['mode' => Email::VALIDATION_MODE_LOOSE]); $this->validator->validate('example@example..com', $constraint); diff --git a/src/Symfony/Component/Validator/Tests/ValidationTest.php b/src/Symfony/Component/Validator/Tests/ValidationTest.php index 880294e25be23..f4fb1041c16b0 100644 --- a/src/Symfony/Component/Validator/Tests/ValidationTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidationTest.php @@ -12,7 +12,8 @@ namespace Symfony\Component\Validator\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\Validator\Constraints\Email; +use Symfony\Component\Validator\Constraints\Blank; +use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Exception\ValidationFailedException; use Symfony\Component\Validator\Validation; @@ -23,13 +24,13 @@ class ValidationTest extends TestCase { public function testCreateCallableValid() { - $validator = Validation::createCallable(new Email()); + $validator = Validation::createCallable(new NotBlank()); $this->assertEquals('test@example.com', $validator('test@example.com')); } public function testCreateCallableInvalid() { - $validator = Validation::createCallable(new Email()); + $validator = Validation::createCallable(new Blank()); try { $validator('test'); $this->fail('No ValidationFailedException thrown'); @@ -38,21 +39,21 @@ public function testCreateCallableInvalid() $violations = $e->getViolations(); $this->assertCount(1, $violations); - $this->assertEquals('This value is not a valid email address.', $violations->get(0)->getMessage()); + $this->assertEquals('This value should be blank.', $violations->get(0)->getMessage()); } } public function testCreateIsValidCallableValid() { - $validator = Validation::createIsValidCallable(new Email()); + $validator = Validation::createIsValidCallable(new NotBlank()); $this->assertTrue($validator('test@example.com')); } public function testCreateIsValidCallableInvalid() { - $validator = Validation::createIsValidCallable(new Email()); + $validator = Validation::createIsValidCallable(new Blank()); $this->assertFalse($validator('test', $violations)); $this->assertCount(1, $violations); - $this->assertEquals('This value is not a valid email address.', $violations->get(0)->getMessage()); + $this->assertEquals('This value should be blank.', $violations->get(0)->getMessage()); } }