Completed
Push — master ( 57eb77...af9a70 )
by Sam
04:28 queued 02:46
created

RdataHandlers::catchAll()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
1
<?php
2
3
namespace Badcow\DNS\Parser;
4
5
use Badcow\DNS\Rdata;
6
7
class RdataHandlers
8
{
9
    private static $handlers = [
10
        Rdata\LOC::TYPE => __CLASS__.'::handleLocRdata',
11
        Rdata\TXT::TYPE => __CLASS__.'::handleTxtRdata',
12
        Rdata\APL::TYPE => __CLASS__.'::handleAplRdata',
13
    ];
14
15 7
    public static function getHandlers(): array
16
    {
17 7
        return static::$handlers;
0 ignored issues
show
Bug introduced by
Since $handlers is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $handlers to at least protected.
Loading history...
18
    }
19
20
    /**
21
     * Transform a DMS string to a decimal representation. Used for LOC records.
22
     *
23
     * @param int    $deg        Degrees
24
     * @param int    $min        Minutes
25
     * @param float  $sec        Seconds
26
     * @param string $hemisphere Either 'N', 'S', 'E', or 'W'
27
     *
28
     * @return float
29
     */
30 1
    public static function dmsToDecimal(int $deg, int $min, float $sec, string $hemisphere): float
31
    {
32 1
        $multiplier = ('S' === $hemisphere || 'W' === $hemisphere) ? -1 : 1;
33
34 1
        return $multiplier * ($deg + ($min / 60) + ($sec / 3600));
35
    }
36
37
    /**
38
     * @param \ArrayIterator $iterator
39
     *
40
     * @return Rdata\LOC
41
     */
42 1
    public static function handleLocRdata(\ArrayIterator $iterator): Rdata\LOC
43
    {
44 1
        $lat = self::dmsToDecimal((int) self::pop($iterator), (int) self::pop($iterator), (float) self::pop($iterator), self::pop($iterator));
45 1
        $lon = self::dmsToDecimal((int) self::pop($iterator), (int) self::pop($iterator), (float) self::pop($iterator), self::pop($iterator));
46
47 1
        return Rdata\Factory::Loc(
48 1
            $lat,
49 1
            $lon,
50 1
            (float) self::pop($iterator),
51 1
            (float) self::pop($iterator),
52 1
            (float) self::pop($iterator),
53 1
            (float) self::pop($iterator)
54
        );
55
    }
56
57
    /**
58
     * @param \ArrayIterator $iterator
59
     *
60
     * @return Rdata\APL
61
     *
62
     * @throws ParseException
63
     */
64 4
    public static function handleAplRdata(\ArrayIterator $iterator): Rdata\APL
65
    {
66 4
        $rdata = new Rdata\APL();
67
68 4
        while ($iterator->valid()) {
69 4
            $matches = [];
70 4
            if (1 !== preg_match('/^(?<negate>!)?[1-2]:(?<block>.+)$/i', $iterator->current(), $matches)) {
71 2
                throw new ParseException(sprintf('"%s" is not a valid IP range.', $iterator->current()));
72
            }
73
74 2
            $ipBlock = \IPBlock::create($matches['block']);
75 2
            $rdata->addAddressRange($ipBlock, '!' !== $matches['negate']);
76 2
            $iterator->next();
77
        }
78
79 2
        return $rdata;
80
    }
81
82
    /**
83
     * @param \ArrayIterator $iterator
84
     *
85
     * @return Rdata\TXT
86
     */
87 3
    public static function handleTxtRdata(\ArrayIterator $iterator): Rdata\TXT
88
    {
89 3
        $string = new StringIterator(implode(Tokens::SPACE, self::getAllRemaining($iterator)));
90 3
        $txt = new StringIterator();
91
92 3
        while ($string->valid()) {
93 3
            self::handleTxt($string, $txt);
94 3
            $string->next();
95
        }
96
97 3
        return Rdata\Factory::txt((string) $txt);
98
    }
99
100 5
    public static function catchAll(string $type, \ArrayIterator $iterator): Rdata\RdataInterface
101
    {
102 5
        if (!Rdata\Factory::isTypeImplemented($type)) {
103 1
            return new PolymorphicRdata($type, implode(Tokens::SPACE, self::getAllRemaining($iterator)));
104
        }
105
106 4
        return call_user_func_array([Rdata\Factory::class, $type], self::getAllRemaining($iterator));
107
    }
108
109
    /**
110
     * @param StringIterator $string
111
     * @param StringIterator $txt
112
     */
113 3
    private static function handleTxt(StringIterator $string, StringIterator $txt): void
114
    {
115 3
        if ($string->isNot(Tokens::DOUBLE_QUOTES)) {
116 1
            return;
117
        }
118
119 3
        $string->next();
120
121 3
        while ($string->isNot(Tokens::DOUBLE_QUOTES) && $string->valid()) {
122 3
            if ($string->is(Tokens::BACKSLASH)) {
123 3
                $string->next();
124
            }
125
126 3
            $txt->append($string->current());
127 3
            $string->next();
128
        }
129 3
    }
130
131
    /**
132
     * Return current entry and moves the iterator to the next entry.
133
     *
134
     * @param \ArrayIterator $iterator
135
     *
136
     * @return string
137
     */
138 1
    private static function pop(\ArrayIterator $iterator): string
139
    {
140 1
        $current = $iterator->current();
141 1
        $iterator->next();
142
143 1
        return $current;
144
    }
145
146
    /**
147
     * Get all the remaining values of an iterator as an array.
148
     *
149
     * @param \ArrayIterator $iterator
150
     *
151
     * @return array
152
     */
153 5
    private static function getAllRemaining(\ArrayIterator $iterator): array
154
    {
155 5
        $values = [];
156 5
        while ($iterator->valid()) {
157 5
            $values[] = $iterator->current();
158 5
            $iterator->next();
159
        }
160
161 5
        return $values;
162
    }
163
}
164