Completed
Push — master ( c05c3f...d57fc8 )
by Sam
02:42
created

ResourceRecord::fromWire()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 2
dl 0
loc 19
ccs 13
cts 13
cp 1
crap 1
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Badcow DNS Library.
7
 *
8
 * (c) Samuel Williams <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Badcow\DNS;
15
16
use Badcow\DNS\Rdata\Factory;
17
use Badcow\DNS\Rdata\RdataInterface;
18
use Badcow\DNS\Rdata\RdataTrait;
19
use Badcow\DNS\Rdata\Types;
20
use InvalidArgumentException;
21
22
class ResourceRecord
23
{
24
    /**
25
     * @var int|null
26
     */
27
    private $classId = 1;
28
29
    /**
30
     * @var RdataInterface|null
31
     */
32
    private $rdata;
33
34
    /**
35
     * @var int|null
36
     */
37
    private $ttl;
38
39
    /**
40
     * @var string
41
     */
42
    private $name;
43
44
    /**
45
     * @var string|null
46
     */
47
    private $comment;
48
49
    /**
50
     * @param string         $name
51
     * @param RdataInterface $rdata
52
     * @param int            $ttl
53
     * @param string         $class
54
     * @param string         $comment
55
     *
56
     * @return ResourceRecord
57
     */
58 16
    public static function create(string $name, RdataInterface $rdata, int $ttl = null, string $class = Classes::INTERNET, string $comment = null): ResourceRecord
59
    {
60 16
        $rr = new self();
61 16
        $rr->setName($name);
62 16
        $rr->setRdata($rdata);
63 16
        $rr->setTtl($ttl);
64 16
        $rr->setClass($class);
65 16
        $rr->setComment($comment);
66
67 16
        return $rr;
68
    }
69
70
    /**
71
     * Set the class for the resource record
72
     * Usually one of IN, HS, or CH.
73
     *
74
     * @param string $class
75
     *
76
     * @throws InvalidArgumentException
77
     */
78 40
    public function setClass(?string $class): void
79
    {
80 40
        if (null !== $class && !Classes::isValid($class)) {
81 1
            throw new InvalidArgumentException(sprintf('No such class as "%s"', $class));
82
        }
83
84 40
        if (null === $class) {
85 1
            $this->classId = null;
86
87 1
            return;
88
        }
89
90 40
        $this->classId = Classes::getClassId($class);
91 40
    }
92
93
    /**
94
     * Set the name for the resource record.
95
     * Eg. "subdomain.example.com.".
96
     *
97
     * @param string $name
98
     */
99 41
    public function setName(string $name): void
100
    {
101 41
        $this->name = $name;
102 41
    }
103
104
    /**
105
     * @param RdataInterface $rdata
106
     */
107 38
    public function setRdata(?RdataInterface $rdata): void
108
    {
109 38
        $this->rdata = $rdata;
110 38
    }
111
112
    /**
113
     * @return string
114
     */
115 32
    public function getClass(): ?string
116
    {
117 32
        if (null === $this->classId) {
118 1
            return null;
119
        }
120
121 31
        return Classes::getClassName($this->classId);
122
    }
123
124 1
    public function setClassId(int $classId): void
125
    {
126 1
        $this->classId = $classId;
127 1
    }
128
129
    /**
130
     * @return int|null
131
     */
132 2
    public function getClassId(): ?int
133
    {
134 2
        return $this->classId;
135
    }
136
137
    /**
138
     * Set the time to live.
139
     *
140
     * @param int $ttl
141
     */
142 41
    public function setTtl(?int $ttl): void
143
    {
144 41
        $this->ttl = $ttl;
145 41
    }
146
147
    /**
148
     * @return string
149
     */
150 31
    public function getName(): ?string
151
    {
152 31
        return $this->name;
153
    }
154
155
    /**
156
     * @return string
157
     */
158 26
    public function getType(): ?string
159
    {
160 26
        if (null === $this->rdata) {
161 2
            return null;
162
        }
163
164 25
        return $this->rdata->getType();
165
    }
166
167
    /**
168
     * @return RdataInterface
169
     */
170 26
    public function getRdata(): ?RdataInterface
171
    {
172 26
        return $this->rdata;
173
    }
174
175
    /**
176
     * @return int
177
     */
178 28
    public function getTtl(): ?int
179
    {
180 28
        return $this->ttl;
181
    }
182
183
    /**
184
     * Set a comment for the record.
185
     *
186
     * @param string $comment
187
     */
188 39
    public function setComment(?string $comment): void
189
    {
190 39
        $this->comment = $comment;
191 39
    }
192
193
    /**
194
     * Get the record's comment.
195
     *
196
     * @return string
197
     */
198 10
    public function getComment(): ?string
199
    {
200 10
        return $this->comment;
201
    }
202
203
    /**
204
     * @return string
205
     *
206
     * @throws UnsetValueException|InvalidArgumentException
207
     */
208 1
    public function toWire(): string
209
    {
210 1
        if (null === $this->name) {
211
            throw new UnsetValueException('ResourceRecord name has not been set.');
212
        }
213
214 1
        if (null === $this->rdata) {
215
            throw new UnsetValueException('ResourceRecord rdata has not been set.');
216
        }
217
218 1
        if (null === $this->classId) {
219
            throw new UnsetValueException('ResourceRecord class has not been set.');
220
        }
221
222 1
        if (null === $this->ttl) {
223
            throw new UnsetValueException('ResourceRecord TTL has not been set.');
224
        }
225
226 1
        if (!Validator::fullyQualifiedDomainName($this->name)) {
227
            throw new InvalidArgumentException(sprintf('"%s" is not a fully qualified domain name.', $this->name));
228
        }
229
230 1
        $rdata = $this->rdata->toWire();
231
232 1
        $encoded = RdataTrait::encodeName($this->name);
233 1
        $encoded .= pack('nnNn',
234 1
            $this->rdata->getTypeCode(),
235 1
            $this->classId,
236 1
            $this->ttl,
237 1
            strlen($rdata)
238
        );
239 1
        $encoded .= $rdata;
240
241 1
        return $encoded;
242
    }
243
244
    /**
245
     * @param string $encoded
246
     * @param int    $offset
247
     *
248
     * @return ResourceRecord
249
     *
250
     * @throws Rdata\UnsupportedTypeException
251
     */
252 1
    public static function fromWire(string $encoded, int &$offset = 0): ResourceRecord
253
    {
254 1
        $rr = new self();
255 1
        $rr->setName(RdataTrait::decodeName($encoded, $offset));
256 1
        $integers = unpack('ntype/nclass/Nttl/ndlength', $encoded, $offset);
257 1
        $offset += 10;
258 1
        $rr->setClassId($integers['class']);
259 1
        $rr->setTtl($integers['ttl']);
260 1
        $rdataLen = $integers['dlength'];
261
262
        /** @var callable $callable */
263 1
        $callable = Factory::getRdataClassName(Types::getName($integers['type'])).'::fromWire';
264
        /** @var RdataInterface $rdata */
265 1
        $rdata = call_user_func($callable, substr($encoded, $offset, $rdataLen));
266
267 1
        $offset += $rdataLen;
268 1
        $rr->setRdata($rdata);
269
270 1
        return $rr;
271
    }
272
}
273