Skip to content

Commit 3368630

Browse files
eguliasfabpot
authored andcommitted
#1581 - Strict in Email constraint and use of Egulias\EmailValidator
1 parent e0de958 commit 3368630

File tree

10 files changed

+89
-7
lines changed

10 files changed

+89
-7
lines changed

UPGRADE-2.5.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,31 @@ Form
4444
public function getErrors($deep = false, $flatten = true)
4545
{
4646
```
47+
48+
Validator
49+
---------
50+
51+
* EmailValidator has changed to allow `non-strict` and `strict` email validation
52+
53+
Before:
54+
55+
Email validation was done with php's `filter_var()`
56+
57+
After:
58+
59+
Default email validation is now done via a simple regex which may cause invalid emails (not RFC compilant) to be
60+
valid. This is the default behaviour.
61+
62+
Strict email validation has to be explicitly activated in the configuration file by adding
63+
```
64+
framework_bundle:
65+
//...
66+
validation:
67+
strict_email: true
68+
//...
69+
70+
```
71+
Also you have to add to your composer.json:
72+
```
73+
"egulias/email-validator": "1.1.*"
74+
```

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@
7373
"monolog/monolog": "~1.3",
7474
"propel/propel1": "1.6.*",
7575
"ircmaxell/password-compat": "1.0.*",
76-
"ocramius/proxy-manager": ">=0.3.1,<0.6-dev"
76+
"ocramius/proxy-manager": ">=0.3.1,<0.6-dev",
77+
"egulias/email-validator": "1.1.0"
7778
},
7879
"autoload": {
7980
"psr-0": { "Symfony\\": "src/" },

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ private function addValidationSection(ArrayNodeDefinition $rootNode)
445445
->scalarNode('cache')->end()
446446
->booleanNode('enable_annotations')->defaultFalse()->end()
447447
->scalarNode('translation_domain')->defaultValue('validators')->end()
448+
->booleanNode('strict_email')->defaultFalse()->end()
448449
->end()
449450
->end()
450451
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,9 @@ private function registerValidationConfiguration(array $config, ContainerBuilder
678678
$container->setParameter('validator.mapping.loader.xml_files_loader.mapping_files', $this->getValidatorXmlMappingFiles($container));
679679
$container->setParameter('validator.mapping.loader.yaml_files_loader.mapping_files', $this->getValidatorYamlMappingFiles($container));
680680

681+
$definition = $container->findDefinition('validator.email');
682+
$definition->replaceArgument(0, $config['strict_email']);
683+
681684
if (array_key_exists('enable_annotations', $config) && $config['enable_annotations']) {
682685
$loaderChain = $container->getDefinition('validator.mapping.loader.loader_chain');
683686
$arguments = $loaderChain->getArguments();

src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<parameter key="validator.mapping.loader.xml_files_loader.mapping_files" type="collection" />
1919
<parameter key="validator.mapping.loader.yaml_files_loader.mapping_files" type="collection" />
2020
<parameter key="validator.expression.class">Symfony\Component\Validator\Constraints\ExpressionValidator</parameter>
21+
<parameter key="validator.email.class">Symfony\Component\Validator\Constraints\EmailValidator</parameter>
2122
</parameters>
2223

2324
<services>
@@ -69,5 +70,10 @@
6970
<argument type="service" id="property_accessor" />
7071
<tag name="validator.constraint_validator" alias="validator.expression" />
7172
</service>
73+
74+
<service id="validator.email" class="%validator.email.class%">
75+
<argument></argument>
76+
<tag name="validator.constraint_validator" alias="validator.email" />
77+
</service>
7278
</services>
7379
</container>

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ protected static function getBundleDefaultConfig()
127127
'enabled' => false,
128128
'enable_annotations' => false,
129129
'translation_domain' => 'validators',
130+
'strict_email' => false,
130131
),
131132
'annotations' => array(
132133
'cache' => 'file',

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,13 @@ class Email extends Constraint
2525
public $message = 'This value is not a valid email address.';
2626
public $checkMX = false;
2727
public $checkHost = false;
28+
public $strict = null;
29+
30+
/**
31+
* {@inheritDoc}
32+
*/
33+
public function validatedBy()
34+
{
35+
return 'validator.email';
36+
}
2837
}

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Validator\Constraint;
1515
use Symfony\Component\Validator\ConstraintValidator;
1616
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
17+
use Egulias\EmailValidator\EmailValidator as StrictEmailValidator;
1718

1819
/**
1920
* @author Bernhard Schussek <[email protected]>
@@ -22,6 +23,18 @@
2223
*/
2324
class EmailValidator extends ConstraintValidator
2425
{
26+
/**
27+
* isStrict
28+
*
29+
* @var Boolean
30+
*/
31+
private $isStrict;
32+
33+
public function __construct($strict = false)
34+
{
35+
$this->isStrict = $strict;
36+
}
37+
2538
/**
2639
* {@inheritDoc}
2740
*/
@@ -40,12 +53,23 @@ public function validate($value, Constraint $constraint)
4053
}
4154

4255
$value = (string) $value;
43-
$valid = filter_var($value, FILTER_VALIDATE_EMAIL);
56+
if (null === $constraint->strict) {
57+
$constraint->strict = $this->isStrict;
58+
}
59+
60+
if ($constraint->strict && class_exists('\Egulias\EmailValidator\EmailValidator')) {
61+
$strictValidator = new StrictEmailValidator();
62+
$valid = $strictValidator->isValid($value, false);
63+
} elseif ($constraint->strict === true) {
64+
throw new \RuntimeException('Strict email validation requires egulias/email-validator');
65+
} else {
66+
$valid = preg_match('/.+\@.+\..+/', $value);
67+
}
4468

4569
if ($valid) {
4670
$host = substr($value, strpos($value, '@') + 1);
47-
4871
// Check for host DNS resource records
72+
4973
if ($valid && $constraint->checkMX) {
5074
$valid = $this->checkMX($host);
5175
} elseif ($valid && $constraint->checkHost) {

src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
2222
protected function setUp()
2323
{
2424
$this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false);
25-
$this->validator = new EmailValidator();
25+
$this->validator = new EmailValidator(false);
2626
$this->validator->initialize($this->context);
2727
}
2828

@@ -100,7 +100,14 @@ public function getInvalidEmails()
100100
array('example'),
101101
array('example@'),
102102
array('example@localhost'),
103-
array('[email protected]@example.com'),
104103
);
105104
}
105+
106+
public function testStrict()
107+
{
108+
$this->context->expects($this->never())
109+
->method('addViolation');
110+
111+
$this->validator->validate('example@localhost', new Email(array('strict' => true)));
112+
}
106113
}

src/Symfony/Component/Validator/composer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,17 @@
2626
"symfony/yaml": "~2.0",
2727
"symfony/config": "~2.2",
2828
"doctrine/annotations": "~1.0",
29-
"doctrine/cache": "~1.0"
29+
"doctrine/cache": "~1.0",
30+
"egulias/email-validator": "~1.0"
3031
},
3132
"suggest": {
3233
"doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.",
3334
"doctrine/cache": "For using the default cached annotation reader and metadata cache.",
3435
"symfony/http-foundation": "",
3536
"symfony/intl": "",
3637
"symfony/yaml": "",
37-
"symfony/config": ""
38+
"symfony/config": "",
39+
"egulias/email-validator": "Strict (RFC compliant) email validation"
3840
},
3941
"autoload": {
4042
"psr-0": { "Symfony\\Component\\Validator\\": "" }

0 commit comments

Comments
 (0)