Completed
Push — 3.0.0-dev ( 34d49c...6abede )
by Eduardo Gulias
02:52 queued 01:22
created

Parser   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 197
Duplicated Lines 19.29 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

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