Passed
Pull Request — master (#222)
by Dmitriy
02:35
created

EmailHandler::validate()   C

Complexity

Conditions 17
Paths 97

Size

Total Lines 64
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 17.0097

Importance

Changes 0
Metric Value
eloc 37
c 0
b 0
f 0
dl 0
loc 64
ccs 30
cts 31
cp 0.9677
rs 5.2166
cc 17
nc 97
nop 3
crap 17.0097

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Yiisoft\Validator\Result;
8
use Yiisoft\Validator\ValidationContext;
9
use function is_string;
10
use function strlen;
11
use Yiisoft\Validator\Exception\UnexpectedRuleException;
12
13
/**
14
 * Validates that the value is a valid email address.
15
 */
16
final class EmailHandler implements RuleHandlerInterface
17
{
18 84
    public function validate(mixed $value, object $rule, ?ValidationContext $context = null): Result
19
    {
20 84
        if (!$rule instanceof Email) {
21 1
            throw new UnexpectedRuleException(Email::class, $rule);
22
        }
23
24 83
        $originalValue = $value;
25 83
        $result = new Result();
26
27 83
        if (!is_string($value)) {
28 3
            $valid = false;
29 80
        } elseif (!preg_match(
30
            '/^(?P<name>(?:"?([^"]*)"?\s)?)(?:\s+)?((?P<open><?)((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))$/i',
31
            $value,
32
            $matches
33
        )) {
34 6
            $valid = false;
35
        } else {
36
            /** @psalm-var array{name:string,local:string,open:string,domain:string,close:string} $matches */
37 74
            if ($rule->enableIDN) {
38 27
                $matches['local'] = $this->idnToAscii($matches['local']);
39 27
                $matches['domain'] = $this->idnToAscii($matches['domain']);
40 27
                $value = implode([
41 27
                    $matches['name'],
42 27
                    $matches['open'],
43 27
                    $matches['local'],
44
                    '@',
45 27
                    $matches['domain'],
46 27
                    $matches['close'],
47
                ]);
48
            }
49
50 74
            if (is_string($matches['local']) && strlen($matches['local']) > 64) {
51
                // The maximum total length of a user name or other local-part is 64 octets. RFC 5322 section 4.5.3.1.1
52
                // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
53 1
                $valid = false;
54 73
            } elseif (is_string($matches['local']) && strlen($matches['local'] . '@' . $matches['domain']) > 254) {
55
                // There is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands
56
                // of 254 characters. Since addresses that do not fit in those fields are not normally useful, the
57
                // upper limit on address lengths should normally be considered to be 254.
58
                //
59
                // Dominic Sayers, RFC 3696 erratum 1690
60
                // http://www.rfc-editor.org/errata_search.php?eid=1690
61
                $valid = false;
62
            } else {
63 73
                $valid = preg_match($rule->pattern, $value) || ($rule->allowName && preg_match(
64 47
                    $rule->fullPattern,
65
                    $value
66
                ));
67 73
                if ($valid && $rule->checkDNS) {
68 5
                    $valid = checkdnsrr($matches['domain'] . '.', 'MX') || checkdnsrr($matches['domain'] . '.', 'A');
69
                }
70
            }
71
        }
72
73 83
        if ($rule->enableIDN && $valid === false) {
74 10
            $valid = (bool) preg_match($rule->idnEmailPattern, $originalValue);
75
        }
76
77 83
        if ($valid === false) {
78 45
            $result->addError($rule->message);
79
        }
80
81 83
        return $result;
82
    }
83
84 27
    private function idnToAscii($idn)
85
    {
86 27
        return idn_to_ascii($idn, 0, INTL_IDNA_VARIANT_UTS46);
87
    }
88
}
89