LocalPart::parse()   C
last analyzed

Complexity

Conditions 17
Paths 34

Size

Total Lines 66
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 17

Importance

Changes 0
Metric Value
cc 17
eloc 35
nc 34
nop 0
dl 0
loc 66
ccs 35
cts 35
cp 1
crap 17
rs 5.2166
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
3
namespace Egulias\EmailValidator\Parser;
4
5
use Egulias\EmailValidator\EmailLexer;
6
use Egulias\EmailValidator\Result\Result;
7
use Egulias\EmailValidator\Result\ValidEmail;
8
use Egulias\EmailValidator\Result\InvalidEmail;
9
use Egulias\EmailValidator\Warning\LocalTooLong;
10
use Egulias\EmailValidator\Result\Reason\DotAtEnd;
11
use Egulias\EmailValidator\Result\Reason\DotAtStart;
12
use Egulias\EmailValidator\Result\Reason\ConsecutiveDot;
13
use Egulias\EmailValidator\Result\Reason\ExpectingATEXT;
14
use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment;
15
16
class LocalPart extends PartParser
17
{
18
    public const INVALID_TOKENS = [
19
        EmailLexer::S_COMMA => EmailLexer::S_COMMA,
20
        EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
21
        EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,
22
        EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN,
23
        EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN,
24
        EmailLexer::S_COLON => EmailLexer::S_COLON,
25
        EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON,
26
        EmailLexer::INVALID => EmailLexer::INVALID
27
    ];
28
29
    /**
30
     * @var string
31
     */
32
    private $localPart = '';
33
34
35 186
    public function parse(): Result
36
    {
37 186
        $this->lexer->startRecording();
38
39 186
        while (!$this->lexer->current->isA(EmailLexer::S_AT) && !$this->lexer->current->isA(EmailLexer::S_EMPTY)) {
0 ignored issues
show
Bug introduced by
Egulias\EmailValidator\EmailLexer::S_AT of type integer is incompatible with the type Doctrine\Common\Lexer\T expected by parameter $types of Doctrine\Common\Lexer\Token::isA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

39
        while (!$this->lexer->current->isA(/** @scrutinizer ignore-type */ EmailLexer::S_AT) && !$this->lexer->current->isA(EmailLexer::S_EMPTY)) {
Loading history...
40 186
            if ($this->hasDotAtStart()) {
41 2
                return new InvalidEmail(new DotAtStart(), $this->lexer->current->value);
42
            }
43
44 184
            if ($this->lexer->current->isA(EmailLexer::S_DQUOTE)) {
45 23
                $dquoteParsingResult = $this->parseDoubleQuote();
46
47
                //Invalid double quote parsing
48 23
                if ($dquoteParsingResult->isInvalid()) {
49 10
                    return $dquoteParsingResult;
50
                }
51
            }
52
53 175
            if (
54 175
                $this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS) ||
55 9
                $this->lexer->current->isA(EmailLexer::S_CLOSEPARENTHESIS)
56
            ) {
57
                $commentsResult = $this->parseComments();
58 9
59 6
                //Invalid comment parsing
60
                if ($commentsResult->isInvalid()) {
61
                    return $commentsResult;
62
                }
63 173
            }
64 1
65
            if ($this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
66
                return new InvalidEmail(new ConsecutiveDot(), $this->lexer->current->value);
67 173
            }
68 173
69
            if (
70 2
                $this->lexer->current->isA(EmailLexer::S_DOT) &&
71
                $this->lexer->isNextToken(EmailLexer::S_AT)
72
            ) {
73 173
                return new InvalidEmail(new DotAtEnd(), $this->lexer->current->value);
74 173
            }
75 6
76
            $resultEscaping = $this->validateEscaping();
77
            if ($resultEscaping->isInvalid()) {
78 168
                return $resultEscaping;
79 168
            }
80 4
81
            $resultToken = $this->validateTokens(false);
82
            if ($resultToken->isInvalid()) {
83 167
                return $resultToken;
84 167
            }
85 7
86
            $resultFWS = $this->parseLocalFWS();
87
            if ($resultFWS->isInvalid()) {
88 166
                return $resultFWS;
89
            }
90
91 148
            $this->lexer->moveNext();
92 148
        }
93 148
94 2
        $this->lexer->stopRecording();
95
        $this->localPart = rtrim($this->lexer->getAccumulatedValues(), '@');
96
        if (strlen($this->localPart) > LocalTooLong::LOCAL_PART_LENGTH) {
97 148
            $this->warnings[LocalTooLong::CODE] = new LocalTooLong();
98
        }
99
100 168
        return new ValidEmail();
101
    }
102 168
103 4
    protected function validateTokens(bool $hasComments): Result
0 ignored issues
show
Unused Code introduced by
The parameter $hasComments is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

103
    protected function validateTokens(/** @scrutinizer ignore-unused */ bool $hasComments): Result

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
104
    {
105 167
        if (isset(self::INVALID_TOKENS[$this->lexer->current->type])) {
106
            return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->current->value);
107
        }
108 186
        return new ValidEmail();
109
    }
