Test Failed
Pull Request — master (#267)
by
unknown
02:14
created

Parser::validateQuotedPair()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10

Duplication

Lines 4
Ratio 40 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 4
loc 10
ccs 0
cts 7
cp 0
rs 9.9332
c 0
b 0
f 0
cc 3
nc 2
nop 0
crap 12
1
<?php
2
3
namespace Egulias\EmailValidator\Parser;
4
5
use Egulias\EmailValidator\EmailLexer;
6
use Egulias\EmailValidator\Exception\AtextAfterCFWS;
7
use Egulias\EmailValidator\Exception\ConsecutiveDot;
8
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
9
use Egulias\EmailValidator\Exception\CRLFX2;
10
use Egulias\EmailValidator\Exception\CRNoLF;
11
use Egulias\EmailValidator\Exception\ExpectingQPair;
12
use Egulias\EmailValidator\Exception\ExpectingATEXT;
13
use Egulias\EmailValidator\Exception\ExpectingCTEXT;
14
use Egulias\EmailValidator\Exception\UnclosedComment;
15
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
16
use Egulias\EmailValidator\Warning\CFWSNearAt;
17
use Egulias\EmailValidator\Warning\CFWSWithFWS;
18
use Egulias\EmailValidator\Warning\Comment;
19
use Egulias\EmailValidator\Warning\QuotedPart;
20
use Egulias\EmailValidator\Warning\QuotedString;
21
22
abstract class Parser
23
{
24
    /**
25
     * @var array
26
     */
27
    protected $warnings = [];
28
29
    /**
30
     * @var EmailLexer
31
     */
32
    protected $lexer;
33
34
    /**
35
     * @var int
36
     */
37
    protected $openedParenthesis = 0;
38
39 132
    public function __construct(EmailLexer $lexer)
40
    {
41 132
        $this->lexer = $lexer;
42 132
    }
43
44
    /**
45
     * @return \Egulias\EmailValidator\Warning\Warning[]
46
     */
47 51
    public function getWarnings()
48
    {
49 51
        return $this->warnings;
50
    }
51
52
    /**
53
     * @param string $str
54
     */
55
    abstract public function parse($str);
56
57
    /** @return int */
58 6
    public function getOpenedParenthesis()
59
    {
60 6
        return $this->openedParenthesis;
61
    }
62
63
    /**
64
     * validateQuotedPair
65
     */
66
    protected function validateQuotedPair()
67
    {
68 View Code Duplication
        if (!($this->lexer->token['type'] === EmailLexer::INVALID
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
            || $this->lexer->token['type'] === EmailLexer::C_DEL)) {
70
            throw new ExpectingQPair();
71
        }
72
73
        $this->warnings[QuotedPart::CODE] =
74
            new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
75
    }
76
77 10
    protected function parseComments()
78
    {
79 10
        $this->openedParenthesis = 1;
80 10
        $this->isUnclosedComment();
81 6
        $this->warnings[Comment::CODE] = new Comment();
82 6
        while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) {
83 6
            if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) {
84 1
                $this->openedParenthesis++;
85 1
            }
86 6
            $this->warnEscaping();
87 6
            $this->lexer->moveNext();
88 6
        }
89
90 6
        $this->lexer->moveNext();
91 6
        if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) {
92
            throw new ExpectingATEXT();
93
        }
94
95 6
        if ($this->lexer->isNextToken(EmailLexer::S_AT)) {
96 1
            $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
97 1
        }
98 6
    }
99
100
    /**
101
     * @return bool
102
     */
103 13
    protected function isUnclosedComment()
104
    {
105
        try {
106 13
            $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS);
107 7
            return true;
108 6
        } catch (\RuntimeException $e) {
109 6
            throw new UnclosedComment();
110
        }
111
    }
112
113 6
    protected function parseFWS()
114
    {
115 6
        $previous = $this->lexer->getPrevious();
116
117 6
        $this->checkCRLFInFWS();
118
119 6
        if ($this->lexer->token['type'] === EmailLexer::S_CR) {
120 2
            throw new CRNoLF();
121
        }
122
123 4 View Code Duplication
        if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type']  !== EmailLexer::S_AT) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124 2
            throw new AtextAfterCFWS();
125
        }
126
127 2 View Code Duplication
        if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
            throw new ExpectingCTEXT();
129
        }
130
131 2
        if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type']  === EmailLexer::S_AT) {
132 2
            $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
133 2
        } else {
134
            $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
135
        }
136 2
    }
137
138 117
    protected function checkConsecutiveDots()
139
    {
140 117 View Code Duplication
        if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141 3
            throw new ConsecutiveDot();
142
        }
143 117
    }
144
145
    /**
146
     * @return bool
147
     */
148 111
    protected function isFWS()
149
    {
150 111
        if ($this->escaped()) {
151
            return false;
152
        }
153
154 111
        if ($this->lexer->token['type'] === EmailLexer::S_SP ||
155 111
            $this->lexer->token['type'] === EmailLexer::S_HTAB ||
156 111
            $this->lexer->token['type'] === EmailLexer::S_CR ||
157 111
            $this->lexer->token['type'] === EmailLexer::S_LF ||
158 111
            $this->lexer->token['type'] === EmailLexer::CRLF
159 111
        ) {
160 6
            return true;
161
        }
162
163 111
        return false;
164
    }
165
166
    /**
167
     * @return bool
168
     */
169 118
    protected function escaped()
170
    {
171 118
        $previous = $this->lexer->getPrevious();
172
173 118
        if ($previous && $previous['type'] === EmailLexer::S_BACKSLASH
0 ignored issues
show
Bug Best Practice introduced by
The expression $previous of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
174 118
            &&
175 2
            $this->lexer->token['type'] !== EmailLexer::GENERIC
176 118
        ) {
177 1
            return true;
178
        }
179
180 118
        return false;
181
    }
182
183
    /**
184
     * @return bool
185
     */
186 117
    protected function warnEscaping()
187
    {
188 117
        if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
189 112
            return false;
190
        }
191
192 7
        if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
193 6
            throw new ExpectingATEXT();
194
        }
195
196 1
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
197
            return false;
198
        }
199
200 1
        $this->warnings[QuotedPart::CODE] =
201 1
            new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
202 1
        return true;
203
204
    }
205
206
    /**
207
     * @param bool $hasClosingQuote
208
     *
209
     * @return bool
210
     */
211 129
    protected function checkDQUOTE($hasClosingQuote)
212
    {
213 129
        if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) {
214 108
            return $hasClosingQuote;
215
        }
216 22
        if ($hasClosingQuote) {
217
            return $hasClosingQuote;
218
        }
219 22
        $previous = $this->lexer->getPrevious();
220 22 View Code Duplication
        if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221 1
            throw new ExpectingATEXT();
222
        }
223
224
        try {
225 21
            $this->lexer->find(EmailLexer::S_DQUOTE);
226 20
            $hasClosingQuote = true;
227 21
        } catch (\Exception $e) {
228 1
            throw new UnclosedQuotedString();
229
        }
230 20
        $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']);
231
232 20
        return $hasClosingQuote;
233
    }
234
235 6
    protected function checkCRLFInFWS()
236
    {
237 6
        if ($this->lexer->token['type'] !== EmailLexer::CRLF) {
238 6
            return;
239
        }
240
241
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
242
            throw new CRLFX2();
243
        }
244
245
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
246
            throw new CRLFAtTheEnd();
247
        }
248
    }
249
}
250