Passed
Pull Request — master (#222)
by Rustam
02:32
created

EmailHandler::validate()   C

Complexity

Conditions 17
Paths 97

Size

Total Lines 68
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 17.0073

Importance

Changes 0
Metric Value
eloc 40
dl 0
loc 68
ccs 33
cts 34
cp 0.9706
rs 5.2166
c 0
b 0
f 0
cc 17
nc 97
nop 3
crap 17.0073

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