110 186
111
    public function localPart(): string
112
    {
113 167
        return $this->localPart;
114
    }
115 167
116 167
    private function parseLocalFWS(): Result
117 167
    {
118 166
        $foldingWS = new FoldingWhiteSpace($this->lexer);
119
        $resultFWS = $foldingWS->parse();
120 167
        if ($resultFWS->isValid()) {
121
            $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings());
122
        }
123 186
        return $resultFWS;
124
    }
125 186
126
    private function hasDotAtStart(): bool
127
    {
128 23
        return $this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->getPrevious()->isA(EmailLexer::S_EMPTY);
0 ignored issues
show
Bug introduced by
Egulias\EmailValidator\EmailLexer::S_DOT of type integer is incompatible with the type Doctrine\Common\Lexer\T expected by parameter $types of Doctrine\Common\Lexer\Token::isA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

128
        return $this->lexer->current->isA(/** @scrutinizer ignore-type */ EmailLexer::S_DOT) && $this->lexer->getPrevious()->isA(EmailLexer::S_EMPTY);
Loading history...
129
    }
130 23
131 23
    private function parseDoubleQuote(): Result
132 23
    {
133
        $dquoteParser = new DoubleQuote($this->lexer);
134 23
        $parseAgain = $dquoteParser->parse();
135
        $this->warnings = array_merge($this->warnings, $dquoteParser->getWarnings());
136
137 8
        return $parseAgain;
138
    }
139 8
140 8
    protected function parseComments(): Result
141 8
    {
142 8
        $commentParser = new Comment($this->lexer, new LocalComment());
143 5
        $result = $commentParser->parse();
144
        $this->warnings = array_merge($this->warnings, $commentParser->getWarnings());
145 3
        if ($result->isInvalid()) {
146
            return $result;
147
        }
148 173
        return $result;
149
    }
150
151 173
    private function validateEscaping(): Result
152 168
    {
153
        //Backslash found
154
        if (!$this->lexer->current->isA(EmailLexer::S_BACKSLASH)) {
0 ignored issues
show
Bug introduced by
Egulias\EmailValidator\EmailLexer::S_BACKSLASH of type integer is incompatible with the type Doctrine\Common\Lexer\T expected by parameter $types of Doctrine\Common\Lexer\Token::isA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

154
        if (!$this->lexer->current->isA(/** @scrutinizer ignore-type */ EmailLexer::S_BACKSLASH)) {
Loading history...
155 7
            return new ValidEmail();
156 6
        }
157
158
        if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
159 1
            return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->current->value);
160
        }
161
162
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
163 1
            return new ValidEmail();
164
        }
165
166
        return new ValidEmail();
167
    }
168
}
169