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

LocalPart   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Test Coverage

Coverage 98.55%

Importance

Changes 0
Metric Value
eloc 71
dl 0
loc 147
ccs 68
cts 69
cp 0.9855
rs 9.92
c 0
b 0
f 0
wmc 31

8 Methods

Rating   Name   Duplication   Size   Complexity  
A parseDoubleQuote() 0 7 1
A parseLocalFWS() 0 8 2
A validateTokens() 0 16 2
A parseComments() 0 9 2
A localPart() 0 3 1
A validateEscaping() 0 16 4
C parse() 0 63 17
A hasDotAtStart() 0 3 2
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
    /**
19
     * @var string
20
     */
21
    private $localPart = '';
22
23
24 186
    public function parse() : Result
25
    {
26 186
        $this->lexer->startRecording();
27
28 186
        while ($this->lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) {
29 186
            if ($this->hasDotAtStart()) {
30 2
                return new InvalidEmail(new DotAtStart(), $this->lexer->token['value']);
31
            }
32
33 184
            if ($this->lexer->token['type'] === EmailLexer::S_DQUOTE) {
34 23
                $dquoteParsingResult = $this->parseDoubleQuote();
35
36
                //Invalid double quote parsing
37 23
                if($dquoteParsingResult->isInvalid()) {
38 10
                    return $dquoteParsingResult;
39
                }
40
            }
41
42 175
            if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS || 
43 175
                $this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS ) {
44 9
                $commentsResult = $this->parseComments();
45
46
                //Invalid comment parsing
47 9
                if($commentsResult->isInvalid()) {
48 6
                    return $commentsResult;
49
                }
50
            }
51
52 173
            if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
53 1
                return new InvalidEmail(new ConsecutiveDot(), $this->lexer->token['value']);
54
            }
55
56 173
            if ($this->lexer->token['type'] === EmailLexer::S_DOT &&
57 173
                $this->lexer->isNextToken(EmailLexer::S_AT)
58
            ) {
59 2
                return new InvalidEmail(new DotAtEnd(), $this->lexer->token['value']);
60
            }
61
62 173
            $resultEscaping = $this->validateEscaping();
63 173
            if ($resultEscaping->isInvalid()) {
64 6
                return $resultEscaping;
65
            }
66
67 168
            $resultToken = $this->validateTokens(false);
68 168
            if ($resultToken->isInvalid()) {
69 4
                return $resultToken;
70
            }
71
72 167
            $resultFWS = $this->parseLocalFWS();
73 167
            if($resultFWS->isInvalid()) {
74 7
                return $resultFWS;
75
            }
76
77 166
            $this->lexer->moveNext();
78
        }
79
80 148
        $this->lexer->stopRecording();
81 148
        $this->localPart = rtrim($this->lexer->getAccumulatedValues(), '@');
82 148
        if (strlen($this->localPart) > LocalTooLong::LOCAL_PART_LENGTH) {
83 2
            $this->warnings[LocalTooLong::CODE] = new LocalTooLong();
84
        }
85
86 148
        return new ValidEmail();
87
    }
88
89 168
    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

89
    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...
90
    {
91
        $invalidTokens = array(
92 168
            EmailLexer::S_COMMA => EmailLexer::S_COMMA,
93
            EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
94
            EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,
95
            EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN,
96
            EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN,
97
            EmailLexer::S_COLON => EmailLexer::S_COLON,
98
            EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON,
99
            EmailLexer::INVALID => EmailLexer::INVALID
100
        );
101 168
        if (isset($invalidTokens[$this->lexer->token['type']])) {
102 4
            return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']);
103
        }
104 167
        return new ValidEmail();
105
    }
106
107 186
    public function localPart() : string
108
    {
109 186
        return $this->localPart;
110
    }
111
112 167
    private function parseLocalFWS() : Result 
113
    {
114 167
        $foldingWS = new FoldingWhiteSpace($this->lexer);
115 167
        $resultFWS = $foldingWS->parse();
116 167
        if ($resultFWS->isValid()) {
117 166
            $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings());
118
        }
119 167
        return $resultFWS;
120
    }
121
122 186
    private function hasDotAtStart() : bool
123
    {
124 186
            return $this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type'];
125
    }
126
127 23
    private function parseDoubleQuote() : Result
128
    {
129 23
        $dquoteParser = new DoubleQuote($this->lexer);
130 23
        $parseAgain = $dquoteParser->parse();
131 23
        $this->warnings = array_merge($this->warnings, $dquoteParser->getWarnings());
132
133 23
        return $parseAgain;
134
    }
135
136 8
    protected function parseComments(): Result
137
    {
138 8
        $commentParser = new Comment($this->lexer, new LocalComment());
139 8
        $result = $commentParser->parse();
140 8
        $this->warnings = array_merge($this->warnings, $commentParser->getWarnings());
141 8
        if($result->isInvalid()) {
142 5
            return $result;
143
        }
144 3
        return $result;
145
    }
146
147 173
    private function validateEscaping() : Result
148
    {
149
        //Backslash found
150 173
        if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
151 168
            return new ValidEmail();
152
        }
153
154 7
        if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
155 6
            return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->token['value']);
156
        }
157
158 1
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
159
            return new ValidEmail();
160
        }
161
162 1
        return new ValidEmail();
163
    }
164
}