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