Test Setup Failed
Push — parse-domain-literal ( 97f1d2 )
by Eduardo Gulias
01:49
created

Parser   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 197
Duplicated Lines 19.29 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 14
dl 38
loc 197
rs 9.28
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getWarnings() 0 4 1
parse() 0 1 ?
A getOpenedParenthesis() 0 4 1
A validateQuotedPair() 0 10 3
A parseComments() 0 22 5
A isUnclosedComment() 0 9 2
A parseFWS() 9 9 2
A checkConsecutiveDots() 3 6 3
A isFWS() 12 12 6
A escaped() 8 8 3
A warnEscaping() 3 20 4
A validateEscaping() 3 21 4
A checkCRLFInFWS() 0 14 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Egulias\EmailValidator\Parser;
4
5
use Egulias\EmailValidator\EmailLexer;
6
use Egulias\EmailValidator\Exception\ConsecutiveDot;
7
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
8
use Egulias\EmailValidator\Exception\CRLFX2;
9
use Egulias\EmailValidator\Exception\ExpectingQPair;
10
use Egulias\EmailValidator\Exception\ExpectingATEXT;
11
use Egulias\EmailValidator\Exception\UnclosedComment;
12
use Egulias\EmailValidator\Result\InvalidEmail;
13
use Egulias\EmailValidator\Result\Reason\ExpectingATEXT as ReasonExpectingATEXT;
14
use Egulias\EmailValidator\Result\Result;
15
use Egulias\EmailValidator\Result\ValidEmail;
16
use Egulias\EmailValidator\Warning\CFWSNearAt;
17
use Egulias\EmailValidator\Warning\Comment;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Egulias\EmailValidator\Parser\Comment.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
18
use Egulias\EmailValidator\Warning\QuotedPart;
19
20
abstract class Parser
21
{
22
    /**
23
     * @var \Egulias\EmailValidator\Warning\Warning[]
24
     */
25
    protected $warnings = [];
26
27
    /**
28
     * @var EmailLexer
29
     */
30
    protected $lexer;
31
32
    /**
33
     * @var int
34
     */
35
    protected $openedParenthesis = 0;
36
37
    public function __construct(EmailLexer $lexer)
38
    {
39
        $this->lexer = $lexer;
40
    }
41
42
    /**
43
     * @return \Egulias\EmailValidator\Warning\Warning[]
44
     */
45
    public function getWarnings()
46
    {
47
        return $this->warnings;
48
    }
49
50
    /**
51
     * @param string $str
52
     */
53
    abstract public function parse($str);
54
55
    /** @return int */
56
    public function getOpenedParenthesis()
57
    {
58
        return $this->openedParenthesis;
59
    }
60
61
    /**
62
     * validateQuotedPair
63
     */
64
    protected function validateQuotedPair()
65
    {
66
        if (!($this->lexer->token['type'] === EmailLexer::INVALID
67
            || $this->lexer->token['type'] === EmailLexer::C_DEL)) {
68
            throw new ExpectingQPair();
69
        }
70
71
        $this->warnings[QuotedPart::CODE] =
72
            new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
73
    }
74
75
    protected function parseComments()
76
    {
77
        $this->openedParenthesis = 1;
78
        $this->isUnclosedComment();
79
        $this->warnings[Comment::CODE] = new Comment();
80
        while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) {
81
            if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) {
82
                $this->openedParenthesis++;
83
            }
84
            $this->warnEscaping();
85
            $this->lexer->moveNext();
86
        }
87
88
        $this->lexer->moveNext();
89
        if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) {
90
            throw new ExpectingATEXT();
91
        }
92
93
        if ($this->lexer->isNextToken(EmailLexer::S_AT)) {
94
            $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
95
        }
96
    }
97
98
    /**
99
     * @return bool
100
     */
101
    protected function isUnclosedComment()
102
    {
103
        try {
104
            $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS);
105
            return true;
106
        } catch (\RuntimeException $e) {
107
            throw new UnclosedComment();
108
        }
109
    }
110
111 View Code Duplication
    protected function parseFWS()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
112
    {
113
        $foldingWS = new FoldingWhiteSpace($this->lexer);
114
        $resultFWS = $foldingWS->parse('remove');
115
        if ($resultFWS->isValid()) {
116
            $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings());
117
        }
118
        return $resultFWS;
119
    }
120
121
    protected function checkConsecutiveDots()
122
    {
123 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...
124
            throw new ConsecutiveDot();
125
        }
126
    }
127
128
    /**
129
     * @return bool
130
     */
131 View Code Duplication
    protected function isFWS()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
132
    {
133
        if ($this->escaped()) {
134
            return false;
135
        }
136
137
        return $this->lexer->token['type'] === EmailLexer::S_SP ||
138
            $this->lexer->token['type'] === EmailLexer::S_HTAB ||
139
            $this->lexer->token['type'] === EmailLexer::S_CR ||
140
            $this->lexer->token['type'] === EmailLexer::S_LF ||
141
            $this->lexer->token['type'] === EmailLexer::CRLF;
142
    }
143
144
    /**
145
     * @return bool
146
     */
147 View Code Duplication
    protected function escaped()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
148
    {
149
        $previous = $this->lexer->getPrevious();
150
151
        return $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...
152
            &&
153
            $this->lexer->token['type'] !== EmailLexer::GENERIC;
154
    }
155
156
    /**
157
     * @return bool
158
     */
159
    protected function warnEscaping() : bool
160
    {
161
        //Backslash found
162
        if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
163
            return false;
164
        }
165
166
        if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
167
            throw new ExpectingATEXT();
168
        }
169
170 View Code Duplication
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
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...
171
            return false;
172
        }
173
174
        $this->warnings[QuotedPart::CODE] =
175
            new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
176
        return true;
177
178
    }
179
180
    protected function validateEscaping() : Result
181
    {
182
        //Backslash found
183
        if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
184
            return new ValidEmail();
185
        }
186
187
        if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
188
            return new InvalidEmail(new ReasonExpectingATEXT('Found ATOM after escaping'), $this->lexer->token['value']);
189
        }
190
191 View Code Duplication
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
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...
192
            return new ValidEmail();
193
        }
194
195
        $this->warnings[QuotedPart::CODE] =
196
            new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
197
198
        return new ValidEmail();
199
200
    }
201
202
    protected function checkCRLFInFWS()
203
    {
204
        if ($this->lexer->token['type'] !== EmailLexer::CRLF) {
205
            return;
206
        }
207
208
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
209
            throw new CRLFX2();
210
        }
211
212
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
213
            throw new CRLFAtTheEnd();
214
        }
215
    }
216
}
217