Completed
Push — master ( 334de5...021784 )
by Michele
13s queued 10s
created

Pattern   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 260
Duplicated Lines 1.54 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 95.92%

Importance

Changes 0
Metric Value
dl 4
loc 260
c 0
b 0
f 0
wmc 36
lcom 1
cbo 5
ccs 94
cts 98
cp 0.9592
rs 9.52

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A __toString() 0 4 1
C fromString() 0 46 13
B toString() 0 35 6
A getAddressType() 0 4 1
A getStartAddress() 0 4 1
A getEndAddress() 0 4 1
A getComparableStartString() 0 4 1
A getComparableEndString() 0 4 1
A asSubnet() 4 9 3
A asPattern() 0 4 1
A getSubnetMask() 0 19 4
A getReverseDNSLookupName() 0 4 2

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 IPLib\Range;
4
5
use IPLib\Address\AddressInterface;
6
use IPLib\Address\IPv4;
7
use IPLib\Address\IPv6;
8
use IPLib\Address\Type as AddressType;
9
10
/**
11
 * Represents an address range in pattern format (only ending asterisks are supported).
12
 *
13
 * @example 127.0.*.*
14
 * @example ::/8
15
 */
16
class Pattern extends AbstractRange
17
{
18
    /**
19
     * Starting address of the range.
20
     *
21
     * @var \IPLib\Address\AddressInterface
22
     */
23
    protected $fromAddress;
24
25
    /**
26
     * Final address of the range.
27
     *
28
     * @var \IPLib\Address\AddressInterface
29
     */
30
    protected $toAddress;
31
32
    /**
33
     * Number of ending asterisks.
34
     *
35
     * @var int
36
     */
37
    protected $asterisksCount;
38
39
    /**
40
     * The type of the range of this IP range.
41
     *
42
     * @var int|false|null false if this range crosses multiple range types, null if yet to be determined
43
     */
44
    protected $rangeType;
45
46
    /**
47
     * Initializes the instance.
48
     *
49
     * @param \IPLib\Address\AddressInterface $fromAddress
50
     * @param \IPLib\Address\AddressInterface $toAddress
51
     * @param int $asterisksCount
52
     */
53 137
    public function __construct(AddressInterface $fromAddress, AddressInterface $toAddress, $asterisksCount)
54
    {
55 137
        $this->fromAddress = $fromAddress;
56 137
        $this->toAddress = $toAddress;
57 137
        $this->asterisksCount = $asterisksCount;
58 137
    }
59
60
    /**
61
     * {@inheritdoc}
62
     *
63
     * @see \IPLib\Range\RangeInterface::__toString()
64
     */
65 66
    public function __toString()
66
    {
67 66
        return $this->toString();
68
    }
69
70
    /**
71
     * Try get the range instance starting from its string representation.
72
     *
73
     * @param string|mixed $range
74
     * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
75
     *
76
     * @return static|null
77
     */
78 129
    public static function fromString($range, $supportNonDecimalIPv4 = false)
79
    {
80 129
        if (!is_string($range) || strpos($range, '*') === false) {
81 45
            return null;
82
        }
83 86
        if ($range === '*.*.*.*') {
84 4
            return new static(IPv4::fromString('0.0.0.0'), IPv4::fromString('255.255.255.255'), 4);
85
        }
86 82
        if ($range === '*:*:*:*:*:*:*:*') {
87 2
            return new static(IPv6::fromString('::'), IPv6::fromString('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), 8);
88
        }
89 80
        $matches = null;
90 80
        if (strpos($range, '.') !== false && preg_match('/^[^*]+((?:\.\*)+)$/', $range, $matches)) {
91 48
            $asterisksCount = strlen($matches[1]) >> 1;
92 48
            if ($asterisksCount > 0) {
93 48
                $missingDots = 3 - substr_count($range, '.');
94 48
                if ($missingDots > 0) {
95 2
                    $range .= str_repeat('.*', $missingDots);
96 2
                    $asterisksCount += $missingDots;
97
                }
98
            }
99 48
            $fromAddress = IPv4::fromString(str_replace('*', '0', $range), true, $supportNonDecimalIPv4);
100 48
            if ($fromAddress === null) {
101 1
                return null;
102
            }
103 47
            $fixedBytes = array_slice($fromAddress->getBytes(), 0, -$asterisksCount);
104 47
            $otherBytes = array_fill(0, $asterisksCount, 255);
105 47
            $toAddress = IPv4::fromBytes(array_merge($fixedBytes, $otherBytes));
106
107 47
            return new static($fromAddress, $toAddress, $asterisksCount);
108
        }
109 32
        if (strpos($range, ':') !== false && preg_match('/^[^*]+((?::\*)+)$/', $range, $matches)) {
110 28
            $asterisksCount = strlen($matches[1]) >> 1;
111 28
            $fromAddress = IPv6::fromString(str_replace('*', '0', $range));
112 28
            if ($fromAddress === null) {
113
                return null;
114
            }
115 28
            $fixedWords = array_slice($fromAddress->getWords(), 0, -$asterisksCount);
116 28
            $otherWords = array_fill(0, $asterisksCount, 0xffff);
117 28
            $toAddress = IPv6::fromWords(array_merge($fixedWords, $otherWords));
118
119 28
            return new static($fromAddress, $toAddress, $asterisksCount);
120
        }
121
122 4
        return null;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     *
128
     * @see \IPLib\Range\RangeInterface::toString()
129
     */
130 112
    public function toString($long = false)
131
    {
132 112
        if ($this->asterisksCount === 0) {
133 56
            return $this->fromAddress->toString($long);
134
        }
135
        switch (true) {
136 68
            case $this->fromAddress instanceof \IPLib\Address\IPv4:
137 42
                $chunks = explode('.', $this->fromAddress->toString());
138 42
                $chunks = array_slice($chunks, 0, -$this->asterisksCount);
139 42
                $chunks = array_pad($chunks, 4, '*');
140 42
                $result = implode('.', $chunks);
141 42
                break;
142 26
            case $this->fromAddress instanceof \IPLib\Address\IPv6:
143 26
                if ($long) {
144 6
                    $chunks = explode(':', $this->fromAddress->toString(true));
145 6
                    $chunks = array_slice($chunks, 0, -$this->asterisksCount);
146 6
                    $chunks = array_pad($chunks, 8, '*');
147 6
                    $result = implode(':', $chunks);
148 26
                } elseif ($this->asterisksCount === 8) {
149 2
                    $result = '*:*:*:*:*:*:*:*';
150
                } else {
151 24
                    $bytes = $this->toAddress->getBytes();
152 24
                    $bytes = array_slice($bytes, 0, -$this->asterisksCount * 2);
153 24
                    $bytes = array_pad($bytes, 16, 1);
154 24
                    $address = IPv6::fromBytes($bytes);
155 24
                    $before = substr($address->toString(false), 0, -strlen(':101') * $this->asterisksCount);
156 24
                    $result = $before . str_repeat(':*', $this->asterisksCount);
157
                }
158 26
                break;
159
            default:
160
                throw new \Exception('@todo'); // @codeCoverageIgnore
161
        }
162
163 68
        return $result;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     *
169
     * @see \IPLib\Range\RangeInterface::getAddressType()
170
     */
171 66
    public function getAddressType()
172
    {
173 66
        return $this->fromAddress->getAddressType();
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     *
179
     * @see \IPLib\Range\RangeInterface::getStartAddress()
180
     */
181 30
    public function getStartAddress()
182
    {
183 30
        return $this->fromAddress;
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     *
189
     * @see \IPLib\Range\RangeInterface::getEndAddress()
190
     */
191 30
    public function getEndAddress()
192
    {
193 30
        return $this->toAddress;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     *
199
     * @see \IPLib\Range\RangeInterface::getComparableStartString()
200
     */
201 34
    public function getComparableStartString()
202
    {
203 34
        return $this->fromAddress->getComparableString();
204
    }
205
206
    /**
207
     * {@inheritdoc}
208
     *
209
     * @see \IPLib\Range\RangeInterface::getComparableEndString()
210
     */
211 34
    public function getComparableEndString()
212
    {
213 34
        return $this->toAddress->getComparableString();
214
    }
215
216
    /**
217
     * {@inheritdoc}
218
     *
219
     * @see \IPLib\Range\RangeInterface::asSubnet()
220
     */
221 26
    public function asSubnet()
222
    {
223 26
        switch ($this->getAddressType()) {
224 26 View Code Duplication
            case AddressType::T_IPv4:
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...
225 9
                return new Subnet($this->getStartAddress(), $this->getEndAddress(), 8 * (4 - $this->asterisksCount));
226 17 View Code Duplication
            case AddressType::T_IPv6:
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...
227 17
                return new Subnet($this->getStartAddress(), $this->getEndAddress(), 16 * (8 - $this->asterisksCount));
228
        }
229
    }
230
231
    /**
232
     * {@inheritdoc}
233
     *
234
     * @see \IPLib\Range\RangeInterface::asPattern()
235
     */
236 14
    public function asPattern()
237
    {
238 14
        return $this;
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     *
244
     * @see \IPLib\Range\RangeInterface::getSubnetMask()
245
     */
246 5
    public function getSubnetMask()
247
    {
248 5
        if ($this->getAddressType() !== AddressType::T_IPv4) {
249 1
            return null;
250
        }
251 4
        switch ($this->asterisksCount) {
252 4
            case 0:
253
                $bytes = array(255, 255, 255, 255);
254
                break;
255 4
            case 4:
256 1
                $bytes = array(0, 0, 0, 0);
257 1
                break;
258
            default:
259 3
                $bytes = array_pad(array_fill(0, 4 - $this->asterisksCount, 255), 4, 0);
260 3
                break;
261
        }
262
263 4
        return IPv4::fromBytes($bytes);
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     *
269
     * @see \IPLib\Range\RangeInterface::getReverseDNSLookupName()
270
     */
271 12
    public function getReverseDNSLookupName()
272
    {
273 12
        return $this->asterisksCount === 0 ? array($this->getStartAddress()->getReverseDNSLookupName()) : $this->asSubnet()->getReverseDNSLookupName();
274
    }
275
}
276