Passed
Push — 3.x ( 4cccb8...037594 )
by Eduardo Gulias
02:37
created

DomainLiteral::parse()   B

Complexity

Conditions 11
Paths 30

Size

Total Lines 65
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 11.1967

Importance

Changes 0
Metric Value
cc 11
eloc 35
nc 30
nop 0
dl 0
loc 65
ccs 30
cts 34
cp 0.8824
crap 11.1967
rs 7.3166
c 0
b 0
f 0

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
namespace Egulias\EmailValidator\Parser;
3
4
use Egulias\EmailValidator\EmailLexer;
5
use Egulias\EmailValidator\Result\Result;
6
use Egulias\EmailValidator\Result\ValidEmail;
7
use Egulias\EmailValidator\Result\InvalidEmail;
8
use Egulias\EmailValidator\Warning\CFWSWithFWS;
9
use Egulias\EmailValidator\Warning\IPV6BadChar;
10
use Egulias\EmailValidator\Result\Reason\CRNoLF;
11
use Egulias\EmailValidator\Warning\IPV6ColonEnd;
12
use Egulias\EmailValidator\Warning\IPV6MaxGroups;
13
use Egulias\EmailValidator\Warning\ObsoleteDTEXT;
14
use Egulias\EmailValidator\Warning\AddressLiteral;
15
use Egulias\EmailValidator\Warning\IPV6ColonStart;
16
use Egulias\EmailValidator\Warning\IPV6Deprecated;
17
use Egulias\EmailValidator\Warning\IPV6GroupCount;
18
use Egulias\EmailValidator\Warning\IPV6DoubleColon;
19
use Egulias\EmailValidator\Result\Reason\ExpectingDTEXT;
20
use Egulias\EmailValidator\Result\Reason\UnusualElements;
21
use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
22
23
class DomainLiteral extends PartParser
24
{
25 18
    public function parse() : Result
26
    {
27 18
        $this->addTagWarnings();
28
29 18
        $IPv6TAG = false;
30 18
        $addressLiteral = '';
31
32
        do {
33 18
            if ($this->lexer->token['type'] === EmailLexer::C_NUL) {
34
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
35
            }
36
37 18
            $this->addObsoleteWarnings();
38
39 18
            if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) {
40 1
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
41
            }
42
43 17
            if ($this->lexer->isNextTokenAny(
44 17
                array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF)
45
            )) {
46
                $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
47
                $this->parseFWS();
48
            }
49
50 17
            if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
51 1
                return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']);
52
            }
53
54 16
            if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) {
55 1
                return new InvalidEmail(new UnusualElements($this->lexer->token['value']), $this->lexer->token['value']);
56
            }
57 16
            if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) {
58 9
                $IPv6TAG = true;
59
            }
60
61 16
            if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) {
62
                break;
63
            }
64
65 16
            $addressLiteral .= $this->lexer->token['value'];
66
67 16
        } while ($this->lexer->moveNext());
68
69
70
        //Encapsulate
71 15
        $addressLiteral = str_replace('[', '', $addressLiteral);
72 15
        $isAddressLiteralIPv4 = $this->checkIPV4Tag($addressLiteral);
73
74 15
        if (!$isAddressLiteralIPv4) {
75 3
            return new ValidEmail();
76
        } else {
77 12
            $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral);
78
        }
79
80 12
        if (!$IPv6TAG) {
81 3
            $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral();
82 3
            return new ValidEmail();
83
        }
84
85 9
        $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
86
87 9
        $this->checkIPV6Tag($addressLiteral);
88
89 9
        return new ValidEmail();
90
    }
91
92
    /**
93
     * @param string $addressLiteral
94
     * @param int $maxGroups
95
     */
96 9
    public function checkIPV6Tag($addressLiteral, $maxGroups = 8) : void
97
    {
98 9
        $prev = $this->lexer->getPrevious();
99 9
        if ($prev['type'] === EmailLexer::S_COLON) {
100 1
            $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd();
101
        }
102
103 9
        $IPv6       = substr($addressLiteral, 5);
104
        //Daniel Marschall's new IPv6 testing strategy
105 9
        $matchesIP  = explode(':', $IPv6);
106 9
        $groupCount = count($matchesIP);
107 9
        $colons     = strpos($IPv6, '::');
108
109 9
        if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) {
110 1
            $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar();
111
        }
112
113 9
        if ($colons === false) {
114
            // We need exactly the right number of groups
115 4
            if ($groupCount !== $maxGroups) {
116 1
                $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount();
117
            }
118 4
            return;
119
        }
120
121 5
        if ($colons !== strrpos($IPv6, '::')) {
122 1
            $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon();
123 1
            return;
124
        }
125
126 4
        if ($colons === 0 || $colons === (strlen($IPv6) - 2)) {
127
            // RFC 4291 allows :: at the start or end of an address
128
            //with 7 other groups in addition
129 2
            ++$maxGroups;
130
        }
131
132 4
        if ($groupCount > $maxGroups) {
133 1
            $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups();
134 3
        } elseif ($groupCount === $maxGroups) {
135 1
            $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated();
136
        }
137 4
    }
138
    
139 12
    public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string
140
    {
141 12
        $matchesIP  = array();
142 12
        $IPv4Match = preg_match(
143 12
            '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
144 12
            $addressLiteralIPv4,
145 12
            $matchesIP);
146
147
        // Extract IPv4 part from the end of the address-literal (if there is one)
148 12
        if ($IPv4Match > 0) {
149 1
            $index = (int) strrpos($addressLiteralIPv4, $matchesIP[0]);
150
            //There's a match but it is at the start
151 1
            if ($index > 0) {
152
                // Convert IPv4 part to IPv6 format for further testing
153 1
                return substr($addressLiteralIPv4, 0, $index) . '0:0';
154
            }
155
        }
156
157 11
        return $addressLiteralIPv4;
158
    }
159
160
    /**
161
     * @param string $addressLiteral
162
     *
163
     * @return bool
164
     */
165 15
    protected function checkIPV4Tag($addressLiteral) : bool
166
    {
167 15
        $matchesIP  = array();
168 15
        $IPv4Match = preg_match(
169 15
            '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
170 15
            $addressLiteral,
171 15
            $matchesIP);
172
173
        // Extract IPv4 part from the end of the address-literal (if there is one)
174
175 15
        if ($IPv4Match > 0) {
176 4
            $index = strrpos($addressLiteral, $matchesIP[0]);
177
            //There's a match but it is at the start
178 4
            if ($index === 0) {
179 3
                $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
180 3
                return false;
181
            }
182
        }
183
184 12
        return true;
185
    }
186
187 18
    private function addObsoleteWarnings() : void
188
    {
189 18
        if ($this->lexer->token['type'] === EmailLexer::INVALID ||
190 18
            $this->lexer->token['type'] === EmailLexer::C_DEL   ||
191 18
            $this->lexer->token['type'] === EmailLexer::S_LF ||
192 18
            $this->lexer->token['type'] === EmailLexer::S_BACKSLASH
193
        ) {
194 2
            $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
195
        }
196 18
    }
197
198 18
    private function addTagWarnings() : void
199
    {
200 18
        if ($this->lexer->isNextToken(EmailLexer::S_COLON)) {
201
            $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
202
        }
203 18
        if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) {
204 9
            $lexer = clone $this->lexer;
205 9
            $lexer->moveNext();
206 9
            if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) {
207 1
                $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
208
            }
209
        }
210 18
    }
211
212
}