Test Setup Failed
Pull Request — master (#20)
by
unknown
02:09
created

RData::defaultExtractor()   D

Complexity

Conditions 26
Paths 0

Size

Total Lines 75

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 52
CRAP Score 26.0045

Importance

Changes 0
Metric Value
dl 0
loc 75
ccs 52
cts 53
cp 0.9811
rs 4.1666
c 0
b 0
f 0
cc 26
nc 0
nop 1
crap 26.0045

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
 * @author: Viskov Sergey
4
 * @date  : 14.04.16
5
 * @time  : 4:50
6
 */
7
8
namespace LTDBeget\dns\record;
9
10
use LTDBeget\ascii\AsciiChar;
11
use LTDBeget\dns\SyntaxErrorException;
12
use LTDBeget\stringstream\StringStream;
13
14
/**
15
 * Class RData
16
 *
17
 * @package LTDBeget\dns\record
18
 */
19
class RData
20
{
21
    /**
22
     * @var array
23
     */
24
    private static $rdataFormats = [
25
        'SOA'   => [
26
            'MNAME'   => 'defaultExtractor',
27
            'RNAME'   => 'defaultExtractor',
28
            'SERIAL'  => 'defaultExtractor',
29
            'REFRESH' => 'defaultExtractor',
30
            'RETRY'   => 'defaultExtractor',
31
            'EXPIRE'  => 'defaultExtractor',
32
            'MINIMUM' => 'defaultExtractor',
33
        ],
34
        'A'     => [
35
            'ADDRESS' => 'defaultExtractor'
36
        ],
37
        'AAAA'  => [
38
            'ADDRESS' => 'defaultExtractor'
39
        ],
40
        'CNAME' => [
41
            'CNAME' => 'defaultExtractor'
42
        ],
43
        'MX'    => [
44
            'PREFERENCE' => 'defaultExtractor',
45
            'EXCHANGE'   => 'defaultExtractor'
46
        ],
47
        'NS'    => [
48
            'NSDNAME' => 'defaultExtractor'
49
        ],
50
        'PTR'   => [
51
            'PTRDNAME' => 'defaultExtractor'
52
        ],
53
        'SRV'   => [
54
            'PRIORITY' => 'defaultExtractor',
55
            'WEIGHT'   => 'defaultExtractor',
56
            'PORT'     => 'defaultExtractor',
57
            'TARGET'   => 'defaultExtractor'
58
        ],
59
        'TXT'   => [
60
            'TXTDATA' => 'txtExtractor'
61
        ],
62
        'CAA' => [
63
            'FLAGS' => 'defaultExtractor',
64
            'TAG'   => 'defaultExtractor',
65
            'VALUE' => 'defaultExtractor'
66
        ],
67
        'NAPTR' => [
68
            'ORDER'       => 'defaultExtractor',
69
            'PREFERENCE'  => 'defaultExtractor',
70
            'FLAGS'       => 'defaultExtractor',
71
            'SERVICES'    => 'defaultExtractor',
72
            'REGEXP'      => 'defaultExtractor',
73
            'REPLACEMENT' => 'defaultExtractor'
74
        ]
75
    ];
76
    /**
77
     * @var string
78
     */
79
    private $type;
80
    /**
81
     * @var array
82
     */
83
    private $tokens = [];
84
85
    /**
86
     * @var bool
87
     */
88 6
    private $commentOpen = false;
89
90 6
    /**
91
     * @var bool
92
     */
93
    private $multiLineOpened = false;
94 6
95 6
    /**
96 6
     * RData constructor.
97
     *
98
     * @param StringStream $stream
99
     * @param string       $type
100
     */
101
    public function __construct(StringStream $stream, string $type)
102 6
    {
103
        if (! self::isKnownType($type)) {
104 6
            throw new SyntaxErrorException($stream);
105
        }
106
107
        $this->stream = $stream;
0 ignored issues
show
Bug introduced by
The property stream does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
108
        $this->type   = $type;
109
    }
110 6
111
    /**
112 6
     * @param string $type
113 6
     * @return bool
114
     */
115
    public static function isKnownType(string $type) : bool
116 6
    {
117
        return array_key_exists($type, self::$rdataFormats);
118 6
    }
119
120
    /**
121
     * @return array
122
     */
123
    public function tokenize() : array
124 6
    {
125
        foreach (self::$rdataFormats[$this->type] as $tokenName => $extractor) {
126 6
            $this->$extractor($tokenName);
127 5
        }
128
        
129 6
        $this->endRecord();
130
131
        return $this->tokens;
132 6
    }
133
    
134 6
    /**
135 6
     * @param string $tokenName
136
     */
137
    protected function defaultExtractor(string $tokenName)
138
    {
139
        if($this->multiLineOpened) {
140 6
            $this->stream->ignoreWhitespace();
141
        } else {
142 6
            $this->stream->ignoreHorizontalSpace();
143 4
        }
144
        
145
        $this->commentOpen = false;
146 6
        
147 5
        if (!array_key_exists($tokenName, $this->tokens)) {
148 5
            $this->tokens[$tokenName] = '';
149 5
        }
150 6
        
151 1
        start:
152 1
153 1
        $ord = $this->stream->ord();
154 6
155 4
        if($ord === AsciiChar::NULL || $this->stream->isEnd()) {
156 4
            return;
157 6
        }
158 4
159
        if($ord === AsciiChar::OPEN_BRACKET && !$this->commentOpen) {
160 6
            $this->multiLineOpened = true;
161 4
            $this->stream->next();
162 4
            goto start;
163
        } elseif($this->multiLineOpened && !$this->commentOpen && $ord === AsciiChar::CLOSE_BRACKET) {
164 3
            $this->multiLineOpened = false;
165 3
            $this->stream->next();
166 3
            goto start;
167
        } elseif($this->multiLineOpened && !$this->commentOpen && $ord === AsciiChar::LINE_FEED) {
168 1
            $this->stream->next();
169 1
            goto start;
170 1
        } elseif($ord === AsciiChar::LINE_FEED && !$this->commentOpen) {
171
            return;
172 4
        } else {
173 6
            if($ord === AsciiChar::SEMICOLON) {
174 3
                $this->stream->previous();
175 3
                if($this->stream->currentAscii()->isHorizontalSpace()) {
176 3
177 3
                    $this->commentOpen = true;
178 6
                    $this->stream->next();
179 3
                    $this->stream->next();
180 3
                } else {
181 3
                    $this->stream->next();
182 6
                    $this->tokens[$tokenName] .= $this->stream->current();
183 6
                    $this->stream->next();
184 4
                }
185 4
                goto start;
186 6
            } elseif(($this->stream->currentAscii()->isVerticalSpace() || $ord === AsciiChar::NULL) && $this->commentOpen) {
187 5
                $this->stream->next();
188
                $this->stream->ignoreHorizontalSpace();
189 6
                $this->commentOpen = false;
190 6
                goto start;
191 6
            } elseif($this->commentOpen) {
192 4
                $this->commentOpen = true;
193
                $this->ignoreComment();
194 6
                goto start;
195
            } elseif(!$this->commentOpen) {
196
                if($ord === AsciiChar::SPACE && $this->tokens[$tokenName] === '') {
197
                    $this->stream->next();
198
                    goto start;
199
                } elseif($this->stream->currentAscii()->isWhiteSpace()) {
200 3
                    return;
201
                } else {
202
                    $this->tokens[$tokenName] .= $this->stream->current();
203 3
                    $this->stream->next();
204 3
                    if($this->stream->isEnd()) {
205 3
                        $this->tokens[$tokenName] = trim($this->tokens[$tokenName]);
206
                    }
207 3
                    goto start;
208
                }
209 6
            }
210
        }
211
    }
212 6
213 6 View Code Duplication
    private function ignoreComment()
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...
214 4
    {
215
        start:
216 5
        if (!$this->stream->currentAscii()->isVerticalSpace() && !$this->stream->isEnd()) {
217 2
            $this->stream->next();
218 2
            goto start;
219 2
        }
220 5
    }
221 2
    
222 2
    protected function endRecord()
223 2
    {
224
        start:
225 2
        $ord = $this->stream->ord();
226 2
        if($ord === AsciiChar::NULL) {
227 2
            return;
228
        }
229 5
        if($ord === AsciiChar::SEMICOLON) {
230 5
            $this->stream->next();
231 4
            $this->commentOpen = true;
232 4
            goto start;
233
        } elseif($this->commentOpen) {
234 4
            if($ord === AsciiChar::NULL() || $ord === AsciiChar::LINE_FEED) {
235 4
                $this->commentOpen = false;
236 5
                goto start;
237 5
            } else {
238
                $this->stream->next();
239
                $this->commentOpen = true;
240 3
                goto start;
241
            }
242
        } elseif(!$this->commentOpen)  {
243
            if($this->multiLineOpened) {
244
                if($ord === AsciiChar::CLOSE_BRACKET) {
245 1
                    $this->multiLineOpened = false;
246
                }
247 1
                $this->stream->next();
248 1
                goto start;
249
            } elseif($ord === AsciiChar::NULL() || $ord === AsciiChar::LINE_FEED) {
250
                return;
251
            }
252 1
        }
253 1
    }
254
255 1
    /**
256
     * @param string $tokenName
257
     */
258
    private function txtExtractor(string $tokenName)
259
    {
260 1
        if (!array_key_exists($tokenName, $this->tokens)) {
261 1
            $this->tokens[$tokenName] = '';
262 1
        }
263 1
264 1
        start:
265 1
        $ord = $this->stream->ord();
266 1
        $this->stream->next();
267 1
268 1
        if($ord === 0) { // if end of record
269 1
            return;
270
        }
271
272 1
        // comment starts
273 1
        if($ord === 59) {
274
            $this->commentOpen = true;
275
            goto start;
276
        } elseif($this->commentOpen === true && $ord !== 10) {
277 1
            $this->commentOpen = true;
278 1
            goto start;
279
        } elseif($this->commentOpen === true && ($ord === 10 || $ord === 0)) {
280
            $this->stream->previous();
281
            $this->commentOpen = false;
282 1
            goto start;
283 1
        } else {
284 1
            // ignore blanck line
285
            if($ord === 32) {
286
                goto start;
287
            }
288 1
289 1
            // Find starts of char set
290 1
            if($ord === 34 && !$this->commentOpen) { // "
291
                $this->extractCharSet($tokenName);
292
            }
293
294 1
            // multi line opened
295
            if($ord === 40 && !$this->commentOpen) {
296
                $this->multiLineOpened = true;
297
                goto start;
298
            }
299 1
300 1
            // multi line closed
301 1
            if($this->multiLineOpened && !$this->commentOpen && $ord === 41) {
302 1
                $this->multiLineOpened = false;
303
                goto start;
304
            }
305 1
306
            // comment end in multi line TXT record
307
            if($ord === 10 && $this->commentOpen && $this->multiLineOpened) {
308
                goto start;
309
            }
310 1
311
            // is record ends?
312 1
            if(!$this->multiLineOpened && ($ord === 10 || $ord === 0)) {
313
                return;
314 1
            } elseif($this->multiLineOpened && $ord === 10) {
315 1
                goto start;
316
            }
317 1
        }
318
    }
319
320
    /**
321 1
     * @param string $tokenName
322 1
     */
323
    private function extractCharSet(string $tokenName)
324 1
    {
325
        $escaping_open = false;
326
        start:
327
        $ord = $this->stream->ord();
328 1
        $this->stream->next();
329 1
330 1
        if($ord === AsciiChar::NULL) { // if end of record
331
            throw new SyntaxErrorException($this->stream);
332 1
        }
333
334
        if(!$escaping_open && $ord === 34) {
335
            $this->txtExtractor($tokenName);
336
        } else {
337
            if($ord === AsciiChar::LINE_FEED || $ord === AsciiChar::VERTICAL_TAB || $ord === AsciiChar::NULL) {
338
                $this->stream->previous();
339
                throw new SyntaxErrorException($this->stream);
340
            }
341
            $this->tokens[$tokenName] .= chr($ord);
342
            $escaping_open = ($ord === 92 && !$escaping_open);
343
            goto start;
344
        }
345
    }
346
}
347